Why no Self within structs?

Self (capital S) can be used within protocols and protocol extensions (to mean the conforming type).

But within structs, we must use the actual name of the type, as demonstrated by this contrived example:

protocol Pairable {
    func pairedWith(other: Self) -> (Self, Self)
}
extension Pairable {
    func pairedWith(other: Self) -> (Self, Self) { return (self, other) }
}
struct UsingDefaultImpl : Pairable {}
struct ReversedPairable {
    func pairedWith(other: ReversedPairable) -> (ReversedPairable, ReversedPairable) { return (other, self) }
    // Ok, but why not simply:
    // func pairedWith(other: Self) -> (Self, Self) { return (other, self) }
    // ?
}
extension ReversedPairable : Pairable {}


So, what's the rationale behind not allowing Self within a struct?

(It can't be to to avoid mixing up Self and self. (See the default implementation for pairedWith in the protocol extension above.))

I have never understood why either.

You can still use self.dynamicType but the compiler no longer suggests it (did you mean...? ;-)


Jan E.

You can't use self.dynamicType outside function/method bodies, eg for argument and return types, so this won't work:

func pairedWith(other: self.dynamicType) -> (self.dynamicType, self.dynamicType) { return (other, self) }

(Not sure what you meant by "(did you mean..? ;-)".)

This is not unique to structs; it's true of all concrete types.


I think the alternative we have now should be disallowed. I don't remember the name of the thing I'm in that easily and it doesn't matter conceptually. Also, nearly everything takes up more room on the screen than Self.

Not quite true, because Self (capital S) can also be used within classes, but only as the return type of a method, so this compiles fine:

class C {
    func someMethod() -> Self { return self }
}


I'm focusing on structs here just because that's where I'm most often frustrated by this. But I guess enums and classes could be included, with the above exception in mind.

This doesn't compile:

class C {
    var someProperty: Self {return self}
}

and it's pointless for either to compile:

protocol CType {}
extension CType {
   func someMethod() -> Self {return self}
   var someProperty: Self {return self}
}


Reference types being tied in with inheritance is a weird overload.

This is (at least the beginning of) a great example of why I'm staying away from classes, not to mention inheritance, as much as I possibly can in my code, and in (the topic of) this thread. : )

Yeah, wouldn't it be cool if Self wasn't just basically the same thing as instancetype? I wish it were valid to use in places other than return types. Something like this in Objective-C:

+ (NSString *)defaultName { return "Element";}
- (id)init {
     if (self = [super init]) {
          _name = [self.class defaultName];
     }
     return self;
}

has to be written in Swift like this, with this odd jump through a private instance method:

public class func defaultName() -> String {
     return "Element"
}

private func defaultName() -> String {
     return self.dynamicType.defaultName()
}

public var name: String = defaultName()


Wouldn't it be nice if I could just write this?

public var name: String = Self.defaultName()

I don't think you have to write your Swift code "with the odd jump through a private instance method."


Instead you coud do more simply:

  public class var defaultName : String { return "Element" }
  public lazy var name : String = self.dynamicType.defaultName


or even:

  public class var defaultName : String { return "Element" }
  public var name : String { return self.dynamicType.defaultName }

Yes, that would work, but the discussion was about the nature of Self, so that's why I used that particular example.

Inheritance is ridiculous and I expect that it will be deprecated in Swift for non-"objc" types.

protocol ThingType {}
extension ThingType {
   static var name: String {return "ThingType"}
}
class Thing: ThingType {
   static var defaultName: String {return (Thing.self as ThingType.Type).name}
   static var name = "Thing"
}

What's the point of the extension ThingType {}, anyway? How are protocol extensions like that supposed to work? That has never made sense to me.

Check out my reply here:

https://forums.developer.apple.com/thread/17541


It's a theme of the modern world, where people are learning that people are not actually certain concrete types, but mixes of qualities. As Apple learns that there are more things than men and women of a single race or gender, so is Swift's type system motivated to adapt. There are of course other reasons, but I think it's pretty obvious that this was the main motivator.

As the title says: structs (not classes) ... so I repeat:

This is (at least the beginning of) a great example of why I'm staying away from classes, not to mention inheritance, as much as I possibly can in my code, and in (the topic of) this thread. : )

I think bob133 gave you the correct answer accidentally. 'Self' as the return type in a class is exactly what 'instancetype' is in Obj-C. It means a class determined by the call site, which may be a subclass of the class of the declaration site of the method. In fact, using the class name instead is semantically different from Self.


In structs, without any inheritance, the only possibility is the struct containing the declaration, so you can use the literal name of the type. OTOH, allowing 'Self' would seem to be harmless.


As far as protocols are concerned (and classes using Self conforming to protocols using Self), I was not able to find documentation on what it means, the last time I looked.

Why no Self within structs?
 
 
Q