Probably my & Matthew's previous discussion in `[swift-evolution] [RFC] #Self` topic will help you. I was trying there to find out (in primitive examples) what Matthew is trying to achive with this `->StaticSelf` in protocol.
In two words - he wants to achieve requirement 'return Self class or any of base classes', as current `->Self` requires 'strictly return Self class'
···
On 13.05.2016 12:46, Nicola Salmoria via swift-evolution wrote:
Matthew Johnson via swift-evolution <swift-evolution@...> writes:
Consider the following example, under the current system:
protocol StringCreatable {
static func createWithString(s: String) -> Self
}
extension NSURL: StringCreatable {
// cannot conform because NSURL is non-final
// error: method 'createWithString' in non-final class 'NSURL' must
return `Self` to conform to protocol 'A'
}Introducing a static, invariant version of Self permits the desired
conformance:
protocol StringCreatable {
static func createWithString(s: String) -> StaticSelf
}
I think that before attempting to solve this specific problem introducing a
new notation, the general design of the interaction between protocols and
class inheritance should be reviewed.
Could protocol Self change to just the first behaviour for classes?
If a conformance absolutely needs to have a method returning ‘only me but not my subclasses’, then it sets that conforming method to be final.
···
On 13 May 2016, at 4:38 PM, Vladimir.S <svabox@gmail.com> wrote:
The proposed StaticSelf when used as `->StaticSelf` in protocol means ‘myself or my some *base* class’. I.e. if this requirement was implemented in one of base classes, any subclass automatically conforms to the protocol as it has `->(myself or some base class)` in his hierarchy.
This is the difference with `->Self` in protocol which requires 'myself'.
On 13.05.2016 7:21, Patrick Smith via swift-evolution wrote:
I didn’t really understand some of the lead in discussion examples
regarding protocols A and B each being interwoven, but I would prefer to
see StaticSelf only used for concrete types, and protocols only to use
Self. If Self has problems with non-final classes, then maybe how it
works in protocols could change. A class could interpret a protocol’s
‘Self’ as ‘myself or my subclasses’?
Maybe instead of introducing StaticSelf it could be renamed simply Self,
and ‘Self’ as used in protocols could change to something else?
‘Instance’ perhaps?
On 13 May 2016, at 12:21 PM, Joe Groff via swift-evolution >>> <swift-evolution@swift.org> wrote:
On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution >>>> <swift-evolution@swift.org> wrote:
The invariant StaticSelf identifier will always refer to A, unlike
Self, which is covarying and refers to the type of the actual
instance. Since multiple inheritance for non-protocol types is
disallowed, this establishes this invariant type identifier with no
possibility for conflict.
Consider the following example, under the current system:
protocol StringCreatable {
static func createWithString(s: String) -> Self
}
extension NSURL: StringCreatable {
// cannot conform because NSURL is non-final
// error: method 'createWithString' in non-final class 'NSURL' must
return `Self` to conform to protocol 'A'
}
Introducing a static, invariant version of Self permits the desired
conformance:
As I've noted before, I don't think this makes sense to encode in the
protocol. `Self` is already effectively invariant within a protocol.
If a protocol doesn't have the foresight to use StaticSelf, then you
still have the same problems retroactively conforming class
hierarchies to the protocol. Whether a conformance is inherited or not
feels more natural as a property of a conformance, not something that
can be legislated a priori by a protocol definition.
Something like StaticSelf might still be useful as shorthand within a
class definition with a long-winded name, though `StaticSelf` feels
kind of long as a shortcut to me.
In this particular case, making conformances non-inheritable, under the conformer's control, would avoid the issue of the framework having to anticipate its users' needs.
-Joe
···
On May 13, 2016, at 9:06 AM, Matthew Johnson <matthew@anandabits.com> wrote:
On May 13, 2016, at 10:39 AM, Joe Groff <jgroff@apple.com> wrote:
On May 13, 2016, at 8:18 AM, Matthew Johnson <matthew@anandabits.com> wrote:
Sent from my iPad
On May 12, 2016, at 9:21 PM, Joe Groff <jgroff@apple.com> wrote:
On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:
The invariant StaticSelf identifier will always refer to A, unlike Self, which is covarying and refers to
the type of the actual instance. Since multiple inheritance for non-protocol types is disallowed,
this establishes this invariant type identifier with no possibility for conflict.
Consider the following example, under the current system:
protocol StringCreatable
{
static func createWithString(s: String) -> Self
}
extension NSURL: StringCreatable
{
// cannot conform because NSURL is non-final
// error: method 'createWithString' in non-final class 'NSURL' must return `Self` to conform to protocol 'A'
}
Introducing a static, invariant version of Self permits the desired conformance:
As I've noted before, I don't think this makes sense to encode in the protocol. `Self` is already effectively invariant within a protocol.
'Self' is not invariant when used as a return type so I'm not sure what you mean.
That's a property of a conformance. Class conformances are inherited, so they have to satisfy a protocol's requirements . Within the protocol definition, or in a protocol extension, `Self` is a generic parameter bound to a specific conforming type. When you conform a base class to a type, that means `Self == Base` and `Self == Derived` must be possible, but `Self` is never simultaneously `Base` and `Derived`.
If a protocol doesn't have the foresight to use StaticSelf, then you still have the same problems retroactively conforming class hierarchies to the protocol.
True, but in many use cases we are in control of the protocol. This has always been the case when I have personally encountered this problem.
That will likely change once resilient Swift frameworks start to exist. Changing `Self` to `StaticSelf` or back would also be a nonresilient change, so if frameworks get this wrong, they wouldn't be able to fix it without breaking ABI, which makes this even more problematic.
You can say this about many things. It seems less problematic than having no way to express this. Frameworks would not be required to use it if the authors have concerns about ABI.
Could protocol Self change to just the first behaviour for classes?
If a conformance absolutely needs to have a method returning ‘only me but not my subclasses’, then it sets that conforming method to be final.
It does not say the method returns “only me but not my subclasses”. It just says “subclasses are not *required* to return an instance of their own type, the original conforming type is sufficient to meet the requirement”.
This is quite a bit different from a ‘final’ requirement. Subclasses are allowed to override the implementation if desired. If they do choose to override the implementation they have more flexibility in *how* to implement it and what signature to expose. This is exactly the same as a method in Base that is declared as returning Base rather than returning Self.
···
On May 13, 2016, at 1:45 AM, Patrick Smith via swift-evolution <swift-evolution@swift.org> wrote:
On 13 May 2016, at 4:38 PM, Vladimir.S <svabox@gmail.com> wrote:
The proposed StaticSelf when used as `->StaticSelf` in protocol means ‘myself or my some *base* class’. I.e. if this requirement was implemented in one of base classes, any subclass automatically conforms to the protocol as it has `->(myself or some base class)` in his hierarchy.
This is the difference with `->Self` in protocol which requires 'myself'.
On 13.05.2016 7:21, Patrick Smith via swift-evolution wrote:
I didn’t really understand some of the lead in discussion examples
regarding protocols A and B each being interwoven, but I would prefer to
see StaticSelf only used for concrete types, and protocols only to use
Self. If Self has problems with non-final classes, then maybe how it
works in protocols could change. A class could interpret a protocol’s
‘Self’ as ‘myself or my subclasses’?
Maybe instead of introducing StaticSelf it could be renamed simply Self,
and ‘Self’ as used in protocols could change to something else?
‘Instance’ perhaps?
On 13 May 2016, at 12:21 PM, Joe Groff via swift-evolution >>>> <swift-evolution@swift.org> wrote:
On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution >>>>> <swift-evolution@swift.org> wrote:
The invariant StaticSelf identifier will always refer to A, unlike
Self, which is covarying and refers to the type of the actual
instance. Since multiple inheritance for non-protocol types is
disallowed, this establishes this invariant type identifier with no
possibility for conflict.
Consider the following example, under the current system:
protocol StringCreatable {
static func createWithString(s: String) -> Self
}
extension NSURL: StringCreatable {
// cannot conform because NSURL is non-final
// error: method 'createWithString' in non-final class 'NSURL' must
return `Self` to conform to protocol 'A'
}
Introducing a static, invariant version of Self permits the desired
conformance:
As I've noted before, I don't think this makes sense to encode in the
protocol. `Self` is already effectively invariant within a protocol.
If a protocol doesn't have the foresight to use StaticSelf, then you
still have the same problems retroactively conforming class
hierarchies to the protocol. Whether a conformance is inherited or not
feels more natural as a property of a conformance, not something that
can be legislated a priori by a protocol definition.
Something like StaticSelf might still be useful as shorthand within a
class definition with a long-winded name, though `StaticSelf` feels
kind of long as a shortcut to me.
The invariant StaticSelf identifier will always refer to A, unlike Self, which is covarying and refers to
the type of the actual instance. Since multiple inheritance for non-protocol types is disallowed,
this establishes this invariant type identifier with no possibility for conflict.
Consider the following example, under the current system:
protocol StringCreatable
{
static func createWithString(s: String) -> Self
}
extension NSURL: StringCreatable
{
// cannot conform because NSURL is non-final
// error: method 'createWithString' in non-final class 'NSURL' must return `Self` to conform to protocol 'A'
}
Introducing a static, invariant version of Self permits the desired conformance:
As I've noted before, I don't think this makes sense to encode in the protocol. `Self` is already effectively invariant within a protocol.
'Self' is not invariant when used as a return type so I'm not sure what you mean.
That's a property of a conformance. Class conformances are inherited, so they have to satisfy a protocol's requirements . Within the protocol definition, or in a protocol extension, `Self` is a generic parameter bound to a specific conforming type. When you conform a base class to a type, that means `Self == Base` and `Self == Derived` must be possible, but `Self` is never simultaneously `Base` and `Derived`.
If a protocol doesn't have the foresight to use StaticSelf, then you still have the same problems retroactively conforming class hierarchies to the protocol.
True, but in many use cases we are in control of the protocol. This has always been the case when I have personally encountered this problem.
That will likely change once resilient Swift frameworks start to exist. Changing `Self` to `StaticSelf` or back would also be a nonresilient change, so if frameworks get this wrong, they wouldn't be able to fix it without breaking ABI, which makes this even more problematic.
You can say this about many things. It seems less problematic than having no way to express this. Frameworks would not be required to use it if the authors have concerns about ABI.
In this particular case, making conformances non-inheritable, under the conformer's control, would avoid the issue of the framework having to anticipate its users' needs.
How would that work for class clusters? I may have an instance of a subclass but only know about the visible superclass. When the visible superclass conforms to a protocol I expect that the instance I have a reference to also conforms, regardless of its dynamic type.
···
Sent from my iPad
On May 13, 2016, at 11:08 AM, Joe Groff <jgroff@apple.com> wrote:
On May 13, 2016, at 9:06 AM, Matthew Johnson <matthew@anandabits.com> wrote:
On May 13, 2016, at 10:39 AM, Joe Groff <jgroff@apple.com> wrote:
On May 13, 2016, at 8:18 AM, Matthew Johnson <matthew@anandabits.com> wrote:
On May 12, 2016, at 9:21 PM, Joe Groff <jgroff@apple.com> wrote:
On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:
func makeWithZero<T: Fooable>(x: Int) -> T {
return T.make(value: 0) // ERROR: T.StaticSelf may be a supertype of T so isn't convertible to T
}
`StaticSelf` in this model is effectively an associated type of the protocol, with a `Self: StaticSelf` constraint (if that were supported).
-Joe
···
On May 13, 2016, at 9:06 AM, Matthew Johnson <matthew@anandabits.com> wrote:
On May 13, 2016, at 10:55 AM, Joe Groff <jgroff@apple.com> wrote:
On May 13, 2016, at 8:18 AM, Matthew Johnson <matthew@anandabits.com> wrote:
When I write a class Base with non-final methods that return instances of Base I can choose whether to state the return type as Self (covariant) or Base (invariant, under this proposal StaticSelf would also be an alternative way to state this). If I choose to specify Base as the return type derived classes *may* override the method but are not required to. Further, if they *do* override the method they are allowed to choose whether their implementation returns Base or Derived.
`StaticSelf` requirements by themselves don't even save you from covariance. If Base conforms to a protocol (with Self == Base), Derived inherits that conformance and also conforms (with Self == Derived). If `StaticSelf` always refers to the conforming type, then it must also be bindable to Base and Derived, so a base class must still use a covariant-returning method to satisfy the `StaticSelf` requirement.
We are specifying that `StaticSelf` refers to the type that explicitly declares conformance. If a class inherits conformance it refers to the base class which explicitly declared the conformance it is inheriting.
The other advantage of Self! over StaticSelf is that in code completion, Self, Self? Self! Will come together, giving people a quick tool to discover/remind themselves of the semantic difference right at the point of use.
It might also address Joe's comment about StaticSelf not being much of a shortcut.
···
On May 13, 2016, at 1:15 PM, LM <laurent.mihalkovic@gmail.com> wrote:
Considering the precedent of using ! and ? in swift, could it be that:
Self! would designate what is known for sure, the invariant compile time type of self
Self? Would designate the yet unknown (*optional* if you will) covariant type of self
Regards
LM
(From mobile)
On May 13, 2016, at 3:59 AM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:
I like the way the motivation for this feature has been explained here. Now that the reasoning behind it is evident, I have to say I'm leaning towards the "InvariantSelf" name--after all, you describe this feature in the title as "an invariant self."
On Thu, May 12, 2016 at 7:49 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:
Erica Sadun and I have written a proposal are following up the recent discussion thread "[RFC] self” with a proposal to introduce StaticSelf, an invariant Self.
This proposal introduces a new keyword that provides consistent invariant type semantics in all contexts.
The Swift-evolution thread about this topic can be found here: [RFC] self
Motivation
The distinction between covariant and non-covariant type references come into play when
conforming non-final classes to protocols. Fixing a protocol requirement to a covarying type
means that a method returning Self must be overriden by all subclasses in order to return
the correct, matching type.
This proposal builds on the covariant construct Self accepted in SE–0068
to introduce an invariant type identifier. It enables protocol declarations to consistently
refer to a type that is fixed at compile time. This ensures that subclasses can inherit
protocol implementations without having to re-implement that code at each level of
inheritance.
Under this proposal, a new identifier keyword is fixed in use at the point of protocol conformance
to the static type of that construct.
class A: MyProtocol
The invariant StaticSelf identifier will always refer to A, unlike Self, which is covarying and refers to
the type of the actual instance. Since multiple inheritance for non-protocol types is disallowed,
this establishes this invariant type identifier with no possibility for conflict.
Consider the following example, under the current system:
extension NSURL: StringCreatable {
// cannot conform because NSURL is non-final
// error: method 'createWithString' in non-final class 'NSURL' must return `Self` to conform to protocol 'A'
}
Introducing a static, invariant version of Self permits the desired conformance:
extension NSURL: StringCreatable {
// can now conform conform because NSURL is fixed and matches the static
// type of the conforming construct. Subclasses need not re-implement
// NOTE: the return type can be declared as StaticSelf *or* as NSURL
// they are interchangeable
static func createWithString(s: String) -> StaticSelf {
// ...
}
}
Additional Utility
The utility of StaticSelf is not limited to protocols. A secondary use enables code to refer to the lexical context’s current type without explicitly mentioning its name. This provides a useful shortcut when referencing static type members with especially long names and when re-purposing code between types.
class StructWithAVeryLongName {
static func foo() -> String {
// ...
}
func bar() {
// ...
let s = StaticSelf.foo()
//
}
}
Detailed Design
This proposal introduces StaticSelf, a new keyword that may be used in protocols to refer to the invariant static type of a conforming construct. StaticSelf may also be used in the lexical context of any type declaration. In such use, the keyword is identical to spelling out the full name of that type.
Impact on existing code
Being additive, there should be no impact on existing code.
Alternatives considered
The keyword is not fixed at this time. Alternatives that have been discussed include StaticType, InvariantSelf, SelfType, or Type. The community is welcome to bikeshed on the most clear and concise name for this keyword.
Could protocol Self change to just the first behaviour for classes?
If a conformance absolutely needs to have a method returning ‘only me but not my subclasses’, then it sets that conforming method to be final.
Hm.. Do we *need* to change `->Self` behavior? It actually depends on what such requirement will mean for classes. Right now it is '->return instance of self class'. If we all agree that it should means '->return instance of self class or of any base class' - then we obviously can require such a change.
···
On 13.05.2016 9:45, Patrick Smith wrote:
On 13 May 2016, at 4:38 PM, Vladimir.S <svabox@gmail.com> wrote:
The proposed StaticSelf when used as `->StaticSelf` in protocol means ‘myself or my some *base* class’. I.e. if this requirement was implemented in one of base classes, any subclass automatically conforms to the protocol as it has `->(myself or some base class)` in his hierarchy.
This is the difference with `->Self` in protocol which requires 'myself'.
On 13.05.2016 7:21, Patrick Smith via swift-evolution wrote:
I didn’t really understand some of the lead in discussion examples
regarding protocols A and B each being interwoven, but I would prefer to
see StaticSelf only used for concrete types, and protocols only to use
Self. If Self has problems with non-final classes, then maybe how it
works in protocols could change. A class could interpret a protocol’s
‘Self’ as ‘myself or my subclasses’?
Maybe instead of introducing StaticSelf it could be renamed simply Self,
and ‘Self’ as used in protocols could change to something else?
‘Instance’ perhaps?
On 13 May 2016, at 12:21 PM, Joe Groff via swift-evolution >>>> <swift-evolution@swift.org> wrote:
On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution >>>>> <swift-evolution@swift.org> wrote:
The invariant StaticSelf identifier will always refer to A, unlike
Self, which is covarying and refers to the type of the actual
instance. Since multiple inheritance for non-protocol types is
disallowed, this establishes this invariant type identifier with no
possibility for conflict.
Consider the following example, under the current system:
protocol StringCreatable {
static func createWithString(s: String) -> Self
}
extension NSURL: StringCreatable {
// cannot conform because NSURL is non-final
// error: method 'createWithString' in non-final class 'NSURL' must
return `Self` to conform to protocol 'A'
}
Introducing a static, invariant version of Self permits the desired
conformance:
As I've noted before, I don't think this makes sense to encode in the
protocol. `Self` is already effectively invariant within a protocol.
If a protocol doesn't have the foresight to use StaticSelf, then you
still have the same problems retroactively conforming class
hierarchies to the protocol. Whether a conformance is inherited or not
feels more natural as a property of a conformance, not something that
can be legislated a priori by a protocol definition.
Something like StaticSelf might still be useful as shorthand within a
class definition with a long-winded name, though `StaticSelf` feels
kind of long as a shortcut to me.
What does bar() return? What do you put in place of X in its declaration?
You can't use T, you can't use T.StaticSelf. So what's the purpose of
having a protocol if you can't use it in generic code?
Nicola
···
On Fri, May 13, 2016 at 12:55 PM, Vladimir.S <svabox@gmail.com> wrote:
> I'm not convinced by this example.
Probably my & Matthew's previous discussion in `[swift-evolution] [RFC]
#Self` topic will help you. I was trying there to find out (in primitive
examples) what Matthew is trying to achive with this `->StaticSelf` in
protocol.
In two words - he wants to achieve requirement 'return Self class or any
of base classes', as current `->Self` requires 'strictly return Self class'
In most cases, the subtype conversion should still kick in, so that we can convert ImplSubclass to VisibleSuperclass and invoke a generic with T == VisibleSuperclass instead of with T == ImplSubclass. There might be problems if the ImplSubclass appeared structurally in an invariant position, where implicit conversion is rare, but for situations where you want invariant protocol conformances, such as class clusters, it's rare to work to specific implementation classes directly, since the visible superclass is the primary API interface.
-Joe
···
On May 13, 2016, at 9:22 AM, Matthew Johnson <matthew@anandabits.com> wrote:
Sent from my iPad
On May 13, 2016, at 11:08 AM, Joe Groff <jgroff@apple.com> wrote:
On May 13, 2016, at 9:06 AM, Matthew Johnson <matthew@anandabits.com> wrote:
On May 13, 2016, at 10:39 AM, Joe Groff <jgroff@apple.com> wrote:
On May 13, 2016, at 8:18 AM, Matthew Johnson <matthew@anandabits.com> wrote:
Sent from my iPad
On May 12, 2016, at 9:21 PM, Joe Groff <jgroff@apple.com> wrote:
On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:
The invariant StaticSelf identifier will always refer to A, unlike Self, which is covarying and refers to
the type of the actual instance. Since multiple inheritance for non-protocol types is disallowed,
this establishes this invariant type identifier with no possibility for conflict.
Consider the following example, under the current system:
protocol StringCreatable
{
static func createWithString(s: String) -> Self
}
extension NSURL: StringCreatable
{
// cannot conform because NSURL is non-final
// error: method 'createWithString' in non-final class 'NSURL' must return `Self` to conform to protocol 'A'
}
Introducing a static, invariant version of Self permits the desired conformance:
As I've noted before, I don't think this makes sense to encode in the protocol. `Self` is already effectively invariant within a protocol.
'Self' is not invariant when used as a return type so I'm not sure what you mean.
That's a property of a conformance. Class conformances are inherited, so they have to satisfy a protocol's requirements . Within the protocol definition, or in a protocol extension, `Self` is a generic parameter bound to a specific conforming type. When you conform a base class to a type, that means `Self == Base` and `Self == Derived` must be possible, but `Self` is never simultaneously `Base` and `Derived`.
If a protocol doesn't have the foresight to use StaticSelf, then you still have the same problems retroactively conforming class hierarchies to the protocol.
True, but in many use cases we are in control of the protocol. This has always been the case when I have personally encountered this problem.
That will likely change once resilient Swift frameworks start to exist. Changing `Self` to `StaticSelf` or back would also be a nonresilient change, so if frameworks get this wrong, they wouldn't be able to fix it without breaking ABI, which makes this even more problematic.
You can say this about many things. It seems less problematic than having no way to express this. Frameworks would not be required to use it if the authors have concerns about ABI.
In this particular case, making conformances non-inheritable, under the conformer's control, would avoid the issue of the framework having to anticipate its users' needs.
How would that work for class clusters? I may have an instance of a subclass but only know about the visible superclass. When the visible superclass conforms to a protocol I expect that the instance I have a reference to also conforms, regardless of its dynamic type.
Probably my & Matthew's previous discussion in `[swift-evolution] [RFC] #Self` topic will help you. I was trying there to find out (in primitive examples) what Matthew is trying to achive with this `->StaticSelf` in protocol.
In two words - he wants to achieve requirement 'return Self class or any of base classes', as current `->Self` requires 'strictly return Self class'
I think I understand what the request is, but I'm not sure if it's a problem worth solving, and if this would be the right solution.
Going back to the example, let's say you have the requested
protocol Fooable {
func foo() -> StaticSelf
}
class A: Fooable {
func foo() -> A { return A() }
}
What does bar() return? What do you put in place of X in its declaration?
You can't use T, you can't use T.StaticSelf. So what's the purpose of having a protocol if you can't use it in generic code?
This is a good question. Thank you very much for providing a concrete example along with the question.
Let’s look at an example of what some of us have in mind:
Obviously this will not work properly because we are not guaranteed that `createWithString` returns Result (that is only possible if the return type is Self). We would have to do the following:
func foo<Result: StringCreatable where Result.ConformingType == Result>(s: String) -> Result {
return Result.createWithString(s: s)
}
This requires same type constraints. I believe that is coming as part of “completing generics”.
However, it also raises a question: if the conformance afforded to subclasses can’t actually be used in a useful manner they probably shouldn’t have that conformance in the first place. If the conformance isn’t inherited then we don’t need StaticSelf at all (we can just use Self and still conform the visible class of a class cluster). This is the point Joe has been making all along. Working through the example has helped me understand this point of view better.
I wonder if anyone has any other examples where subclass conformance would actually be useful. If so, please share. Those who are supporting this proposal: how do you envision using StaticSelf in your code? What are some examples where you have had trouble due to the current limitations of the language?
-Matthew
···
On May 13, 2016, at 1:11 PM, Nicola Salmoria via swift-evolution <swift-evolution@swift.org> wrote:
On Fri, May 13, 2016 at 12:55 PM, Vladimir.S <svabox@gmail.com <mailto:svabox@gmail.com>> wrote:
I don't understand.
Right now we are allowed to have Optional(Self) :
protocol A {
func g()->Self?
}
class B: A {
func g()->Self? {return self}
}
print(B().g()) //Optional(main.B)
How do you want to divide your `->Self?` and this currently possible `->Self?` ?
But I do like the idea to separate meaning of `Self` in protocol with some marker.. What about `->?Self` and `->!Self` - no confusing with Optional<>
···
On 13.05.2016 14:21, LM via swift-evolution wrote:
The other advantage of Self! over StaticSelf is that in code completion,
Self, Self? Self! Will come together, giving people a quick tool to
discover/remind themselves of the semantic difference right at the point of
use.
It might also address Joe's comment about StaticSelf not being much of a
shortcut.
On May 13, 2016, at 1:15 PM, LM <laurent.mihalkovic@gmail.com > <mailto:laurent.mihalkovic@gmail.com>> wrote:
Considering the precedent of using ! and ? in swift, could it be that:
Self! would designate what is known for sure, the invariant compile time
type of self
Self? Would designate the yet unknown (*optional* if you will) covariant
type of self
Regards
LM
(From mobile)
On May 13, 2016, at 3:59 AM, Xiaodi Wu via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I like the way the motivation for this feature has been explained here.
Now that the reasoning behind it is evident, I have to say I'm leaning
towards the "InvariantSelf" name--after all, you describe this feature
in the title as "an invariant self."
On Thu, May 12, 2016 at 7:49 PM, Matthew Johnson via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Erica Sadun and I have written a proposal are following up the
recent discussion thread "[RFC] self” with a proposal to introduce
StaticSelf, an invariant Self.
The distinction between covariant and non-covariant type references
come into play when
conforming non-final classes to protocols. Fixing a protocol
requirement to a covarying type
means that a method returning |Self| must be overriden by all
subclasses in order to return
the correct, matching type.
This proposal builds on the covariant construct |Self| accepted
in SE–0068
<https://github.com/apple/swift-evolution/blob/master/proposals/0068-universal-self.md>
to introduce an invariant type identifier. It enables protocol
declarations to consistently
refer to a type that is fixed at compile time. This ensures that
subclasses can inherit
protocol implementations without having to re-implement that code at
each level of
inheritance.
Under this proposal, a new identifier keyword is fixed in use /at
the point of protocol conformance/
to the static type of that construct.
>class A: MyProtocol|
The invariant |StaticSelf| identifier will always refer to |A|,
unlike |Self|, which is covarying and refers to
the type of the actual instance. Since multiple inheritance for
non-protocol types is disallowed,
this establishes this invariant type identifier with no possibility
for conflict.
Consider the following example, under the current system:
>protocol StringCreatable { static func createWithString(s: String)
-> Self } extension NSURL: StringCreatable { // cannot conform
because NSURL is non-final // error: method 'createWithString' in
non-final class 'NSURL' must return `Self` to conform to protocol 'A' }|
Introducing a static, invariant version of |Self| permits the
desired conformance:
>protocol StringCreatable { static func createWithString(s: String)
-> StaticSelf } extension NSURL: StringCreatable { // can now
conform conform because NSURL is fixed and matches the static //
type of the conforming construct. Subclasses need not re-implement
// NOTE: the return type can be declared as StaticSelf *or* as NSURL
// they are interchangeable static func createWithString(s: String)
-> StaticSelf { // ... } }|
Additional Utility
The utility of |StaticSelf| is not limited to protocols. A secondary
use enables code to refer to the lexical context’s current type
without explicitly mentioning its name. This provides a useful
shortcut when referencing static type members with especially long
names and when re-purposing code between types.
This proposal introduces |StaticSelf|, a new keyword that may be
used in protocols to refer to the invariant static type of a
conforming construct. |StaticSelf| may also be used in the lexical
context of any type declaration. In such use, the keyword is
identical to spelling out the full name of that type.
Impact on existing code
Being additive, there should be no impact on existing code.
Alternatives considered
The keyword is not fixed at this time. Alternatives that have been
discussed include |StaticType|, |InvariantSelf|, |SelfType|,
or |Type|. The community is welcome to bikeshed on the most clear
and concise name for this keyword.
When I write a class Base with non-final methods that return instances of Base I can choose whether to state the return type as Self (covariant) or Base (invariant, under this proposal StaticSelf would also be an alternative way to state this). If I choose to specify Base as the return type derived classes *may* override the method but are not required to. Further, if they *do* override the method they are allowed to choose whether their implementation returns Base or Derived.
`StaticSelf` requirements by themselves don't even save you from covariance. If Base conforms to a protocol (with Self == Base), Derived inherits that conformance and also conforms (with Self == Derived). If `StaticSelf` always refers to the conforming type, then it must also be bindable to Base and Derived, so a base class must still use a covariant-returning method to satisfy the `StaticSelf` requirement.
We are specifying that `StaticSelf` refers to the type that explicitly declares conformance. If a class inherits conformance it refers to the base class which explicitly declared the conformance it is inheriting.
That makes `StaticSelf` tricky to use in generic code. This would be invalid:
func makeWithZero<T: Fooable>(x: Int) -> T {
return T.make(value: 0) // ERROR: T.StaticSelf may be a supertype of T so isn't convertible to T
}
I agree it’s a bit tricky. But that’s better than not possible at all. You just need a typealias and a same type constraint to make this work as expected / desired:
func makeWithZero<T: Makable where T == T.RootMakable>(x: Int) -> T {
return T.make(value: 0) // works now
}
Now that we have a typealias we can refer to the binding of StaticSelf and constrain it as necessary for whatever purpose we have in mind. In some cases that will be a same type constraint so that our code works properly with class clusters. I don’t have concrete examples of other use cases but can imagine use cases constraining the typealias to a protocol, for example.
If we had control over inheritance of conformance at the point of conformance we probably wouldn’t be talking about StaticSelf. But we don’t and this is a problem that has caused enough people trouble that it is worth solving. StaticSelf does that in a general way that is also as a shorthand in types themselves and has consistent semantics in both use cases.
IIRC the design of point-of-conformance control over inheritance of conformance is pretty thorny. I wouldn’t mind seeing that feature eventually but don’t have any confidence that it will come soon.
`StaticSelf` in this model is effectively an associated type of the protocol, with a `Self: StaticSelf` constraint (if that were supported).
If you add that the associated type is automatically bound with the initial conformance (and cannot be modified by subclass conformances) then yes, you can look at it this way.
···
On May 13, 2016, at 3:12 PM, Joe Groff <jgroff@apple.com> wrote:
On May 13, 2016, at 9:06 AM, Matthew Johnson <matthew@anandabits.com> wrote:
On May 13, 2016, at 10:55 AM, Joe Groff <jgroff@apple.com> wrote:
On May 13, 2016, at 8:18 AM, Matthew Johnson <matthew@anandabits.com> wrote:
Seems like ->StaticSelf can actually only means returns the class for which protocol conformance was applied first(in hierarchy). I.e. some `->BaseSelf`.
But in this case we need a method to get this 'base' class from protocol..
I don't know if all of this makes sense at all ;-)
···
On 13.05.2016 23:12, Joe Groff via swift-evolution wrote:
On May 13, 2016, at 9:06 AM, Matthew Johnson <matthew@anandabits.com> wrote:
On May 13, 2016, at 10:55 AM, Joe Groff <jgroff@apple.com> wrote:
On May 13, 2016, at 8:18 AM, Matthew Johnson <matthew@anandabits.com> wrote:
When I write a class Base with non-final methods that return instances of Base I can choose whether to state the return type as Self (covariant) or Base (invariant, under this proposal StaticSelf would also be an alternative way to state this). If I choose to specify Base as the return type derived classes *may* override the method but are not required to. Further, if they *do* override the method they are allowed to choose whether their implementation returns Base or Derived.
`StaticSelf` requirements by themselves don't even save you from covariance. If Base conforms to a protocol (with Self == Base), Derived inherits that conformance and also conforms (with Self == Derived). If `StaticSelf` always refers to the conforming type, then it must also be bindable to Base and Derived, so a base class must still use a covariant-returning method to satisfy the `StaticSelf` requirement.
We are specifying that `StaticSelf` refers to the type that explicitly declares conformance. If a class inherits conformance it refers to the base class which explicitly declared the conformance it is inheriting.
That makes `StaticSelf` tricky to use in generic code. This would be invalid:
I don't understand.
Right now we are allowed to have Optional(Self) :
protocol A {
func g()->Self?
}
class B: A {
func g()->Self? {return self}
}
print(B().g()) //Optional(main.B)
How do you want to divide your `->Self?` and this currently possible `->Self?` ?
But I do like the idea to separate meaning of `Self` in protocol with some marker.. What about `->?Self` and `->!Self` - no confusing with Optional<>
My idea was to keep the markers at the end, rather than as a prefix (Lexer will thank you for it), such that in code completion they would be together, but your idea has some appeal.
Especially if the argument is made that the IDE should be smart enough to 'cleanup' the list meaningfully, which I would expect coming from a decade of java as I do (at the risk of sounding critical, I am still rather put-off by the crude state of text editing in the obj-c/swift world). Although in fairness, mike & team have done marvels these last couple years.
···
On May 13, 2016, at 1:26 PM, Vladimir.S <svabox@gmail.com> wrote:
On 13.05.2016 14:21, LM via swift-evolution wrote:
The other advantage of Self! over StaticSelf is that in code completion,
Self, Self? Self! Will come together, giving people a quick tool to
discover/remind themselves of the semantic difference right at the point of
use.
It might also address Joe's comment about StaticSelf not being much of a
shortcut.
On May 13, 2016, at 1:15 PM, LM <laurent.mihalkovic@gmail.com >> <mailto:laurent.mihalkovic@gmail.com>> wrote:
Considering the precedent of using ! and ? in swift, could it be that:
Self! would designate what is known for sure, the invariant compile time
type of self
Self? Would designate the yet unknown (*optional* if you will) covariant
type of self
Regards
LM
(From mobile)
On May 13, 2016, at 3:59 AM, Xiaodi Wu via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I like the way the motivation for this feature has been explained here.
Now that the reasoning behind it is evident, I have to say I'm leaning
towards the "InvariantSelf" name--after all, you describe this feature
in the title as "an invariant self."
On Thu, May 12, 2016 at 7:49 PM, Matthew Johnson via swift-evolution >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Erica Sadun and I have written a proposal are following up the
recent discussion thread "[RFC] self” with a proposal to introduce
StaticSelf, an invariant Self.
The distinction between covariant and non-covariant type references
come into play when
conforming non-final classes to protocols. Fixing a protocol
requirement to a covarying type
means that a method returning |Self| must be overriden by all
subclasses in order to return
the correct, matching type.
This proposal builds on the covariant construct |Self| accepted
in SE–0068
<https://github.com/apple/swift-evolution/blob/master/proposals/0068-universal-self.md>
to introduce an invariant type identifier. It enables protocol
declarations to consistently
refer to a type that is fixed at compile time. This ensures that
subclasses can inherit
protocol implementations without having to re-implement that code at
each level of
inheritance.
Under this proposal, a new identifier keyword is fixed in use /at
the point of protocol conformance/
to the static type of that construct.
>class A: MyProtocol|
The invariant |StaticSelf| identifier will always refer to |A|,
unlike |Self|, which is covarying and refers to
the type of the actual instance. Since multiple inheritance for
non-protocol types is disallowed,
this establishes this invariant type identifier with no possibility
for conflict.
Consider the following example, under the current system:
>protocol StringCreatable { static func createWithString(s: String)
-> Self } extension NSURL: StringCreatable { // cannot conform
because NSURL is non-final // error: method 'createWithString' in
non-final class 'NSURL' must return `Self` to conform to protocol 'A' }|
Introducing a static, invariant version of |Self| permits the
desired conformance:
>protocol StringCreatable { static func createWithString(s: String)
-> StaticSelf } extension NSURL: StringCreatable { // can now
conform conform because NSURL is fixed and matches the static //
type of the conforming construct. Subclasses need not re-implement
// NOTE: the return type can be declared as StaticSelf *or* as NSURL
// they are interchangeable static func createWithString(s: String)
-> StaticSelf { // ... } }|
Additional Utility
The utility of |StaticSelf| is not limited to protocols. A secondary
use enables code to refer to the lexical context’s current type
without explicitly mentioning its name. This provides a useful
shortcut when referencing static type members with especially long
names and when re-purposing code between types.
This proposal introduces |StaticSelf|, a new keyword that may be
used in protocols to refer to the invariant static type of a
conforming construct. |StaticSelf| may also be used in the lexical
context of any type declaration. In such use, the keyword is
identical to spelling out the full name of that type.
Impact on existing code
Being additive, there should be no impact on existing code.
Alternatives considered
The keyword is not fixed at this time. Alternatives that have been
discussed include |StaticType|, |InvariantSelf|, |SelfType|,
or |Type|. The community is welcome to bikeshed on the most clear
and concise name for this keyword.
func makeWithZero<T: Makable where T == T.RootMakable>(x: Int) -> T {
return T.make(value: 0) // works now
}
Now that we have a typealias we can refer to the binding of StaticSelf and
constrain it as necessary for whatever purpose we have in mind. In some
cases that will be a same type constraint so that our code works properly
with class clusters. I don’t have concrete examples of other use cases but
can imagine use cases constraining the typealias to a protocol, for example.
func makeWithZero<T: Makable where T == T.MadeType>(x: Int) -> T {
return T.make(value: 0)
}
You can't currently constrain MadeType to be the same as the conforming
type, but, does it matter? What kind of extra guarantees would that give,
since you need to add the extra constraint anyway in generic code?
func makeWithZero<T: Makable where T == T.RootMakable>(x: Int) -> T {
return T.make(value: 0) // works now
}
Now that we have a typealias we can refer to the binding of StaticSelf and
constrain it as necessary for whatever purpose we have in mind. In some
cases that will be a same type constraint so that our code works properly
with class clusters. I don’t have concrete examples of other use cases but
can imagine use cases constraining the typealias to a protocol, for example.
func makeWithZero<T: Makable where T == T.MadeType>(x: Int) -> T {
return T.make(value: 0)
}
You can't currently constrain MadeType to be the same as the conforming
type, but, does it matter? What kind of extra guarantees would that give,
since you need to add the extra constraint anyway in generic code?
Wow, this is pretty cool. Thank you very much for pointing this out Nicola!
I haven’t seen this approach to solving the problem. Given the amount of discussion this problem has received I am surprised nobody has shared this solution yet. I just checked in Xcode 7.3 and it works there. It isn’t dependent on any pre-release features.
Instead of using StaticSelf under the current proposal:
func makeWith<T: StringInitializable where T == T.Initialized>(string: String) -> T {
return T.initializeWith(string: string)
}
There are two minor downsides to this approach:
1. You can’t copy and paste the method signature.
2. You can theoretically conform a type completely unrelated to `Initialized` to the protocol, thus violating the semantics.
I think we can live with these downsides. Maybe the `Self: Initialized` will be possible someday. That would be pretty close to StaticSelf. The only difference would be that subclasses still have flexibility to override with their own type.
Now that a reasonable way to do this with existing language features has been identified I will withdraw this proposal. If this approach doesn’t address use cases others have in mind for StaticSelf please speak up!
Doug, if you’re reading this, does the `where Self: Initialized` (i.e. arbitrary subclass constraints) fall into the scope of your “completing generics” manifesto? This is a concrete use case that would utilize subclass constraints.
-Matthew
···
On May 14, 2016, at 12:55 AM, Nicola Salmoria via swift-evolution <swift-evolution@swift.org> wrote:
func makeWithZero<T: Makable where T == T.RootMakable>(x: Int) -> T {
return T.make(value: 0) // works now
}
Now that we have a typealias we can refer to the binding of StaticSelf and
constrain it as necessary for whatever purpose we have in mind. In some
cases that will be a same type constraint so that our code works properly
with class clusters. I don’t have concrete examples of other use cases but
can imagine use cases constraining the typealias to a protocol, for example.
func makeWithZero<T: Makable where T == T.MadeType>(x: Int) -> T {
return T.make(value: 0)
}
You can't currently constrain MadeType to be the same as the conforming
type, but, does it matter? What kind of extra guarantees would that give,
since you need to add the extra constraint anyway in generic code?