[Pitch] Rename `x.dynamicType` to `x.Self`


(Joe Groff) #1

It's been pitched before, but I don't think we've had a dedicated thread to this idea. Erica has proposed making `Self` generally available within methods in types to refer to the dynamic type of the current receiver. One could think of `Self` as a special associated type member that exists in every type for this purpose. This also happens to be what you get when ask for the `dynamicType` member of a value. We could unify these concepts and get rid of the clunky `dynamicType` keyword, replacing it with `x.Self`.

There's another benefit to this syntax change. Looking to the future, one of the many features Doug pitched in his generics manifesto was to generalize protocol existentials, lifting our current restrictions on protocols "with Self or associated types" and allowing them to be used as dynamic types in addition to static generic constraints. Once you do this, you often want to "open" the type of the existential, so that you can refer to its Self and associated types in the types of other values. I think a natural way would be to let you directly use Self and associated type members of existentials as types themselves, for example:

  let a: Equatable = /*...*/
  let b: Equatable = /*...*/

  // This is not allowed, since Equatable requires two values with the same static type, but
  // a and b may have different dynamic types.
  a == b

  // However, we can dynamically cast one to the other's dynamic type:
  if let bAsA = b as? a.Self {
    return a == bAsA
  }

  let x: RangeReplaceableCollection = /*...*/
  let y: Collection = /*...*/

  // If y has the same dynamic Element type as x, append it to x
  var z: x.Self = x
  if let yAsX = y as? Any<Collection where Element == x.Element> {
    z.append(yAsX)
  }

`x.Self` then becomes just the first step in this direction.

-Joe


(William Dillon) #2

This would be great!

I use a nearly identical pattern in my networking framework that would be nice to streamline:

public func ==(lhs: NetworkAddress, rhs: NetworkAddress) -> Bool {
    // Only addresses of the same protocol are considered equal.
    guard lhs.dynamicType == rhs.dynamicType else {
        return false
    }
    
    if lhs.dynamicType == IPv4NetworkAddress.self {
        return (lhs as! IPv4NetworkAddress) == (rhs as! IPv4NetworkAddress)
    }

    if lhs.dynamicType == IPv6NetworkAddress.self {
        return (lhs as! IPv6NetworkAddress) == (rhs as! IPv6NetworkAddress)
    }
    
    return false
}

- Will

···

On Apr 13, 2016, at 6:41 PM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

It's been pitched before, but I don't think we've had a dedicated thread to this idea. Erica has proposed making `Self` generally available within methods in types to refer to the dynamic type of the current receiver. One could think of `Self` as a special associated type member that exists in every type for this purpose. This also happens to be what you get when ask for the `dynamicType` member of a value. We could unify these concepts and get rid of the clunky `dynamicType` keyword, replacing it with `x.Self`.

There's another benefit to this syntax change. Looking to the future, one of the many features Doug pitched in his generics manifesto was to generalize protocol existentials, lifting our current restrictions on protocols "with Self or associated types" and allowing them to be used as dynamic types in addition to static generic constraints. Once you do this, you often want to "open" the type of the existential, so that you can refer to its Self and associated types in the types of other values. I think a natural way would be to let you directly use Self and associated type members of existentials as types themselves, for example:

  let a: Equatable = /*...*/
  let b: Equatable = /*...*/

  // This is not allowed, since Equatable requires two values with the same static type, but
  // a and b may have different dynamic types.
  a == b

  // However, we can dynamically cast one to the other's dynamic type:
  if let bAsA = b as? a.Self {
    return a == bAsA
  }

  let x: RangeReplaceableCollection = /*...*/
  let y: Collection = /*...*/

  // If y has the same dynamic Element type as x, append it to x
  var z: x.Self = x
  if let yAsX = y as? Any<Collection where Element == x.Element> {
    z.append(yAsX)
  }

`x.Self` then becomes just the first step in this direction.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Erica Sadun) #3

Pull request updated with just the rename. This amounted to basically saying "Self" will replace
"self.dynamicType" and eliminate an outlier case for a keyword using camel case.

I did not include any discussion of generalizing protocol existentials. I can add in
a future directions section if you think it appropriate.

-- E

···

On Apr 13, 2016, at 7:41 PM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

It's been pitched before, but I don't think we've had a dedicated thread to this idea. Erica has proposed making `Self` generally available within methods in types to refer to the dynamic type of the current receiver. One could think of `Self` as a special associated type member that exists in every type for this purpose. This also happens to be what you get when ask for the `dynamicType` member of a value. We could unify these concepts and get rid of the clunky `dynamicType` keyword, replacing it with `x.Self`.

There's another benefit to this syntax change. Looking to the future, one of the many features Doug pitched in his generics manifesto was to generalize protocol existentials, lifting our current restrictions on protocols "with Self or associated types" and allowing them to be used as dynamic types in addition to static generic constraints. Once you do this, you often want to "open" the type of the existential, so that you can refer to its Self and associated types in the types of other values. I think a natural way would be to let you directly use Self and associated type members of existentials as types themselves, for example:

  let a: Equatable = /*...*/
  let b: Equatable = /*...*/

  // This is not allowed, since Equatable requires two values with the same static type, but
  // a and b may have different dynamic types.
  a == b

  // However, we can dynamically cast one to the other's dynamic type:
  if let bAsA = b as? a.Self {
    return a == bAsA
  }

  let x: RangeReplaceableCollection = /*...*/
  let y: Collection = /*...*/

  // If y has the same dynamic Element type as x, append it to x
  var z: x.Self = x
  if let yAsX = y as? Any<Collection where Element == x.Element> {
    z.append(yAsX)
  }

`x.Self` then becomes just the first step in this direction.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Dave Abrahams) #4

It's been pitched before, but I don't think we've had a dedicated
thread to this idea. Erica has proposed making `Self` generally
available within methods in types to refer to the dynamic type of the
current receiver. One could think of `Self` as a special associated
type member that exists in every type for this purpose. This also
happens to be what you get when ask for the `dynamicType` member of a
value. We could unify these concepts and get rid of the clunky
`dynamicType` keyword, replacing it with `x.Self`.

There's another benefit to this syntax change. Looking to the future,
one of the many features Doug pitched in his generics manifesto was to
generalize protocol existentials, lifting our current restrictions on
protocols "with Self or associated types" and allowing them to be used
as dynamic types in addition to static generic constraints. Once you
do this, you often want to "open" the type of the existential, so that
you can refer to its Self and associated types in the types of other
values. I think a natural way would be to let you directly use Self
and associated type members of existentials as types themselves, for
example:

  let a: Equatable = /*...*/
  let b: Equatable = /*...*/

  // This is not allowed, since Equatable requires two values
with the same static type, but
  // a and b may have different dynamic types.
  a == b

  // However, we can dynamically cast one to the other's dynamic
type:
  if let bAsA = b as? a.Self {
    return a == bAsA
  }

This doesn't entirely work, I think:

     class Z : Equatable {} // ...
     class A : Z {}
     class B : Z {}

     let a: Equatable = A()
     let b: Equatable = B()
     if let bAsA = b as? a.Self { ... } // test fails.

Of course, one could decide we don't care about classes conforming to
protocols with Self requirements.

  let x: RangeReplaceableCollection = /*...*/
  let y: Collection = /*...*/

  // If y has the same dynamic Element type as x, append it to x
  var z: x.Self = x
  if let yAsX = y as? Any<Collection where Element == x.Element>

I don't think x.Element can work. Do you mean x.Self.Element?

···

on Wed Apr 13 2016, Joe Groff <swift-evolution@swift.org> wrote:

{ z.append(yAsX) }

`x.Self` then becomes just the first step in this direction.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave


(Vladimir) #5

+1, I also support. We already have Self in meaning of dynamicType as result of method, for example:

class A {
     func some()->Self {
         //print(self.dynamicType) // btw: if we uncomment this - will get run-time error wtf??
         return self
     }
}

class B:A {
}

var aa = B()

print(aa.some().dynamicType)

so why do we need to have this "dynamicType" instead of "Self".
It seems to be natural to have

print(aa.some().Self)

···

On 14.04.2016 4:41, Joe Groff via swift-evolution wrote:

It's been pitched before, but I don't think we've had a dedicated thread to this idea. Erica has proposed making `Self` generally available within methods in types to refer to the dynamic type of the current receiver. One could think of `Self` as a special associated type member that exists in every type for this purpose. This also happens to be what you get when ask for the `dynamicType` member of a value. We could unify these concepts and get rid of the clunky `dynamicType` keyword, replacing it with `x.Self`.

