SE-0247 includes an additive change (#filePath literal to provide the full path to the file), but then introduces three changes that affect existing sources:
#file literals have a different form that does not include the full path name. Therefore, the spelling #file has changed meaning.
The compiler provides a warning when a wrapper around a #filePath -defaulting function passes it #file instead, or vice versa.
Standard library functions like precondition currently use #file, and therefore have had their behavior changed to no longer produce the full path name by default.
My concern is with #1 and #2. With #1, we have changed language semantics without a language version bump and without a deprecation cycle. With #2, we are seeing a bunch of warnings in user code about the migration. In both cases, if you want to fix your code to work with Swift 5.2 and Swift 5.3, you have to use #if's on language version in a bunch of places, which is an unfortunate workaround because it litters code with unnecessary divergence.
I consider #3 to be a necessary semantic change. As the proposal highlights, the standard library is effectively leaking private information about the build environment into binaries, and paying a significant percentage of the code size to do so.
Here is my proposal for fixing these issues with SE-0247:
Introduce #fileId to have the shortened spelling
Update all of the Standard Library's usage of #file to #fileId
Keep #file meaning the same thing as #filePath in Swift 5.3
Change the meaning of #file to be an alias of #fileId in Swift 6
Thoughts?
Doug
(Note: I advocated for SE-0247 as it was accepted, including the source breaks above, but I've been thinking about that decision more in light of the other discussions going on.)
I agree that we should havenโt to use โ#ifโs to support different language versions, which are not major. One thing I didnโt understand is whether you propose having both #filePath and #file or just #file. As far is the deprecation goes, I agree that the current behavior is actively harmful and I support changing it as soon as posting -in the next major version.
Thank you SO MUCH! I agree with everything you say, I'm fully on board with this pitch as well as the #fileId idea. If you asked me to choose a name, I'd probably go for #fileBasename or #fileID but I'd take anything to make this issue go away .
As you point out it breaks source compatibility more than necessary. Worst of all actually is that the biggest #file vs. #filePath problems happen in test assertions. The problem with those is that under normal circumstances, they don't actually print anything. So a potential #file to #filePath forwarding issue will potentially be hidden until the worst point in time: when your test assertion fails, printing the wrong #filePath (this literally happened to me today...).
Below a few bugs and pull requests we made until we discovered that neither the first, nor the second idea how to forward #file to #filePath warning free worked, which then meant we needed a third one which actually works .
My understanding is that we are still in the midst of discussing these principles as a community; I'm somewhat surprised to see that they're being adopted already and particularly in the context of revisiting existing proposals.
I do think that this is a reasonable migration path. For consistency, it'd probably best be spelled #fileID or #fileString, but besides bikeshedding I would agree with this revision.
Do we genuinely want to have #fileId (or #fileID?) in the language after #fileโs behavior changes? If not, we could tie #fileโs behavior to the language version mode and either add an underscored #_fileID and use it only in the standard library, or simply wait until Swift 6 lands for the standard libraryโs behavior to change (and have it change only for clients compiled in Swift 6 mode).
One advantage of full paths is itโs easier for editor clients to map run-time errors back to files. Changing the behavior of fatalError and precondition is definitely a sensible change (and maybe even assert), but something like XCTest benefits from using the full path.
I feel like what #fileID does is valuable and should be made available more generally. Now, we could say it only exists in Swift < 6, and deprecate it in favor of the new #file behavior in Swift 6, so the result is back down to 2 ideas, with the shorter one being the preferred one for most tasks.
These principles arenโt new to Swift; that they are being written down is new. As is the feedback weโre getting from folks trying out the 5.3 development snapshots.
GRDB + Xcode 12 beta is littered with warning: parameter 'file' with default argument '#file' passed to parameter 'file', whose default argument is '#filePath'.
In order to avoid code duplication, the workaround I'm currently using is:
The worse side effect of this workaround is that it erases default arguments. Consequence: it not only prevents the quoted warning, but also all future compiler warnings of the same kind.
Yeah that's one workaround. Unfortunately it requires the entire signature to be duplicated three times. This makes me wish we could do something like this in Swift:
#fileID will generate the concise file string in current Swift; the standard library assertions will adopt it, and other Swift 5 code can adopt it too.
#file's meaning will only change in "Swift 6 mode" (whatever that ends up being). At that time, we will deprecate #fileID.
The mismatched-default-argument warning will consider #file interchangeable with both #filePath and #fileID in Swift 5 mode; in "Swift 6 mode", it will complain about #filePath but not #fileID.
Thank you for highlighting these issues from the original proposal discussion once more, @Douglas_Gregor. It utterly escapes me why the proposal was approved in the form it's in. Please make the changes you have proposed to introduce #fileId.