Super short summary:

I think a function argument or right-hand-side expression prefixed with `.` 
should allow access to *any* static member on the expected type, dropping the 
existing limitations of this syntax.

Detail:

At the moment in Swift, you can use a `.` (period or dot) prefix to perform a 
scoped lookup of static vars and funcs on the expected type, if those static 
vars or funcs return that type.

For example:

        // If we have a type `SomeNontrivialTypeName`
        struct SomeNontrivialTypeName {
           // With a static function returning `SomeNontrivialTypeName`
           static func a() -> SomeNontrivialTypeName
        }
        
        // And a function that requires a `SomeNontrivialTypeName` parameter
        func f(a: SomeNontrivialTypeName)
        
        // We can call the function like this:
        f(a: .a())

The `.` prefix allows us to omit the typename `SomeNontrivialTypeName`; since 
the parameter already expects `SomeNontrivialTypeName`, the `.` already implies 
lookup in the list of static func/vars for `SomeNontrivialTypeName`.

The purpose is syntactic efficiency and it's used to great extent across a wide 
range of Swift/AppKit/Foundation interfaces for enum-like value lookups. It 
lets us have very simple names that won't clash with names in the global 
namespace because they're not in the global namespace – and yet, they're only a 
single `.` more syntactic overhead.

Unfortunately, there is no extendability. This approach will look up only 
static vars or funcs that immediately return the expected type and you can't 
transform the result – it's one function and done. For example, if 
`SomeNontrivialTypeName` has a fluent-style interface (i.e. an interface where 
instance methods return mutated `self` or new instances of 
`SomeNontrivialTypeName`):

        extension SomeNontrivialTypeName {
                func addThings() -> SomeNontrivialTypeName
        }

trying to append this function won't work, even though the return type remains 
correct:

        f(a: .a().addThings())

This fails and claims that we've forgotten to provide a parameter (!).

A completely different kind of transformation might go via a different type

        extension SomeNontrivialTypeName {
                static func another() -> AnotherType
        }
        
        struct AnotherType {
                func back() -> SomeNontrivialTypeName
        }

It would be nice to be able to use this "there-and-back-again" transformation:

        f(a: .another().back())

But it also won't work.

I realize that this is a point about minor syntactic efficiency. Yes, you could 
simply write:

        f(a: SomeNontrivialTypeName.another().back())

but it's clunky and the type name gets in the way.

There's also an element of consistency. Swift already lets us look up static 
functions in this way – but:
        
        * only functions that return the expected type
        * and we can't *use* the function result ourselves, it must be 
immediately yielded to the parameter or left-hand-side

Seems more than a little strange.

Anyone else care or have thoughts on this point?

Regards,
Matt Gallagher.

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to