There's another benefit to this syntax change. Looking to the future, one of the many features Doug pitched in his generics manifesto was to generalize protocol existentials, lifting our current restrictions on protocols "with Self or associated types" and allowing them to be used as dynamic types in addition to static generic constraints. Once you do this, you often want to "open" the type of the existential, so that you can refer to its Self and associated types in the types of other values. I think a natural way would be to let you directly use Self and associated type members of existentials as types themselves, for example:

  let a: Equatable = /*...*/
  let b: Equatable = /*...*/

  // This is not allowed, since Equatable requires two values with the same static type, but
  // a and b may have different dynamic types.
  a == b

  // However, we can dynamically cast one to the other's dynamic type:
  if let bAsA = b as? a.Self {
    return a == bAsA
  }

  let x: RangeReplaceableCollection = /*...*/
  let y: Collection = /*...*/

  // If y has the same dynamic Element type as x, append it to x
  var z: x.Self = x
  if let yAsX = y as? Any<Collection where Element == x.Element> {
    z.append(yAsX)
  }

`x.Self` then becomes just the first step in this direction.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(L Mihalkovic) #6

+1

can’t wait for the Generics 4.0:

++++ typealias StringDictionary<Value> = Dictionary<String, Value>
++++ Parameterized extensions
+++ func containsAll<S: Sequence>(elements: S) -> Bool
       where Sequence.Iterator.Element == Element
++++++++++ Higher-kinded types
+++ Generalized existentials
     Generic protocols
The ConstructibleFrom<X> looks a bit like something I played with this afternoon:

public protocol LiteralCreatable {
    associatedtype LiteralType
    init(literalValue : LiteralType)
}
public protocol NilLiteralConvertible : LiteralCreatable {
    associatedtype LiteralType = ()
}
public protocol StringLiteralCreatable : LiteralCreatable {
    associatedtype LiteralType = String
}
public protocol IntLiteralCreatable : LiteralCreatable {
    associatedtype LiteralType = Int
}

Cheers,
L/

···

On Apr 14, 2016, at 3:41 AM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

It's been pitched before, but I don't think we've had a dedicated thread to this idea. Erica has proposed making `Self` generally available within methods in types to refer to the dynamic type of the current receiver. One could think of `Self` as a special associated type member that exists in every type for this purpose. This also happens to be what you get when ask for the `dynamicType` member of a value. We could unify these concepts and get rid of the clunky `dynamicType` keyword, replacing it with `x.Self`.

There's another benefit to this syntax change. Looking to the future, one of the many features Doug pitched in his generics manifesto was to generalize protocol existentials, lifting our current restrictions on protocols "with Self or associated types" and allowing them to be used as dynamic types in addition to static generic constraints. Once you do this, you often want to "open" the type of the existential, so that you can refer to its Self and associated types in the types of other values. I think a natural way would be to let you directly use Self and associated type members of existentials as types themselves, for example:

  let a: Equatable = /*...*/
  let b: Equatable = /*...*/

  // This is not allowed, since Equatable requires two values with the same static type, but
  // a and b may have different dynamic types.
  a == b

  // However, we can dynamically cast one to the other's dynamic type:
  if let bAsA = b as? a.Self {
    return a == bAsA
  }

  let x: RangeReplaceableCollection = /*...*/
  let y: Collection = /*...*/

  // If y has the same dynamic Element type as x, append it to x
  var z: x.Self = x
  if let yAsX = y as? Any<Collection where Element == x.Element> {
    z.append(yAsX)
  }

`x.Self` then becomes just the first step in this direction.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Taras Zakharko) #7

I do not understand why we can’t do

  type(self)

or even

#type(self)

Personally, I find .Self business to be quite confusing and idiosyncratic. Having a generic #type() directive would be a general improvement for the language design and it would also open up future possibilities such as

extension A where A.B == #type(A.C.property1) {

}

and other potentially useful things.

···

On 14 Apr 2016, at 03:41, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

It's been pitched before, but I don't think we've had a dedicated thread to this idea. Erica has proposed making `Self` generally available within methods in types to refer to the dynamic type of the current receiver. One could think of `Self` as a special associated type member that exists in every type for this purpose. This also happens to be what you get when ask for the `dynamicType` member of a value. We could unify these concepts and get rid of the clunky `dynamicType` keyword, replacing it with `x.Self`.

