> 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
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution