PITCH: Return a subclass for a protocol method without the need for an associatedtype


(Sitton, Yogev) #1

Hi,

I raised this issue a few months back and discussion has died out since.
I’m raising this again to see if there are any objections before I submit a proposal.

I have a class that conforms to a protocol which declares a method with a specific return type.
In case I want to return a subclass of the return type I am forced to use anassociatedtype.
This feels like a hack.

Example:

// The protocol
protocol MyShapeProtocol {
// returns Shape
func make() -> Shape?
}

// Circle inherits from Shape
class Circle : Shape {}

// CircleMaker conforms to the MyShapeProtocol
class CircleMaker : MyShapeProtocol {
// CircleMaker wants to return Circle which is a type of Shape
func make() ->Circle? {
return Circle()
}
}

This will not work.
For that to work I’ll need to use toe associatedtype “hack”:

Example:
protocol MyShapeProtocol {
associatedtype ShapeReturnType : Shape
func make() -> ShapeReturnType?
}

class Circle : Shape {}

class CircleMaker : MyShapeProtocol{
func make() ->Circle? {
return Circle()
}
}

What I’m suggesting is to allow to return a subclass for a protocol method without the need for an associatedtype.

Any reason why not?


(Vladimir) #2

Although I see your point, and probably support, nothing prevents you from actually return Circle from make() but have return type defined as Shape.

Actually you can even have both Shape and Circle returning make() if you fill this will be handy for you:

class Shape {}

// The protocol
protocol MyShapeProtocol {
// returns Shape
func make() -> Shape?
}

// Circle inherits from Shape
class Circle : Shape {}

// CircleMaker conforms to the MyShapeProtocol
class CircleMaker : MyShapeProtocol {
// CircleMaker wants to return Circle which is a type of Shape
func make()->Shape? {
     return make() as Circle?
}

func make()->Circle? {
   return Circle()
}

var cm = CircleMaker()
var x : Circle? = cm.make()
print(type(of: x)) // Optional<Circle>

var p = cm as MyShapeProtocol
print(type(of: p.make())) // Optional<Shape>

But yes, strictly speaking 'make()->Circle?' conforms to protocol requirement 'make()->Shape?', it does returns 'Shape?', so I believe this should be treated as conformance to MyShapeProtocol protocol.

···

On 17.08.2016 10:09, Sitton, Yogev via swift-evolution wrote:

Hi,

I raised this issue a few months back and discussion has died out since.
I’m raising this again to see if there are any objections before I submit a
proposal.

I have a class that conforms to a protocol which declares a method with a
specific return type.
In case I want to return a subclass of the return type I am forced to use
anassociatedtype.
This feels like a hack.

*Example:*

// The protocol
protocol MyShapeProtocol {
// returns Shape
func make() -> Shape?
}

// Circle inherits from Shape
class Circle : Shape {}

// CircleMaker conforms to the MyShapeProtocol
class CircleMaker : MyShapeProtocol {
// CircleMaker wants to return Circle which is a type of Shape
func make() ->Circle? {
return Circle()
}

This will not work.
For that to work I’ll need to use toe associatedtype “hack”:

*Example:*
protocol MyShapeProtocol {
associatedtype ShapeReturnType : Shape
func make() -> ShapeReturnType?
}

class Circle : Shape {}

class CircleMaker : MyShapeProtocol{
func make() ->Circle? {
return Circle()
}

What I’m suggesting is to allow to return a subclass for a protocol method
without the need for an associatedtype.

Any reason why not?

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


(Slava Pestov) #3

But yes, strictly speaking 'make()->Circle?' conforms to protocol requirement 'make()->Shape?', it does returns 'Shape?', so I believe this should be treated as conformance to MyShapeProtocol protocol.

I agree this should be made to work, especially since method overriding supports the exact same scenario.

We have two sets of rules, implemented in two different places, for matching method overrides and protocol witnesses. We need to unify the rules and the code.

Slava

···

On Aug 17, 2016, at 10:18 AM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

On 17.08.2016 10:09, Sitton, Yogev via swift-evolution wrote:

Hi,

I raised this issue a few months back and discussion has died out since.
I’m raising this again to see if there are any objections before I submit a
proposal.

I have a class that conforms to a protocol which declares a method with a
specific return type.
In case I want to return a subclass of the return type I am forced to use
anassociatedtype.
This feels like a hack.

*Example:*

// The protocol
protocol MyShapeProtocol {
// returns Shape
func make() -> Shape?
}

// Circle inherits from Shape
class Circle : Shape {}

// CircleMaker conforms to the MyShapeProtocol
class CircleMaker : MyShapeProtocol {
// CircleMaker wants to return Circle which is a type of Shape
func make() ->Circle? {
return Circle()
}
}

This will not work.
For that to work I’ll need to use toe associatedtype “hack”:

*Example:*
protocol MyShapeProtocol {
associatedtype ShapeReturnType : Shape
func make() -> ShapeReturnType?
}

class Circle : Shape {}

class CircleMaker : MyShapeProtocol{
func make() ->Circle? {
return Circle()
}
}

What I’m suggesting is to allow to return a subclass for a protocol method
without the need for an associatedtype.

Any reason why not?

_______________________________________________
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


(Sitton, Yogev) #4

That’s was my point.
Two sets of rules for the same case in two different places.
These should be unified.

I’ll write the proposal and create a pull request.

···

On Aug 17, 2016, at 11:24 PM, Slava Pestov <spestov@apple.com<mailto:spestov@apple.com>> wrote:

On Aug 17, 2016, at 10:18 AM, Vladimir.S via swift-evolution <swift-evolution@swift.org<mailto:swift-evolution@swift.org>> wrote:

But yes, strictly speaking 'make()->Circle?' conforms to protocol requirement 'make()->Shape?', it does returns 'Shape?', so I believe this should be treated as conformance to MyShapeProtocol protocol.

I agree this should be made to work, especially since method overriding supports the exact same scenario.

We have two sets of rules, implemented in two different places, for matching method overrides and protocol witnesses. We need to unify the rules and the code.

Slava

On 17.08.2016 10:09, Sitton, Yogev via swift-evolution wrote:
Hi,

I raised this issue a few months back and discussion has died out since.
I’m raising this again to see if there are any objections before I submit a
proposal.

I have a class that conforms to a protocol which declares a method with a
specific return type.
In case I want to return a subclass of the return type I am forced to use
anassociatedtype.
This feels like a hack.

*Example:*

// The protocol
protocol MyShapeProtocol {
// returns Shape
func make() -> Shape?
}

// Circle inherits from Shape
class Circle : Shape {}

// CircleMaker conforms to the MyShapeProtocol
class CircleMaker : MyShapeProtocol {
// CircleMaker wants to return Circle which is a type of Shape
func make() ->Circle? {
return Circle()
}
}

This will not work.
For that to work I’ll need to use toe associatedtype “hack”:

*Example:*
protocol MyShapeProtocol {
associatedtype ShapeReturnType : Shape
func make() -> ShapeReturnType?
}

class Circle : Shape {}

class CircleMaker : MyShapeProtocol{
func make() ->Circle? {
return Circle()
}
}

What I’m suggesting is to allow to return a subclass for a protocol method
without the need for an associatedtype.

Any reason why not?

_______________________________________________
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


(Karl) #5

Sounds like you could save yourself some trouble and just file a bug report instead?

···

On 31 Aug 2016, at 06:10, Sitton, Yogev via swift-evolution <swift-evolution@swift.org> wrote:

That’s was my point.
Two sets of rules for the same case in two different places.
These should be unified.

I’ll write the proposal and create a pull request.

On Aug 17, 2016, at 11:24 PM, Slava Pestov <spestov@apple.com <mailto:spestov@apple.com>> wrote:

On Aug 17, 2016, at 10:18 AM, Vladimir.S via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

But yes, strictly speaking 'make()->Circle?' conforms to protocol requirement 'make()->Shape?', it does returns 'Shape?', so I believe this should be treated as conformance to MyShapeProtocol protocol.

I agree this should be made to work, especially since method overriding supports the exact same scenario.

We have two sets of rules, implemented in two different places, for matching method overrides and protocol witnesses. We need to unify the rules and the code.

Slava


(Adrian Zubarev) #6

I’m definitely not an expert on the technical part of this but I wonder if this idea can be generalized.

It would be great if one could override the type A of a member from the supertype with type B iff there is a subtype or conformance relationship like B : A. I believe this would reduce the usage of associated and generic workaround types a lot.

As an example we could take a look at UIView where we have a variable var layerClass: AnyClass.

With the mentioned ability we could make it typesafe.

class UIView {
    var layerClass: CALayer { … }
}

class CustomLayer : CALayer {}

class CustomView : UIView {
    override var layerClass: CustomLayer { … }
}
That would be awesome. :slight_smile:

···

--
Adrian Zubarev
Sent with Airmail

Am 1. September 2016 um 05:03:15, Karl via swift-evolution (swift-evolution@swift.org) schrieb:

On 31 Aug 2016, at 06:10, Sitton, Yogev via swift-evolution <swift-evolution@swift.org> wrote:

That’s was my point.
Two sets of rules for the same case in two different places.
These should be unified.

I’ll write the proposal and create a pull request.

On Aug 17, 2016, at 11:24 PM, Slava Pestov <spestov@apple.com> wrote:

On Aug 17, 2016, at 10:18 AM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

But yes, strictly speaking 'make()->Circle?' conforms to protocol requirement 'make()->Shape?', it does returns 'Shape?', so I believe this should be treated as conformance to MyShapeProtocol protocol.

I agree this should be made to work, especially since method overriding supports the exact same scenario.

We have two sets of rules, implemented in two different places, for matching method overrides and protocol witnesses. We need to unify the rules and the code.

Slava

Sounds like you could save yourself some trouble and just file a bug report instead?

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