There's another benefit to this syntax change. Looking to the future, one of the many features Doug pitched in his generics manifesto was to generalize protocol existentials, lifting our current restrictions on protocols "with Self or associated types" and allowing them to be used as dynamic types in addition to static generic constraints. Once you do this, you often want to "open" the type of the existential, so that you can refer to its Self and associated types in the types of other values. I think a natural way would be to let you directly use Self and associated type members of existentials as types themselves, for example:

  let a: Equatable = /*...*/
  let b: Equatable = /*...*/

  // This is not allowed, since Equatable requires two values with the same static type, but
  // a and b may have different dynamic types.
  a == b

  // However, we can dynamically cast one to the other's dynamic type:
  if let bAsA = b as? a.Self {
    return a == bAsA
  }

  let x: RangeReplaceableCollection = /*...*/
  let y: Collection = /*...*/

  // If y has the same dynamic Element type as x, append it to x
  var z: x.Self = x
  if let yAsX = y as? Any<Collection where Element == x.Element> {
    z.append(yAsX)
  }

`x.Self` then becomes just the first step in this direction.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Howard Lovatt) #8

+1 nice addition

  -- Howard.

···

On 14 April 2016 at 11:41, Joe Groff via swift-evolution < swift-evolution@swift.org> wrote:

It's been pitched before, but I don't think we've had a dedicated thread
to this idea. Erica has proposed making `Self` generally available within
methods in types to refer to the dynamic type of the current receiver. One
could think of `Self` as a special associated type member that exists in
every type for this purpose. This also happens to be what you get when ask
for the `dynamicType` member of a value. We could unify these concepts and
get rid of the clunky `dynamicType` keyword, replacing it with `x.Self`.

There's another benefit to this syntax change. Looking to the future, one
of the many features Doug pitched in his generics manifesto was to
generalize protocol existentials, lifting our current restrictions on
protocols "with Self or associated types" and allowing them to be used as
dynamic types in addition to static generic constraints. Once you do this,
you often want to "open" the type of the existential, so that you can refer
to its Self and associated types in the types of other values. I think a
natural way would be to let you directly use Self and associated type
members of existentials as types themselves, for example:

        let a: Equatable = /*...*/
        let b: Equatable = /*...*/

        // This is not allowed, since Equatable requires two values with
the same static type, but
        // a and b may have different dynamic types.
        a == b

        // However, we can dynamically cast one to the other's dynamic
type:
        if let bAsA = b as? a.Self {
                return a == bAsA
        }

        let x: RangeReplaceableCollection = /*...*/
        let y: Collection = /*...*/

        // If y has the same dynamic Element type as x, append it to x
        var z: x.Self = x
        if let yAsX = y as? Any<Collection where Element == x.Element> {
                z.append(yAsX)
        }

`x.Self` then becomes just the first step in this direction.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Eugene Gubin) #9

I like this idea. I think, if we could use `self` to access instance of
self, we should be allowed to use `Self` to access type of self.

···

2016-04-14 8:46 GMT+04:00 William Dillon via swift-evolution < swift-evolution@swift.org>:

This would be great!

I use a nearly identical pattern in my networking framework that would be
nice to streamline:

public func ==(lhs: NetworkAddress, rhs: NetworkAddress) -> Bool {
    // Only addresses of the same protocol are considered equal.
    guard lhs.dynamicType == rhs.dynamicType else {
        return false
    }

    if lhs.dynamicType == IPv4NetworkAddress.self {
        return (lhs as! IPv4NetworkAddress) == (rhs as! IPv4NetworkAddress
)
    }

    if lhs.dynamicType == IPv6NetworkAddress.self {
        return (lhs as! IPv6NetworkAddress) == (rhs as! IPv6NetworkAddress
)
    }

    return false
}

- Will

On Apr 13, 2016, at 6:41 PM, Joe Groff via swift-evolution < > swift-evolution@swift.org> wrote:

It's been pitched before, but I don't think we've had a dedicated thread
to this idea. Erica has proposed making `Self` generally available within
methods in types to refer to the dynamic type of the current receiver. One
could think of `Self` as a special associated type member that exists in
every type for this purpose. This also happens to be what you get when ask
for the `dynamicType` member of a value. We could unify these concepts and
get rid of the clunky `dynamicType` keyword, replacing it with `x.Self`.

