Pitch: Fully-Qualified Lookups

I have no idea whether this syntax is likely to ever be implemented (@hborla?), but nonetheless I think you make a good argument for finding an alternative to the _. syntax.

I’m personally disinclined to choose another symbol character; $. has the same education and overloading problems as _..

I can almost see #module as an alternative to _.Self, but I would really expect #module to evaluate to a string in keeping with #file and #line.

In the interest of making forward progress, I’d like to implement some syntax even if it isn’t universally loved.

Maybe this?

Module.Swift.dump(thing)
Type.Swift.dump(thing)

The _. symbol sequence looks awkward to me.

I’ll throw out another placeholder syntax: import.Foundation. import is already a keyword and it’s never followed by a dot today. It’s not great for Self but *shrug*

2 Likes

Somewhere in the discussion referenced in the pitch, I proposed #. as the root of everything. This would produce:

#.Swift.dump(thing)
#.Self.isGreater(a, b)

I think it reads better than _.

2 Likes

Why avoid the one syntax that you've brought up twice in the text, which is already precedented in another commonly used language and has been explored for Swift?

6 Likes

Remind me why did we reject :: again? Seems like a good fit for me. Not used in Swift already, and would feel familiar to people coming from C++. Also, it allows us to use dot for sub-module resolution, and nested types, and gives a natural way to separate the two:

Module.SubModule::Type.Nested.member

We could still accept . for module resolution, but generate an ambiguity error with proposed fixits for each available resolution using ::. Maybe also produce a warning even for unambiguous cases like so

typealias Duration = Swift.Duration
// warning: dot is deprecated for module resolution
// fix-it: Swift::Duration 
3 Likes

Yet another choice:

Swift/Duration or Swift\Duration
/Duration or \Duration
1 Like

There's beauty in the consistent behaviour of the underscore in Swift, especially since it has its roots in the real world where _ can denote a missing value. _.Self.isGreater(a, b) seems cryptic and it ruins that beautiful association.

That being said, the problem it tries to solve is real. Perhaps introducing as for the import statement would solve it? as is already part of the lexis and the result is easy to understand/closer to the natural language.

import Swift as SwiftModule


struct Swift {}

func dump(_ thing: Any) -> Void {
    SwiftModule.dump(thing)
}
4 Likes

I thought along the same lines:

alias SwiftModule = Swift // modulealias? just typealias?
1 Like

That’s being worked on separately.

1 Like

Does that mean there's no problem to solve? Once/if module-aliasing is adopted this should be solved as well (?)

Import aliases don’t help with the second example in the pitch, where the shadowing is entirely internal to the module.

I’m warming up to :: as an alternative, even though it would give more ammo to those who deride Swift as a reinvention of C++.

I don’t think deprecating the existing syntax is necessary or preferable. Plenty of other languages use dots for lookup within modules/namespaces, and introducing a bunch of warnings in existing Swift projects seems like busywork.

Rather than :: representing a root namespace, I would probably stick more closely to C++’s spelling: Module::Symbol for fully-qualified lookup within a module, and ::Symbol for fully-qualified lookup starting at the current module’s top level.

6 Likes

I haven't had a look over the module aliases proposal, but in theory, they could if we had a modulealias, just like we have typealias now, scoped to a specific context. (instead of using as)

AKA DocC syntax. It would be nice to unify them if possible. It bugs me that I can write:

WebURL/WebURL/hostname

And DocC knows exactly what I mean. But then I try to write:

WebURL.WebURL.hostname

And the Swift compiler isn't able to tell the difference between "WebURL" the module and "WebURL" the type :man_facepalming:

As for ::, I've never been a massive fan of it. It looks too alien in Swift.

1 Like

I’m pretty sure using / would be a source-incompatible change.

2 Likes

This looks the best.

I’m leaning towards the following:

  1. (module Swift).dump
    This syntax is clear to somebody who’s not a Swift expert, but the parentheses are a bit awkward.

  2. import.Swift.dump
    Here, an existing keyword is reused; however, the keyword is in lowercase and may not allude to Swift being “nested” in import. In fact, folks may confuse this with existing import declarations.

  3. Modules.Swift, Imports.Swift
    These two are similar, in that they are both plural with their first letter capitalized. The reason plural works best is that it adds extra clarity, which counteracts the confusion caused by module names also being capitalized. For example, Icon.flower, would clearly refer to the flower icon. With something like EmptyCollection.Iterator, though, iterator is not an empty collection, but just nested (and in turn related) to EmptyCollection.

How about a mix of 1 and 2: (import Swift).dump?

1 Like

I think this suffers both from the parenthesis awkwardness and confusability with the existing import declaration.