[Draft] Introducing StaticSelf, an Invariant Self

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'

···

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'm not convinced by this example.

I think the problem to solve here is the interaction of protocols with
classes.
A related issue was illustrated by Tony Allevato here
The swift-evolution The Week Of Monday 2 May 2016 Archive by thread
/016294.html

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.

Nicola

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

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:

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 {

// ...

} }

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.

-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

I would prefer BaseSelf.

···

On May 13, 2016, at 2:28 AM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

via

That makes sense to me.

···

On May 13, 2016, at 2:45 AM, Patrick Smith via swift-evolution <swift-evolution@swift.org> wrote:

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.

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:

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
{

// ...

}
}

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:

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 {

// ...

} }

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.

-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

Sent from my iPad

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
{

// ...

}
}

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:

-Joe

That makes `StaticSelf` tricky to use in generic code. This would be invalid:

protocol Makable {
  static func make(value: Int) -> StaticSelf
}

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.

The recent discussion can be found here: http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565

The proposal can be found here: https://github.com/anandabits/swift-evolution/blob/static-self/proposals/NNNN-static-self.md

We look forward to continuing the discussion. We plan to submit a PR in the near future after incorporating your final feedback.

Thanks,
Matthew
Introducing StaticSelf, an Invariant Self

Proposal: TBD
Authors: Matthew Johnson, Erica Sadun
Status: TBD
Review manager: TBD
Introduction

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:

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.

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.

_______________________________________________
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

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:

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 {

// ...

} }

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.

-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

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() }
}

class B: A {
}

How would you use foo() in generic code?

func bar<T: Fooable>(_ x: T) -> X {
    return x.foo()
}

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:

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
{

// ...

}
}

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.

> 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'

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() }
}

class B: A {
}

How would you use foo() in generic code?

func bar<T: Fooable>(_ x: T) -> X {
    return x.foo()
}

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:

protocol StringCreatable {
    static func createWithString(s: String) -> StaticSelf
}

extension NSURL: StringCreatable {
    static func createWithString(s: String) -> StaticSelf {
        // ...
    }
}

func foo<Result: StringCreatable>(s: String) -> Result {
    return Result.createWithString(s: s)
}

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:

protocol StringCreatable {
    typealias ConformingType = StaticSelf
    static func createWithString(s: String) -> StaticSelf
}

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:

Nicola

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

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 recent discussion can be found
    here: http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565

    The proposal can be found
    here: https://github.com/anandabits/swift-evolution/blob/static-self/proposals/NNNN-static-self.md

    We look forward to continuing the discussion. We plan to submit a
    PR in the near future after incorporating your final feedback.

    Thanks,
    Matthew

      Introducing StaticSelf, an Invariant Self

      * Proposal: TBD
      * Authors: Matthew Johnson <https://github.com/anandabits&gt;, Erica
        Sadun <https://github.com/erica&gt;
      * Status: TBD
      * Review manager: TBD

        Introduction

    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
    <http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565&gt;/

        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
    <https://github.com/apple/swift-evolution/blob/master/proposals/0068-universal-self.md&gt;
    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.

    >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.

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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

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:

protocol Makable {
  static func make(value: Int) -> StaticSelf
}

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:

protocol Makable {
  typealias RootMakable = StaticSelf
  static func make(value: Int) -> StaticSelf
}

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:

-Joe

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..

something like(just pseudo code!):

func makeWithZero<T: Makable >(x: Int) -> Makable(T).FirstConformedClass {
  return T.make(value: 0)
}

or

func makeWithZero<T: Makable >(x: Int) -> type<T.make(value:)> {
  return T.make(value: 0)
}

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:

protocol Makable {
  static func make(value: Int) -> StaticSelf
}

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
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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 recent discussion can be found
   here: http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565

   The proposal can be found
   here: https://github.com/anandabits/swift-evolution/blob/static-self/proposals/NNNN-static-self.md

   We look forward to continuing the discussion. We plan to submit a
   PR in the near future after incorporating your final feedback.

   Thanks,
   Matthew

     Introducing StaticSelf, an Invariant Self

     * Proposal: TBD
     * Authors: Matthew Johnson <https://github.com/anandabits&gt;, Erica
       Sadun <https://github.com/erica&gt;
     * Status: TBD
     * Review manager: TBD

       Introduction

   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
   <http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565&gt;/

       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
   <https://github.com/apple/swift-evolution/blob/master/proposals/0068-universal-self.md&gt;
   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.

   >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.

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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

Matthew Johnson via swift-evolution <swift-evolution@...> writes:

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:

protocol Makable {

  typealias RootMakable = StaticSelf
  static func make(value: Int) -> StaticSelf
}

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.

You can do that today:

protocol Makable {
    associatedtype MadeType
    static func make(value: Int) -> MadeType
}

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?

Nicola

Matthew Johnson via swift-evolution <swift-evolution@...> writes:

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:

protocol Makable {

  typealias RootMakable = StaticSelf
  static func make(value: Int) -> StaticSelf
}

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.

You can do that today:

protocol Makable {
   associatedtype MadeType
   static func make(value: Int) -> MadeType
}

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:

protocol StringInitializable {
    static func initializeWith(string: String) -> StaticSelf
}

We just add an associatedtype defaulted to Self:

protocol StringInitializable {
    associatedtype Initialized = Self // where Self: Initialized
    static func initializeWith(string: String) -> Initialized
}

extension NSURL: StringInitializable {
    static func initializeWith(string: String) -> NSURL {
        return NSURL()
    }
}

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:

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

Hmm.. very interesting..

@Matthew, is the code below looks like the same as you wanted to achieve with `->StaticSelf` ?

protocol Makable {
     associatedtype MadeType
     func make(value: Int) -> MadeType
}

class A {

}

class B: A {
     func make(value: Int) -> B {
         return B()
     }
}

class C : B {
     override func make(value: Int) -> B {
         return C()
     }
}

extension B : Makable {
     typealias MadeType = B
}

func makeWithZero<T: Makable>(creator t: T) -> T.MadeType {
     return t.make(0)
}

var instance : B = C()

print(instance.make(0)) // main.C
print(makeWithZero(creator: instance)) // main.C

···

On 14.05.2016 8:55, Nicola Salmoria via swift-evolution wrote:

Matthew Johnson via swift-evolution <swift-evolution@...> writes:

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:

protocol Makable {

  typealias RootMakable = StaticSelf
  static func make(value: Int) -> StaticSelf
}

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.

You can do that today:

protocol Makable {
    associatedtype MadeType
    static func make(value: Int) -> MadeType
}

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?

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