There's another benefit to this syntax change. Looking to the future, one
of the many features Doug pitched in his generics manifesto was to
generalize protocol existentials, lifting our current restrictions on
protocols "with Self or associated types" and allowing them to be used as
dynamic types in addition to static generic constraints. Once you do this,
you often want to "open" the type of the existential, so that you can refer
to its Self and associated types in the types of other values. I think a
natural way would be to let you directly use Self and associated type
members of existentials as types themselves, for example:

let a: Equatable = /*...*/
let b: Equatable = /*...*/

// This is not allowed, since Equatable requires two values with the same
static type, but
// a and b may have different dynamic types.
a == b

// However, we can dynamically cast one to the other's dynamic type:
if let bAsA = b as? a.Self {
return a == bAsA
}

let x: RangeReplaceableCollection = /*...*/
let y: Collection = /*...*/

// If y has the same dynamic Element type as x, append it to x
var z: x.Self = x
if let yAsX = y as? Any<Collection where Element == x.Element> {
z.append(yAsX)
}

`x.Self` then becomes just the first step in this direction.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Joe Groff) #10

It's been pitched before, but I don't think we've had a dedicated
thread to this idea. Erica has proposed making `Self` generally
available within methods in types to refer to the dynamic type of the
current receiver. One could think of `Self` as a special associated
type member that exists in every type for this purpose. This also
happens to be what you get when ask for the `dynamicType` member of a
value. We could unify these concepts and get rid of the clunky
`dynamicType` keyword, replacing it with `x.Self`.

There's another benefit to this syntax change. Looking to the future,
one of the many features Doug pitched in his generics manifesto was to
generalize protocol existentials, lifting our current restrictions on
protocols "with Self or associated types" and allowing them to be used
as dynamic types in addition to static generic constraints. Once you
do this, you often want to "open" the type of the existential, so that
you can refer to its Self and associated types in the types of other
values. I think a natural way would be to let you directly use Self
and associated type members of existentials as types themselves, for
example:

  let a: Equatable = /*...*/
  let b: Equatable = /*...*/

  // This is not allowed, since Equatable requires two values
with the same static type, but
  // a and b may have different dynamic types.
  a == b

  // However, we can dynamically cast one to the other's dynamic
type:
  if let bAsA = b as? a.Self {
    return a == bAsA
  }

This doesn't entirely work, I think:

    class Z : Equatable {} // ...
    class A : Z {}
    class B : Z {}

    let a: Equatable = A()
    let b: Equatable = B()
    if let bAsA = b as? a.Self { ... } // test fails.

Of course, one could decide we don't care about classes conforming to
protocols with Self requirements.

I don't see the problem. B is-an A, so equating an A to a B is equating an A to an A (from the conformance's perspective, Self == A). A() == B() works by the same principle.

  let x: RangeReplaceableCollection = /*...*/
  let y: Collection = /*...*/

  // If y has the same dynamic Element type as x, append it to x
  var z: x.Self = x
  if let yAsX = y as? Any<Collection where Element == x.Element>

I don't think x.Element can work. Do you mean x.Self.Element?

TBD, when we get there, but requiring `x.Self.Element` doesn't seem necessary to me.

-Joe

···

On Apr 14, 2016, at 12:29 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Wed Apr 13 2016, Joe Groff <swift-evolution@swift.org> wrote:


(Joe Groff) #11

Swift's type system has static and dynamic manifestations, and you're conflating them here. #type in a situation like `where A.B == #type(A.C.property1)` would have to produce the static type of property, whereas `x.dynamicType` today produces the dynamic type of a class or existential.

-Joe

···

On Apr 14, 2016, at 1:11 PM, Taras Zakharko <taras.zakharko@uzh.ch> wrote:

I do not understand why we can’t do

type(self)

or even

#type(self)

Personally, I find .Self business to be quite confusing and idiosyncratic. Having a generic #type() directive would be a general improvement for the language design and it would also open up future possibilities such as

extension A where A.B == #type(A.C.property1) {

}

and other potentially useful things.


(Brandon Knope) #12

-1 from me. To me this is not *obvious* as to what "Self" it means.

And it seems possible to run into this:
self.someClass.Self

Just looks confusing to me. What's wrong with using "Type" or something more obvious?

···

Sent from my iPad

On Apr 14, 2016, at 10:28 AM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

+1, I also support. We already have Self in meaning of dynamicType as result of method, for example:

class A {
   func some()->Self {
       //print(self.dynamicType) // btw: if we uncomment this - will get run-time error wtf??
       return self
   }
}

class B:A {
}

var aa = B()

print(aa.some().dynamicType)

so why do we need to have this "dynamicType" instead of "Self".
It seems to be natural to have

print(aa.some().Self)

On 14.04.2016 4:41, Joe Groff via swift-evolution wrote:
It's been pitched before, but I don't think we've had a dedicated thread to this idea. Erica has proposed making `Self` generally available within methods in types to refer to the dynamic type of the current receiver. One could think of `Self` as a special associated type member that exists in every type for this purpose. This also happens to be what you get when ask for the `dynamicType` member of a value. We could unify these concepts and get rid of the clunky `dynamicType` keyword, replacing it with `x.Self`.

There's another benefit to this syntax change. Looking to the future, one of the many features Doug pitched in his generics manifesto was to generalize protocol existentials, lifting our current restrictions on protocols "with Self or associated types" and allowing them to be used as dynamic types in addition to static generic constraints. Once you do this, you often want to "open" the type of the existential, so that you can refer to its Self and associated types in the types of other values. I think a natural way would be to let you directly use Self and associated type members of existentials as types themselves, for example:

   let a: Equatable = /*...*/
   let b: Equatable = /*...*/

   // This is not allowed, since Equatable requires two values with the same static type, but
   // a and b may have different dynamic types.
   a == b

   // However, we can dynamically cast one to the other's dynamic type:
   if let bAsA = b as? a.Self {
       return a == bAsA
   }

   let x: RangeReplaceableCollection = /*...*/
   let y: Collection = /*...*/

   // If y has the same dynamic Element type as x, append it to x
   var z: x.Self = x
   if let yAsX = y as? Any<Collection where Element == x.Element> {
       z.append(yAsX)
   }

`x.Self` then becomes just the first step in this direction.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Taras Zakharko) #13

I do not think that I was conflating these two aspects. Using #type(self) would return the particular type of the current instance (dynamic type) while using #type(A.var) would return the declared (static) type of the property. Now,

  let a = A()
  #type(a.var)

would again return the actual (dynamic) type of var

In essence, I don’t see why we need to separate the mechanisms for querying these types when the distinction can be made on the grounds whether we are querying the type of a particular value/instance or a particular (not instantiated) declaration.

— Taras

P.S. Does Swift today even have the means of querying the static type of a variable once it has been instantiated, i.e. can I programmatically find out that x has been declared as P in this scope:

let x : P = TypeThatConformsToP()

If you really want to differentiate between these two then we’d need two separate mechanisms, e.g. #statictype(), #dynamictype(), with #dynamictype() referring to the instantiated value and $statictype() referring to the variable declaration.

···

On 14 Apr 2016, at 22:59, Joe Groff <jgroff@apple.com> wrote:

On Apr 14, 2016, at 1:11 PM, Taras Zakharko <taras.zakharko@uzh.ch> wrote:

I do not understand why we can’t do

type(self)

or even

#type(self)

Personally, I find .Self business to be quite confusing and idiosyncratic. Having a generic #type() directive would be a general improvement for the language design and it would also open up future possibilities such as

extension A where A.B == #type(A.C.property1) {

}

and other potentially useful things.

Swift's type system has static and dynamic manifestations, and you're conflating them here. #type in a situation like `where A.B == #type(A.C.property1)` would have to produce the static type of property, whereas `x.dynamicType` today produces the dynamic type of a class or existential.

-Joe


(Joe Groff) #14

It's been pitched before, but I don't think we've had a dedicated
thread to this idea. Erica has proposed making `Self` generally
available within methods in types to refer to the dynamic type of the
current receiver. One could think of `Self` as a special associated
type member that exists in every type for this purpose. This also
happens to be what you get when ask for the `dynamicType` member of a
value. We could unify these concepts and get rid of the clunky
`dynamicType` keyword, replacing it with `x.Self`.

There's another benefit to this syntax change. Looking to the future,
one of the many features Doug pitched in his generics manifesto was to
generalize protocol existentials, lifting our current restrictions on
protocols "with Self or associated types" and allowing them to be used
as dynamic types in addition to static generic constraints. Once you
do this, you often want to "open" the type of the existential, so that
you can refer to its Self and associated types in the types of other
values. I think a natural way would be to let you directly use Self
and associated type members of existentials as types themselves, for
example:

  let a: Equatable = /*...*/
  let b: Equatable = /*...*/

  // This is not allowed, since Equatable requires two values
