[swift-evolution] Allow strengthening argument types in functions declared for protocol conformance

Ian Ynda-Hummel ianynda at gmail.com
Wed Dec 16 15:25:17 CST 2015


I actually think that generic protocols as they exist in Swift 2 are
expressive enough to do what you want to do.

Let me check my understanding, though. You want a definition of a method of
the same name with a signature whose arguments are at least as specific as
those defined in the protocol to implicitly do the appropriate casting,
correct? So to supply a Swift 2 example, your code would be equivalent to
this:

    class Foo { }

    class Bar: Foo { }

    protocol FooDelegate {
        typealias FooType: Foo
        func didPerformSomeAction(object: FooType)
    }

    class FooController: FooDelegate {
        typealias FooType = Foo
        func didPerformSomeAction(object: Foo) {}
    }

    class ProposedFooController: FooDelegate {
        typealias FooType = Bar
        func didPerformSomeAction(object: Bar) {}
    }

What are the limitations there?

On Wed, Dec 16, 2015 at 4:08 PM Terrence Katzenbaer <tkatzenbaer at me.com>
wrote:

> This seems to be better addressed with a generic protocol.
>
> I did consider a generic protocols, and it would be good to have some
> discussion on this vs. my proposed solution.
>
> While there are currently some limitations surrounding generics, and so I
> won't give specific examples, this has been stated as an area of focus for
> Swift 3.
>
> Isn't this mailing list's purpose to discuss and propose changes to Swift
> 3? It seems like you're dismissing this as a "wontfix" with hopes that
> improving generics would resolve this issue in its entirety.
>
> On Dec 16, 2015, at 12:58 PM, ilya <ilya.nikokoshev at gmail.com> wrote:
>
> > It seems more expressive and more functionally correct to be able
> to implement a method strengthening AnyObject to my model type while still
> conforming to the protocol (since my model would pass "is AnyObject").
>
> This seems to be better addressed with a generic protocol. While there are
> currently some limitations surrounding generics, and so I won't give
> specific examples, this has been stated as an area of focus for Swift 3.
>
> > If my NSOutlineView contained objects of a single type, it makes little
> sense to be forced to implement a method solely for handling AnyObjects or
> being forced to typecast to my model type.
>
> In this example NSOutlineView should be specialized to some type T then.
>
> On Wed, Dec 16, 2015 at 23:45 Terrence Katzenbaer via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>> Maybe I shouldn't have mentioned anything about the runtime since that's
>> more about the implementation instead of the general idea... Something more
>> "swifty" could be a compile check on the newly strengthened arguments.
>>
>> If I understand your example code, it's calling
>> didPerformSomeAction(object: Bar) instead of the Foo version because of
>> function overloading? It seems this functionally satisfies not having to
>> typecast, but it doesn't solve the verbosity problem since you're still
>> forced to implement the extraneous didPerformSomeAction(object: Foo).
>>
>> Using the Cocoa framework as an example, NSOutlineViewDelegate has the
>> method:
>> optional func outlineView(_ *outlineView*: NSOutlineView
>> <https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSOutlineView_Class/index.html#//apple_ref/swift/cl/c:objc(cs)NSOutlineView>
>> ,
>>          shouldSelectItem *item*: AnyObject
>> <https://developer.apple.com/library/mac/documentation/Swift/Reference/Swift_AnyObject_Protocol/index.html#//apple_ref/swift/intf/s:PSs9AnyObject>)
>> -> Bool
>> <https://developer.apple.com/library/mac/documentation/Swift/Reference/Swift_Bool_Structure/index.html#//apple_ref/swift/struct/s:Sb>
>>
>> If my NSOutlineView contained objects of a single type, it makes little
>> sense to be forced to implement a method solely for handling AnyObjects or
>> being forced to typecast to my model type.
>>
>> It seems more expressive and more functionally correct to be able
>> to implement a method strengthening AnyObject to my model type while still
>> conforming to the protocol (since my model would pass "is AnyObject").
>>
>> On Dec 16, 2015, at 12:35 PM, Ian Ynda-Hummel <ianynda at gmail.com> wrote:
>>
>> Sorry, that should be
>>
>>     extension FooDelegate where Self: BarController {
>>         func didPerformSomeAction(object: Bar) {}
>>     }
>>
>>
>> On Wed, Dec 16, 2015 at 3:32 PM Ian Ynda-Hummel <ianynda at gmail.com>
>> wrote:
>>
>>> -1
>>>
>>> I think the basic problem is saying the runtime should fail. I feel like
>>> a large part of the power of Swift is letting the compiler and the
>>> programmer make strong assumptions about types specifically to prevent the
>>> runtime from dealing with it.
>>>
>>> In fact, the type system can save us here! I wrote some code you can
>>> play with here: http://swiftstub.com/318278733
>>>
>>> The basic idea is that if you do something like
>>>
>>>     extension FooDelegate where Self: BarController {
>>>         func didPerformSomeAction(object: Foo) {}
>>>     }
>>>
>>> calls to didPerformSomeAction with an argument of type Bar will call the
>>> right one for the type! There might be better ways to do that, but that is
>>> what immediately came to mind.
>>>
>>> On Wed, Dec 16, 2015 at 2:43 PM Terrence Katzenbaer via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>>> Because APIs are designed to be generic, protocols that must be
>>>> conformed generally use types like Object or other base classes for a given
>>>> framework. This introduces type casting verbosity when implementing the
>>>> protocol for a specific use. I would like to see the ability to strengthen
>>>> argument types in functions declared for protocol conformance.
>>>>
>>>> An example:
>>>>
>>>> class Foo { }
>>>>
>>>>
>>>> class Bar: Foo { }
>>>>
>>>>
>>>> protocol FooDelegate {
>>>>
>>>>     func didPerformSomeAction(object: Foo)
>>>>
>>>> }
>>>>
>>>>
>>>> class FooController: FooDelegate {
>>>>
>>>>     func didPerformSomeAction(var object: Foo) {
>>>>
>>>>         // I know that object must be a Bar instance
>>>>
>>>>         object = object as! Bar
>>>>
>>>>         // do something with object
>>>>
>>>>     }
>>>>
>>>> }
>>>>
>>>>
>>>> class ProposedFooController: FooDelegate { // Type
>>>> 'ProposedFooController' does not conform to protocol 'FooDelegate'
>>>>
>>>>     func didPerformSomeAction(object: Bar) {
>>>>
>>>>         // do something with Bar instance
>>>>
>>>>     }
>>>>
>>>> }
>>>>
>>>> The glaring issue I see outright is how the runtime should fail when
>>>> `didPerformSomeAction` in `ProposedFooController` is called with a non-Bar
>>>> instance... But perhaps it /should/ fail outright because the programmer
>>>> has explicitly stated that the type should be Bar.
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>
>>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151216/090fa9a5/attachment.html>


More information about the swift-evolution mailing list