         }
         // If we get this far, there is no suffix.
         return nil
+    }
+
+    func appending(component name: String) -> UNIXPath {
+        assert(!name.contains("/"), "\(name) is invalid path component")
+
+        // Handle pseudo paths.
+        switch name {
+        case "", ".":
+            return self
+        case "..":
+            return self.parentDirectory
+        default:
+            break
+        }
+
+        if self == Self.root {
+            return PathImpl(string: "/" + name)
+        } else {
+            return PathImpl(string: string + "/" + name)
+        }
+    }
+
+    func appending(relativePath: UNIXPath) -> UNIXPath {
+        // Both paths are already normalized.  The only case in which we have
+        // to renormalize their concatenation is if the relative path starts
+        // with a `..` path component.
+        var newPathString = string
+        if self != .root {
+            newPathString.append("/")
+        }
+
+        let relativePathString = relativePath.string
+        newPathString.append(relativePathString)
+
+        // If the relative string starts with `.` or `..`, we need to normalize
+        // the resulting string.
+        // FIXME: We can actually optimize that case, since we know that the
+        // normalization of a relative path can leave `..` path components at
+        // the beginning of the path only.
+        if relativePathString.hasPrefix(".") {
+            if newPathString.hasPrefix("/") {
+                return PathImpl(normalizingAbsolutePath: newPathString)
+            } else {
+                return PathImpl(normalizingRelativePath: newPathString)
+            }
+        } else {
+            return PathImpl(string: newPathString)
+        }
     }
 }
 

    /// The input string will be normalized if needed, as described in the
    /// documentation for AbsolutePath.
    public init(_ absStr: String) {
        // Normalize the absolute string.
        self.init(PathImpl(string: normalize(absolute: absStr)))
    }

    /// Initializes an AbsolutePath from a string that may be either absolute
    /// or relative; if relative, `basePath` is used as the anchor; if absolute,
    /// it is used as is, and in this case `basePath` is ignored.
    public init(_ str: String, relativeTo basePath: AbsolutePath) {
        if str.hasPrefix("/") {
            self.init(str)
        } else {
            self.init(basePath, RelativePath(str))

    }
}

/// Private implementation shared between AbsolutePath and RelativePath.
protocol Path: Hashable {

    /// Root directory.
    static var root: Self { get }

    /// Checks if a string is a valid component.
    static func isValidComponent(_ name: String) -> Bool

    /// Normalized string of the (absolute or relative) path. Never empty.
    var string: String { get }

    /// Returns whether the path is an absolute path.
    var isAbsolute: Bool { get }

    /// Returns the directory part of the stored path (relying on the fact that it has been normalized). Returns a
    /// string consisting of just `.` if there is no directory part (which is the case if and only if there is no path
    /// separator).
    var dirname: String { get }

    /// Returns the last past component.
    var basename: String { get }

    /// Returns the components of the path between each path separator.
    var components: [String] { get }

    /// Path of parent directory. This always returns a path, because every directory has a parent (the parent
    /// directory of the root directory is considered to be the root directory itself).
    var parentDirectory: Self { get }

    /// Creates a path from its normalized string representation.
    init(string: String)

    /// Creates a path from an absolute string representation and normalizes it.
    init(normalizingAbsolutePath: String)

    /// Creates a path from an relative string representation and normalizes it.
    init(normalizingRelativePath: String)

    /// Creates a path from a string representation, validates that it is a valid absolute path and normalizes it.
    init(validatingAbsolutePath: String) throws

    /// Creates a path from a string representation, validates that it is a valid relative path and normalizes it.
    init(validatingRelativePath: String) throws

    /// Returns suffix with leading `.` if withDot is true otherwise without it.
    func suffix(withDot: Bool) -> String?

    /// Returns a new Path by appending the path component.
    func appending(component: String) -> Self

    /// Returns a path by concatenating a relative path and renormalizing if necessary.
    func appending(relativePath: Self) -> Self
}

extension Path {
    var suffix: String? {
        return suffix(withDot: true)
    }

    var `extension`: String? {
        return suffix(withDot: false)
    }
}

private struct UNIXPath: Path {
    let string: String

    static let root = UNIXPath(string: "/")

    static func isValidComponent(_ name: String) -> Bool {
        return name != "" && name != "." && name != ".." && !name.contains("/")
    }

    var dirname: String {
#if os(Windows)
        let dir = string.deletingLastPathComponent
        return dir == "" ? "." : dir