with the same static type, but
  // a and b may have different dynamic types.
  a == b

  // However, we can dynamically cast one to the other's dynamic
type:
  if let bAsA = b as? a.Self {
    return a == bAsA
  }

This doesn't entirely work, I think:

    class Z : Equatable {} // ...
    class A : Z {}
    class B : Z {}

    let a: Equatable = A()
    let b: Equatable = B()
    if let bAsA = b as? a.Self { ... } // test fails.

Of course, one could decide we don't care about classes conforming to
protocols with Self requirements.

I see, I misread in my previous response. You're right this wouldn't necessarily just work. This is far from the only subtle issue with existentials containing subclasses, though; unfortunately there are two levels of dynamic type at play, and we're pretty inconsistent about keeping them, well, consistent. One approach here might be to try to always store the upper bound class as the existential-dynamic-type of the existential wrapper.

-Joe

···

On Apr 14, 2016, at 12:29 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Wed Apr 13 2016, Joe Groff <swift-evolution@swift.org> wrote:

  let x: RangeReplaceableCollection = /*...*/
  let y: Collection = /*...*/

  // If y has the same dynamic Element type as x, append it to x
  var z: x.Self = x
  if let yAsX = y as? Any<Collection where Element == x.Element>

I don't think x.Element can work. Do you mean x.Self.Element?

{ z.append(yAsX) }

`x.Self` then becomes just the first step in this direction.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Joe Groff) #15

That's a fair point. On the other hand, I think we're pretty consistent now about using CapitalizedCamelCase for types and lowerCamelCase for non-types, so while we could rename Self to SelfType, that feels a bit redundant to me if you've already internalized "caps == types".

-Joe

···

On Apr 14, 2016, at 11:59 AM, Brandon Knope <bknope@me.com> wrote:

-1 from me. To me this is not *obvious* as to what "Self" it means.

And it seems possible to run into this:
self.someClass.Self

Just looks confusing to me. What's wrong with using "Type" or something more obvious?


(Ilya Belenkiy) #16

+1. Completely agree with what Eugene said.

···

On Thu, Apr 14, 2016 at 1:14 AM Eugene Gubin via swift-evolution < swift-evolution@swift.org> wrote:

I like this idea. I think, if we could use `self` to access instance of
self, we should be allowed to use `Self` to access type of self.

2016-04-14 8:46 GMT+04:00 William Dillon via swift-evolution <
swift-evolution@swift.org>:

This would be great!

I use a nearly identical pattern in my networking framework that would be
nice to streamline:

public func ==(lhs: NetworkAddress, rhs: NetworkAddress) -> Bool {
    // Only addresses of the same protocol are considered equal.
    guard lhs.dynamicType == rhs.dynamicType else {
        return false
    }

    if lhs.dynamicType == IPv4NetworkAddress.self {
        return (lhs as! IPv4NetworkAddress) == (rhs as!
IPv4NetworkAddress)
    }

    if lhs.dynamicType == IPv6NetworkAddress.self {
        return (lhs as! IPv6NetworkAddress) == (rhs as!
IPv6NetworkAddress)
    }

    return false
}

- Will

On Apr 13, 2016, at 6:41 PM, Joe Groff via swift-evolution < >> swift-evolution@swift.org> wrote:

It's been pitched before, but I don't think we've had a dedicated thread
to this idea. Erica has proposed making `Self` generally available within
methods in types to refer to the dynamic type of the current receiver. One
could think of `Self` as a special associated type member that exists in
every type for this purpose. This also happens to be what you get when ask
for the `dynamicType` member of a value. We could unify these concepts and
get rid of the clunky `dynamicType` keyword, replacing it with `x.Self`.

There's another benefit to this syntax change. Looking to the future, one
of the many features Doug pitched in his generics manifesto was to
generalize protocol existentials, lifting our current restrictions on
protocols "with Self or associated types" and allowing them to be used as
dynamic types in addition to static generic constraints. Once you do this,
you often want to "open" the type of the existential, so that you can refer
to its Self and associated types in the types of other values. I think a
natural way would be to let you directly use Self and associated type
members of existentials as types themselves, for example:

let a: Equatable = /*...*/
let b: Equatable = /*...*/

// This is not allowed, since Equatable requires two values with the same
static type, but
// a and b may have different dynamic types.
a == b

// However, we can dynamically cast one to the other's dynamic type:
if let bAsA = b as? a.Self {
return a == bAsA
}

let x: RangeReplaceableCollection = /*...*/
let y: Collection = /*...*/

// If y has the same dynamic Element type as x, append it to x
var z: x.Self = x
if let yAsX = y as? Any<Collection where Element == x.Element> {
z.append(yAsX)
}

`x.Self` then becomes just the first step in this direction.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Andrey Tarantsov) #17

I do not think that I was conflating these two aspects. Using #type(self) would return the particular type of the current instance (dynamic type) while using #type(A.var) would return the declared (static) type of the property.

Taras, to me personally, #something suggests evaluation at compilation time, so I would be *extremely* surprised if #type would return a dynamic type, and #dynamictype is just an abomination, in every way worse than something.dynamicType.

A.


(Brandon Knope) #18

I'm just concerned about the obviousness of it. If what we are doing is just grabbing the type, why couldn't it be:

someClass.Type (like in the generic system)

I'm open to Self, but I just want to make sure we exhaust all avenues that are more obvious at a glance:

.Self.Type
.ThisType
.SelfType
.Type

SelfType is redundant but it also more obvious at first look.

Maybe it doesn't matter and I am caring about the looks of it too much. Because so many people seem to support .Self in this thread, it might just be me and something I need to accept :stuck_out_tongue:

Brandon

···

On Apr 15, 2016, at 1:19 PM, Joe Groff <jgroff@apple.com> wrote:

On Apr 14, 2016, at 11:59 AM, Brandon Knope <bknope@me.com> wrote:

-1 from me. To me this is not *obvious* as to what "Self" it means.

And it seems possible to run into this:
self.someClass.Self

Just looks confusing to me. What's wrong with using "Type" or something more obvious?

That's a fair point. On the other hand, I think we're pretty consistent now about using CapitalizedCamelCase for types and lowerCamelCase for non-types, so while we could rename Self to SelfType, that feels a bit redundant to me if you've already internalized "caps == types".

-Joe


(Joe Groff) #19

The way I see it, my proposed change reduces the total amount of magic. Associated types *are* members of their parent type, and `Self` is a special case of an associated type.

-Joe

···

On Apr 15, 2016, at 3:19 AM, Taras Zakharko <taras.zakharko@uzh.ch> wrote:

True, that makes sense. I was simply trying to explore different possibilities of how these things could be represented in the syntax. What about #type(d) for static (declaration) type and type(v) for dynamic (value/instance) type? Or would that be potentially confusing as well?

The reason why I dislike .dynamicType etc. declarations is because they introduce another ‘magic’ properties to instances. I think that this functionality is very important and that it should be represented by the standard library instead. If Swift had a universal base type, one could say that the magic properties are just part of that base type (and by extension, part of the standard library), however, right now, they are injected by the compiler. I’d rather have a standard function like

type: (Any)->AnyType

for this purpose. Hell, I would even say that dynamicType(self) is an improvement over self.dynamicType :slight_smile:


(Taras Zakharko) #20

True, that makes sense. I was simply trying to explore different possibilities of how these things could be represented in the syntax. What about #type(d) for static (declaration) type and type(v) for dynamic (value/instance) type? Or would that be potentially confusing as well?

The reason why I dislike .dynamicType etc. declarations is because they introduce another ‘magic’ properties to instances. I think that this functionality is very important and that it should be represented by the standard library instead. If Swift had a universal base type, one could say that the magic properties are just part of that base type (and by extension, part of the standard library), however, right now, they are injected by the compiler. I’d rather have a standard function like

type: (Any)->AnyType

for this purpose. Hell, I would even say that dynamicType(self) is an improvement over self.dynamicType :slight_smile:

— Taras

···

On 15 Apr 2016, at 09:54, Andrey Tarantsov <andrey@tarantsov.com> wrote:

I do not think that I was conflating these two aspects. Using #type(self) would return the particular type of the current instance (dynamic type) while using #type(A.var) would return the declared (static) type of the property.

Taras, to me personally, #something suggests evaluation at compilation time, so I would be *extremely* surprised if #type would return a dynamic type, and #dynamictype is just an abomination, in every way worse than something.dynamicType.

A.