Skip to content

URL.path(percentEncoded: false) is NOT Equivalent to URL.path property for File URLs #1011

Open
@swillits

Description

@swillits

Description

Xcode suggests that URL.path(percentEncoded: false) should be used to replace the will-be-deprecated URL.path, but for relative file URLs, this will lead to bugs in existing code. (Ask me how I know; It already did in mine.)

The documentation for .path notes: "This function resolves against the base URL." It also says: "New code should use .path(percentEncoded: false)"

The documentation for path(percentEncoded:) does not say anything about resolving against the base URL. Does it? Does it not? — It does not, which is the problem.

I raised this issue in the forums with no response: https://forums.swift.org/t/url-path-vs-path-percentencoded-for-file-urls/75358

Reproduction

The problem is something like this:

Bundle.main.url(forAuxiliaryExecutable: "tool")!.path

... which returns the expected file path (ex: "/Applications/MyApp.app/Contents/tool")

would be quickly rewritten as suggested to:

Bundle.main.url(forAuxiliaryExecutable: "tool")!.path(percentEncoded: false)

... which simply returns "tool", because the URL returned is relative to a base URL.

Widespread adoption of path(percentEncoded: false) in place of path on file URLs will lead to bugs if this undocumented difference is not known.

let a = URL(fileURLWithPath: "/System/Library")
let b = URL(string: "Library", relativeTo: URL(fileURLWithPath: "/System"))!

print(a) // file:///System/Library/
print(b) // Library -- file:///System/

// WARNING: 'path' will be deprecated in a future version of macOS: Use path(percentEncoded:) instead
print(a.path) //  /System/Library
print(b.path) //  /System/Library

print(a.path(percentEncoded: false)) //  /System/Library 
print(b.path(percentEncoded: false)) //  Library

print(a.standardizedFileURL.path(percentEncoded: false)) //  /System/Library 
print(b.standardizedFileURL.path(percentEncoded: false)) //  /System/Library

Expected behavior

Based on Xcode's deprecation warning, I expect .path(percentEncoded: false) to behave the same as .path currently does.

The fact is many users will just change .path into .path(percentEncoded: false) because that's what Xcode and the documentation tell them to do, and they will probably introduce bugs.

Environment

Apple Swift version 6.0 (swiftlang-6.0.0.9.10 clang-1600.0.26.2)
Target: arm64-apple-macosx15.0

Additional information

I believe the best solution would be the addition of a new URL property specifically for getting the file path from file URLs.

I've always found it not-completely-obvious to newcomers how to get a standard file path string from a file URL and this only makes it more confusing. (.path, .relativePath, .path(), .path(percentEncoded: false) ..... there are too many choices, and the behavior difference between them is not clear unless you really dig and familiarlize yourself with URLs.

For the sake of sanity where having to go from a URL to a file path string is still very common, I'd expect something along the lines of:

url.standardizedFilePath -> String

... which makes it very clear and obvious to anyone looking at URL and asking "how do I get the [full and complete, resolved, standardized] file path string from this URL?"

This is a common task, and yet it's not obvious. The alternative is that any time code needs to go from a URL to a file path, it needs to call url.standardizedFileURL.path(percentEncoded: false) to get the correct result, which is just not convenient or obvious.

Or, since the FilePath type now exists, I'd even accept:

url.standardizedFilePath -> FilePath

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions