> Are there reasons that prevent using `Self` as a synonym for an instance's > type name? > > Consider: > > struct MyStruct { > static func foo() { print("foo") } > func bar() { > MyStruct.foo() // works > self.dynamicType.foo() // works > Self.foo() // error > } > } > > Obviously, you can always name a type directly or use `self.dynamicType` but > neither solution does any favors for readability. Both approaches obscure > intent, > especially as type names grow large: `MyExtremelyLargeTypeName.staticMember`, > for example. Plus, as Kevin B pointed out to me, > `self.dynamicType.classMember` > and `TypeName.classMember` may not be synonyms in class types with non-final > members. > > I'd like to see `Self.staticMember` introduced as a synonym for > `TypeName.staticMember`. > > Thoughts?
I'm kind of struggling with how best to design this. Here's the most coherent design I've been able to come up with so far. * Adopt the proposal to no longer require `.self` on types to get the type instance. Using a type name in expression context gives you the type instance. * Every variable `foo` has a typealias attached to it, `foo.Self`. This is the static (compile-time declared or inferred) type of that instance. You can use it anywhere you can use a type name, including in declarations. If it's used in an expression, it becomes the type instance of the variable's static type. * Every variable `foo` has a special typealias attached to it, `foo.DynamicSelf`. This is the dynamic (runtime assigned) type of that instance. In theory you can use it anywhere you can use a type name, though in practice there are probably significant limitations. If it's used an expression, it become the type instance of the variable's dynamic type. * A bare `Self` or `DynamicSelf` is a shorthand for `self.Self` or `self.DynamicSelf`. `DynamicSelf` subsumes the roles of both the old `Self` and `dynamicType`. `Self` is both an alias for the declared type and a way to get its type instance. This gives us a number of new abilities: Self.classMember() // Instead of ReallyLongClassName.classMember() foo.Self.classMember() // Likewise, but for a different variable let self2: Self // Match the static type of self let foo2: foo.Self // Match the static type of a different variable DynamicSelf.classMember() // Instead of self.dynamicType.classMember() foo.DynamicSelf.classMember() // Likewise let self3: DynamicSelf // Match the dynamic type of self let foo3: foo.DynamicSelf // Match the dynamic type of a different variable // (Those would probably require certain restrictions, like the base variable has to be // immutable and the assignment has to come from a function returning a DynamicSelf // derived from `self`/`foo`.) // Make promises about matching dynamic types of parameters besides `self`: func tenMinutesAfter(date: NSDate) -> date.DynamicSelf { return date.adding(10 * 60) // Note that `adding(_: NSTimeInterval)` returns DynamicSelf } // Possible alternative to generic syntax: func removingCommonPrefix(_ one: Collection, _ two: Collection) -> (one.Self.SubSequence, two.Self.SubSequence) where one.Self.Element == two.Self.Element, one.Self.Element: Equatable { for (oneIndex, twoIndex) in zip(one.indices + [one.endIndex], two.indices + [two.endIndex]) { if oneIndex == one.endIndex || twoIndex == two.endIndex || one[oneIndex] != two[twoIndex] { return (one.suffixFrom(oneIndex), two.suffixFrom(twoIndex)) } } fatalError("Can't get here") } The only disadvantage I see to this approach is that code which currently uses `Self` will be longer. But there may be other problems as well. I'm not entirely sure I have a good handle on the existing `Self` vs. `dynamicType`; it's possible the connection I see between them is spurious or ill-defined. By the way, an alternative would be to leave the dynamic type as `Self` and call the static type `Type`, which I *think* would generalize the existing notion of the metatype being accessible as `Type`. In other words: Type.classMember() // Instead of ReallyLongClassName.classMember() foo.Type.classMember() // Likewise, but for a different variable let self2: Type // Match the static type of self let foo2: foo.Type // Match the static type of a different variable Self.classMember() // Instead of self.dynamicType.classMember() foo.Self.classMember() // Likewise let self3: Self // Match the dynamic type of self let foo3: foo.Self // Match the dynamic type of a different variable // (Those would probably require certain restrictions, like the base variable has to be // immutable and the assignment has to come from a function returning a Self // derived from `self`/`foo`.) // Make promises about matching dynamic types of parameters besides `self`: func tenMinutesAfter(date: NSDate) -> date.Self { return date.adding(10 * 60) // Note that `adding(_: NSTimeInterval)` returns Self } // Possible alternative to generic syntax: func removingCommonPrefix(_ one: Collection, _ two: Collection) -> (one.Type.SubSequence, two.Type.SubSequence) where one.Type.Element == two.Type.Element, one.Type.Element: Equatable { for (oneIndex, twoIndex) in zip(one.indices + [one.endIndex], two.indices + [two.endIndex]) { if oneIndex == one.endIndex || twoIndex == two.endIndex || one[oneIndex] != two[twoIndex] { return (one.suffixFrom(oneIndex), two.suffixFrom(twoIndex)) } } fatalError("Can't get here") } But I'm even *less* certain that `someVariable.Type` and `SomeClass.Type` are similar in any real sense, so I have my doubts about the wisdom of that one. -- Brent Royal-Gordon Architechies _______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution