Will Swift ever support optional methods without @objc?


(Rick M) #1

Will Swift ever support optional methods without @objc?

What are the disadvantages of marking a protocol @objc?

Thanks!

···

--
Rick Mann
rmann@latencyzero.com


(Benjamin Spratling) #2

Given optionals and closures, is it necessary to support optional protocols?

protocol MyProtocol {
  var titleForRow:((_ indexPath:IndexPath)->(String))? { get }
}

One disadvantage is that you need Obj-C, which means it doesn’t run on linux, or several other platforms.
Another disadvantage, as I understand it, is it requires slower Obj-c dispatch, instead of witness tables. Obj-C dispatch also only considers names, not argument & return types.

···

On Nov 14, 2016, at 5:48 PM, Rick Mann via swift-evolution <swift-evolution@swift.org> wrote:

Will Swift ever support optional methods without @objc?

What are the disadvantages of marking a protocol @objc?

Thanks!

--
Rick Mann
rmann@latencyzero.com

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


(Chris Lattner) #3

We discussed this extensively in the Swift 3 timeframe, and I believe that the consensus was “no”: optional requirements are considered an Objective-C compatibility feature.

I don’t recall all of the discussion, but a major one would have to be that it is highly redundant with other language features we already have, and makes the design space of Swift APIs more complicated. If Objective-C didn’t already have them, we would never consider adding them to our protocol model.

-Chris

···

On Nov 14, 2016, at 3:48 PM, Rick Mann via swift-evolution <swift-evolution@swift.org> wrote:

Will Swift ever support optional methods without @objc?


(Charles Constant) #4

The disadvantage is that it's easy in Swift to push millions of things in
protocols, and end up with:

    class MyClass: SwiftProtocollable, MoreFunctionalityable, MoreHereable,
StillMoreable, ThisTooable, StillMoreable {
        ...
    }

Given enough thought, maybe this can be avoided, but the problem is (as far
as I can tell, and I may be out to lunch) that protocols are
philosophically the "correct" way in Swift to do a lot of things.

I recently wrote a tiny framework for Drag n Drop, and I wound up with
various combinations of almost 10 protocols - and, afai could tell, that
was "correct" because I was specifying the different abilities of my
classes (eg: do they have methods for reading text data, file data, writing
promises, reading promises, etc) It's just not easy to read.

···

On Mon, Nov 14, 2016 at 4:10 PM, Benjamin Spratling via swift-evolution < swift-evolution@swift.org> wrote:

Given optionals and closures, is it necessary to support optional
protocols?

protocol MyProtocol {
        var titleForRow:((_ indexPath:IndexPath)->(String))? { get }
}

One disadvantage is that you need Obj-C, which means it doesn’t run on
linux, or several other platforms.
Another disadvantage, as I understand it, is it requires slower Obj-c
dispatch, instead of witness tables. Obj-C dispatch also only considers
names, not argument & return types.

> On Nov 14, 2016, at 5:48 PM, Rick Mann via swift-evolution < > swift-evolution@swift.org> wrote:
>
> Will Swift ever support optional methods without @objc?
>
> What are the disadvantages of marking a protocol @objc?
>
> Thanks!
>
> --
> Rick Mann
> rmann@latencyzero.com
>
>
> _______________________________________________
> 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


(Rick M) #5

Given optionals and closures, is it necessary to support optional protocols?

protocol MyProtocol {
  var titleForRow:((_ indexPath:IndexPath)->(String))? { get }
}

Well, it would be nice if making a func optional at least acted as syntactic sugar for this, wouldn't it?

One disadvantage is that you need Obj-C, which means it doesn’t run on linux, or several other platforms.
Another disadvantage, as I understand it, is it requires slower Obj-c dispatch, instead of witness tables. Obj-C dispatch also only considers names, not argument & return types.

Does implementing an @objc protocol then make all my class' methods use objc-dispatch? Or just the ones in the protocol?

Thanks,

···

On Nov 14, 2016, at 16:10 , Benjamin Spratling via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 14, 2016, at 5:48 PM, Rick Mann via swift-evolution <swift-evolution@swift.org> wrote:

Will Swift ever support optional methods without @objc?

What are the disadvantages of marking a protocol @objc?

Thanks!

--
Rick Mann
rmann@latencyzero.com

_______________________________________________
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

--
Rick Mann
rmann@latencyzero.com


(Charlie Monroe) #6

One major example is the NS/UITableViewDataSource or Delegate - there are many many methods that you don't need to implement, hence are optional.

But I think that this was partially solved by default implementation of protocol methods, which pretty much does what you want...

···

On Nov 15, 2016, at 1:10 AM, Benjamin Spratling via swift-evolution <swift-evolution@swift.org> wrote:

Given optionals and closures, is it necessary to support optional protocols?

protocol MyProtocol {
  var titleForRow:((_ indexPath:IndexPath)->(String))? { get }
}

One disadvantage is that you need Obj-C, which means it doesn’t run on linux, or several other platforms.
Another disadvantage, as I understand it, is it requires slower Obj-c dispatch, instead of witness tables. Obj-C dispatch also only considers names, not argument & return types.

On Nov 14, 2016, at 5:48 PM, Rick Mann via swift-evolution <swift-evolution@swift.org> wrote:

Will Swift ever support optional methods without @objc?

What are the disadvantages of marking a protocol @objc?

Thanks!

--
Rick Mann
rmann@latencyzero.com

_______________________________________________
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


(Rick M) #7

I just realized I only responded to someone else, and not the whole list. It does, but it forces me to make the return value of the protocol method optional, so that the default implementation can return nil.

In the end, I guess that's not so bad, since I'm not happy with the entire approach, but it'll do for now.

···

On Nov 14, 2016, at 22:51 , Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:

One major example is the NS/UITableViewDataSource or Delegate - there are many many methods that you don't need to implement, hence are optional.

But I think that this was partially solved by default implementation of protocol methods, which pretty much does what you want...

--
Rick Mann
rmann@latencyzero.com


(Charlie Monroe) #8

One major example is the NS/UITableViewDataSource or Delegate - there are many many methods that you don't need to implement, hence are optional.

But I think that this was partially solved by default implementation of protocol methods, which pretty much does what you want...

I just realized I only responded to someone else, and not the whole list. It does, but it forces me to make the return value of the protocol method optional, so that the default implementation can return nil.

You'd still get an optional even with @optional protocol methods:

@objc
protocol Foo {
  @optional func bar() -> Int
}

let x = foo.bar?() // x is Int?

Nevertheless, in the previous example:

  var titleForRow:((_ indexPath:IndexPath)->(String))? { get }

You can return String? in the closure instead and the default implementation can simply return a closure that returns nil. This is pretty much equivalent.

···

On Nov 15, 2016, at 8:53 AM, Rick Mann <rmann@latencyzero.com> wrote:

On Nov 14, 2016, at 22:51 , Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:

In the end, I guess that's not so bad, since I'm not happy with the entire approach, but it'll do for now.

--
Rick Mann
rmann@latencyzero.com


(Haravikk) #9

What's different about having the method return nil vs being optional? You're attempting to call it either way, and presumably need some means of handling the return value, except in Swift it's all nice and explicit and easy to put in a conditional like:

  if let result = myObject.someOptionalMethod() { /* Do some stuff */ }
  print(myObject.someOptionalStringMethod() ?? "")

And so-on. If you need a method to be both optional, and return a nilable result then you can use a double optional like so:

  if let result = myObject.someDoubleOptionalMethod() { // Method was implemented
    if let value = result { // Method returned a value
      /* Do some stuff */
    }
  }

By defining the methods as returning an Optional and throwing in default implementations you can specify fewer, bigger protocols and make clear what the requirements really are, though personally given the choice I'd prefer a dozen smaller protocols that are absolutely explicit in what they do.

But yeah, I think the tools you need are all there already; maybe there's an argument to be made for allowing default return values on protocol methods, to reduce the boiler-plate?

···

On 15 Nov 2016, at 07:53, Rick Mann via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 14, 2016, at 22:51 , Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:

One major example is the NS/UITableViewDataSource or Delegate - there are many many methods that you don't need to implement, hence are optional.

But I think that this was partially solved by default implementation of protocol methods, which pretty much does what you want...

I just realized I only responded to someone else, and not the whole list. It does, but it forces me to make the return value of the protocol method optional, so that the default implementation can return nil.

In the end, I guess that's not so bad, since I'm not happy with the entire approach, but it'll do for now.


(Karl) #10

I think there is a difference between:

- A method which returns an optional result, and
- An optional method which, if present, always returns a result

Perhaps not so much of a difference at the usage site (it’s just a question of placing a ? for optional chaining), but semantically and when conforming to the protocol, they mean different things.

- Karl

···

On 15 Nov 2016, at 12:22, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

On 15 Nov 2016, at 07:53, Rick Mann via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Nov 14, 2016, at 22:51 , Charlie Monroe via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

One major example is the NS/UITableViewDataSource or Delegate - there are many many methods that you don't need to implement, hence are optional.

But I think that this was partially solved by default implementation of protocol methods, which pretty much does what you want...

I just realized I only responded to someone else, and not the whole list. It does, but it forces me to make the return value of the protocol method optional, so that the default implementation can return nil.

In the end, I guess that's not so bad, since I'm not happy with the entire approach, but it'll do for now.

What's different about having the method return nil vs being optional? You're attempting to call it either way, and presumably need some means of handling the return value, except in Swift it's all nice and explicit and easy to put in a conditional like:

  if let result = myObject.someOptionalMethod() { /* Do some stuff */ }
  print(myObject.someOptionalStringMethod() ?? "")

And so-on. If you need a method to be both optional, and return a nilable result then you can use a double optional like so:

  if let result = myObject.someDoubleOptionalMethod() { // Method was implemented
    if let value = result { // Method returned a value
      /* Do some stuff */
    }
  }

By defining the methods as returning an Optional and throwing in default implementations you can specify fewer, bigger protocols and make clear what the requirements really are, though personally given the choice I'd prefer a dozen smaller protocols that are absolutely explicit in what they do.

But yeah, I think the tools you need are all there already; maybe there's an argument to be made for allowing default return values on protocol methods, to reduce the boiler-plate?
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Dave Abrahams) #11

This has been discussed somewhat heavily in the past and nothing yet has
really moved forward on it. I do think a good way of doing something like
this would be helpful. I have resulted to defining an interface with an
extension that provides empty defaults and for each function a match bool
var exists to imply if it exists or not. The code accepting a delegate can
probe these bool vars to configure itself to efficiently operate based on
knowledge about what the delegate expects (some missing from most proposed
solutions other then @objc optional).

If there are truly programming problems that don't have a clean solution
without introducing optional requirements, I'd really like to see them.

Speaking for myself: I think “probe-a-type” programming is in general a
bad idea, and I'm opposed to adding features that encourage it. It's
almost always better to design entry points into supertypes (protocols,
or base classes if you must ;->) with default implementations that can
be overridden to do the work you need based on the characteristics of a
subtype, rather than trying to make decisions in the caller based on the
shape of the type. When you *do* need probing, it's a good idea to make
the set of possible subtypes a closed set, so the compiler can ensure
you handle all cases—i.e., use an enum.

···

on Tue Nov 15 2016, Shawn Erickson <swift-evolution@swift.org> wrote:

On Tue, Nov 15, 2016 at 6:59 AM Karl via swift-evolution < > swift-evolution@swift.org> wrote:

On 15 Nov 2016, at 12:22, Haravikk via swift-evolution < >> swift-evolution@swift.org> wrote:

On 15 Nov 2016, at 07:53, Rick Mann via swift-evolution < >> swift-evolution@swift.org> wrote:

On Nov 14, 2016, at 22:51 , Charlie Monroe via swift-evolution < >> swift-evolution@swift.org> wrote:

One major example is the NS/UITableViewDataSource or Delegate - there are
many many methods that you don't need to implement, hence are optional.

But I think that this was partially solved by default implementation of
protocol methods, which pretty much does what you want...

I just realized I only responded to someone else, and not the whole list.
It does, but it forces me to make the return value of the protocol method
optional, so that the default implementation can return nil.

In the end, I guess that's not so bad, since I'm not happy with the entire
approach, but it'll do for now.

What's different about having the method return nil vs being optional?
You're attempting to call it either way, and presumably need some means of
handling the return value, except in Swift it's all nice and explicit and
easy to put in a conditional like:

if let result = myObject.someOptionalMethod() { /* Do some stuff */ }
print(myObject.someOptionalStringMethod() ?? "")

And so-on. If you need a method to be both optional, and return a nilable
result then you can use a double optional like so:

if let result = myObject.someDoubleOptionalMethod() { // Method was
implemented
if let value = result { // Method returned a value
/* Do some stuff */
}
}

By defining the methods as returning an Optional and throwing in default
implementations you can specify fewer, bigger protocols and make clear what
the requirements really are, though personally given the choice I'd prefer
a dozen smaller protocols that are absolutely explicit in what they do.

But yeah, I think the tools you need are all there already; maybe there's
an argument to be made for allowing default return values on protocol
methods, to reduce the boiler-plate?
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I think there is a difference between:

- A method which returns an optional result, and
- An optional method which, if present, always returns a result

Perhaps not so much of a difference at the usage site (it’s just a
question of placing a ? for optional chaining), but semantically and when
conforming to the protocol, they mean different things.

- Karl

_______________________________________________
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

--
-Dave


(Rick M) #12

(I'm re-watching your WWDC 2105 talk about protocol-oriented programming, so I may end up with answers to the issues below.)

The thing that prompted my original post on this subject was an exploration of how to best implement a CAD program. In this case, something like Illustrator, where you can create, manipulate, and draw various shape types. I wanted to separate, as much as possible, the mathematical representation of the shape from the drawing and manipulating, and ideally have only one set of objects permanently instantiated (the mathematical representations of the shapes, i.e. the model).

So, I have a CanvasView that has a list of these shapes (a simple array). I have a set of tools (generally, a single instance of each, although when each gets instantiated can be changed in the design). The CanvasView triggers the drawing and the mouse handling for the set of shapes (CanvasObjects).

I've got something like this:

protocol Renderable { func renderer() -> Renderer? }
extension Renderable { func renderer() -> Renderer? { return nil } }

protocol Selectable { var selectionState: enum SelectionState }
protocol HitTestable { func hitTest(_ inPt: CGPoitn) }

protocol CanvasObject : HitTestable, Selectable {}
class Path : CanvasObject { }

protocol Renderer { func draw(in inCTX: CGContext) }
class PathRenderer : Renderer { }

You get the idea. Stop me if I'm way off base here.

I initially wanted Renderable.renderer() to be optional. I think I'm convinced returning an optional Renderer is equivalent.

Drawing

···

On Nov 15, 2016, at 09:24 , Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

Speaking for myself: I think “probe-a-type” programming is in general a
bad idea, and I'm opposed to adding features that encourage it. It's
almost always better to design entry points into supertypes (protocols,
or base classes if you must ;->) with default implementations that can
be overridden to do the work you need based on the characteristics of a
subtype, rather than trying to make decisions in the caller based on the
shape of the type. When you *do* need probing, it's a good idea to make
the set of possible subtypes a closed set, so the compiler can ensure
you handle all cases—i.e., use an enum.

-------
CanvasView visits each CanvasObject in turn, instantiates an appropriate Renderer for the object (by calling Renderable.renderer()), calls Renderer.draw().

Mouse Handling
--------------
The currently-selected Tool is handed the mouse hit and the view. It iterates the objects, calling hitTest(). It then instantiates a handler based on the hit object type and current tool (might just be the current tool).

Problems
--------
The CanvasView has a list of CanvasObjects, forcing all objects to conform to all the protocols (e.g. Renderable, Selectable, HitTestable.) That is the CanvasView has a view onto the set of objects as complete objects, rather than a view of all Renderable objects, all HitTestable objects, etc. In this app, it may not be meaningful to talk about objects that are only renderable, but then again, it might (a grid could be renderable, but not selectable or hit testable; in practice it'll be implemented as a completely different entity, not part of the set of objects).

There is a problem of state management. Shapes are drawn differently depending on their state (e.g. normal, hovered, selected, sub-selected, being-snapped-to, etc.). I see no good way to store that state, except in the core object (e.g. Path). Alternatively, a parallel data structure that holds that state, but now I have to ensure instances of associated objects can be mapped back and forth. In fact, as I think about this more, I think it's a better solution, because it's conceivable there would be multiple views of the same model data, and the various states might be independent per view.

And performance will probably be okay, but needs to be considered.

I'm probably just making a mountain out of a molehill, but I want to make sure I'm understanding Swift thoroughly.

--
Rick Mann
rmann@latencyzero.com


(Shawn Erickson) #13

This has been discussed somewhat heavily in the past and nothing yet has
really moved forward on it. I do think a good way of doing something like
this would be helpful. I have resulted to defining an interface with an
extension that provides empty defaults and for each function a match bool
var exists to imply if it exists or not. The code accepting a delegate can
probe these bool vars to configure itself to efficiently operate based on
knowledge about what the delegate expects (some missing from most proposed
solutions other then @objc optional).

···

On Tue, Nov 15, 2016 at 6:59 AM Karl via swift-evolution < swift-evolution@swift.org> wrote:

On 15 Nov 2016, at 12:22, Haravikk via swift-evolution < > swift-evolution@swift.org> wrote:

On 15 Nov 2016, at 07:53, Rick Mann via swift-evolution < > swift-evolution@swift.org> wrote:

On Nov 14, 2016, at 22:51 , Charlie Monroe via swift-evolution < > swift-evolution@swift.org> wrote:

One major example is the NS/UITableViewDataSource or Delegate - there are
many many methods that you don't need to implement, hence are optional.

But I think that this was partially solved by default implementation of
protocol methods, which pretty much does what you want...

I just realized I only responded to someone else, and not the whole list.
It does, but it forces me to make the return value of the protocol method
optional, so that the default implementation can return nil.

In the end, I guess that's not so bad, since I'm not happy with the entire
approach, but it'll do for now.

What's different about having the method return nil vs being optional?
You're attempting to call it either way, and presumably need some means of
handling the return value, except in Swift it's all nice and explicit and
easy to put in a conditional like:

if let result = myObject.someOptionalMethod() { /* Do some stuff */ }
print(myObject.someOptionalStringMethod() ?? "")

And so-on. If you need a method to be both optional, and return a nilable
result then you can use a double optional like so:

if let result = myObject.someDoubleOptionalMethod() { // Method was
implemented
if let value = result { // Method returned a value
/* Do some stuff */
}
}

By defining the methods as returning an Optional and throwing in default
implementations you can specify fewer, bigger protocols and make clear what
the requirements really are, though personally given the choice I'd prefer
a dozen smaller protocols that are absolutely explicit in what they do.

But yeah, I think the tools you need are all there already; maybe there's
an argument to be made for allowing default return values on protocol
methods, to reduce the boiler-plate?
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I think there is a difference between:

- A method which returns an optional result, and
- An optional method which, if present, always returns a result

Perhaps not so much of a difference at the usage site (it’s just a
question of placing a ? for optional chaining), but semantically and when
conforming to the protocol, they mean different things.

- Karl

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


(Shawn Erickson) #14

Note you can also use a protocol of optional methods to do the same things
as the var... I for now haven't done it that way.

···

On Tue, Nov 15, 2016 at 7:46 AM Shawn Erickson <shawnce@gmail.com> wrote:

This has been discussed somewhat heavily in the past and nothing yet has
really moved forward on it. I do think a good way of doing something like
this would be helpful. I have resulted to defining an interface with an
extension that provides empty defaults and for each function a match bool
var exists to imply if it exists or not. The code accepting a delegate can
probe these bool vars to configure itself to efficiently operate based on
knowledge about what the delegate expects (some missing from most proposed
solutions other then @objc optional).
On Tue, Nov 15, 2016 at 6:59 AM Karl via swift-evolution < > swift-evolution@swift.org> wrote:

On 15 Nov 2016, at 12:22, Haravikk via swift-evolution < > swift-evolution@swift.org> wrote:

On 15 Nov 2016, at 07:53, Rick Mann via swift-evolution < > swift-evolution@swift.org> wrote:

On Nov 14, 2016, at 22:51 , Charlie Monroe via swift-evolution < > swift-evolution@swift.org> wrote:

One major example is the NS/UITableViewDataSource or Delegate - there are
many many methods that you don't need to implement, hence are optional.

But I think that this was partially solved by default implementation of
protocol methods, which pretty much does what you want...

I just realized I only responded to someone else, and not the whole list.
It does, but it forces me to make the return value of the protocol method
optional, so that the default implementation can return nil.

In the end, I guess that's not so bad, since I'm not happy with the entire
approach, but it'll do for now.

What's different about having the method return nil vs being optional?
You're attempting to call it either way, and presumably need some means of
handling the return value, except in Swift it's all nice and explicit and
easy to put in a conditional like:

if let result = myObject.someOptionalMethod() { /* Do some stuff */ }
print(myObject.someOptionalStringMethod() ?? "")

And so-on. If you need a method to be both optional, and return a nilable
result then you can use a double optional like so:

if let result = myObject.someDoubleOptionalMethod() { // Method was
implemented
if let value = result { // Method returned a value
/* Do some stuff */
}
}

By defining the methods as returning an Optional and throwing in default
implementations you can specify fewer, bigger protocols and make clear what
the requirements really are, though personally given the choice I'd prefer
a dozen smaller protocols that are absolutely explicit in what they do.

But yeah, I think the tools you need are all there already; maybe there's
an argument to be made for allowing default return values on protocol
methods, to reduce the boiler-plate?
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I think there is a difference between:

- A method which returns an optional result, and
- An optional method which, if present, always returns a result

Perhaps not so much of a difference at the usage site (it’s just a
question of placing a ? for optional chaining), but semantically and when
conforming to the protocol, they mean different things.

- Karl

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


(Haravikk) #15

Maybe, but it just seems like default implementations do everything that optional methods require, it's just not got a shorthand to make it easier.

Really the question is, do we adopt the optional keyword for non @objc methods, along with the special syntax for calling them (it's not exactly the same as chaining). Personally though I'd rather do the opposite and do away with both, and have @objc optional methods replaced by default implementations somehow.

The question then is how; simply making the methods optional (return type becomes optional, or more optional) is not the best solution as testing optionality isn't a one-size-fits-all solution. For example, API designers may prefer to return a method's non-implemented state with a specific int or enum case, or by throwing an exception or producing an error. You can do all of these things with default implementations.

Otherwise you could allow specifying of default return values within a protocol itself, functionally this would be identical to adding a default implementation, just a bit easier for the simplest case, I'm not sure it warrants special treatment though.

I mean, when it comes down to it an optional method is just one that might do nothing; but a default implementation that returns a default value or has no body achieves this just as effectively. The only advantage here is the call-site semantics, but you can enforce the same by having an optional return value if that's required.

Put another way, I don't see what's gained by the first of these two:

  foo.someOptionalMethod?() // @objc optional method
  foo.someMethod() // default implementation is empty

You've attempted to call both, and in both cases it just won't do anything. Your knowing that doesn't really change anything. Meanwhile if you have a return value:

  if let result = foo.someOptionalMethod?() { /* Process result * / }
  if let result = foo.someMethod() { /* Process result */ } // default implementation returns nil

If just doesn't seem like such a special case to require special treatment when Swift's optional support is already really good and encapsulates the same ideas, and the void case just needs a default implementation that's a no-op. Plus by using a default implementation you have more flexibility overall in how you actually respond when a method isn't implemented.

···

On 15 Nov 2016, at 14:59, Karl <razielim@gmail.com> wrote:

On 15 Nov 2016, at 12:22, Haravikk via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
What's different about having the method return nil vs being optional? You're attempting to call it either way, and presumably need some means of handling the return value, except in Swift it's all nice and explicit and easy to put in a conditional like:

  if let result = myObject.someOptionalMethod() { /* Do some stuff */ }
  print(myObject.someOptionalStringMethod() ?? "")

And so-on. If you need a method to be both optional, and return a nilable result then you can use a double optional like so:

  if let result = myObject.someDoubleOptionalMethod() { // Method was implemented
    if let value = result { // Method returned a value
      /* Do some stuff */
    }
  }

By defining the methods as returning an Optional and throwing in default implementations you can specify fewer, bigger protocols and make clear what the requirements really are, though personally given the choice I'd prefer a dozen smaller protocols that are absolutely explicit in what they do.

But yeah, I think the tools you need are all there already; maybe there's an argument to be made for allowing default return values on protocol methods, to reduce the boiler-plate?
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I think there is a difference between:

- A method which returns an optional result, and
- An optional method which, if present, always returns a result

Perhaps not so much of a difference at the usage site (it’s just a question of placing a ? for optional chaining), but semantically and when conforming to the protocol, they mean different things.


(Karl) #16

If you don’t mind me asking, what is your use-case?

Even though I think "optional methods" and “methods returning optionals” are different things, I don’t really have any examples where optional methods are better than sub-protocols.

e.g.

// Core callbacks
protocol MyDelegate { }

// Optional callbacks, added like a mixin
protocol MyDelegateWithExtras : MyDelegate { }

// Some more optional callbacks
protocol MySubDelegate : MyDelegate {}

class DelegateImpl : MySubDelegate, MyDelegateWithExtras {
  // Implement all core + optional callbacks
}

var d : MyDelegate = DelegateImpl()

if let extras = d as? MyDelegateWithExtras {
    // invoke optional functionality
}

I don’t know what the overhead of the as? call is, but it’s almost certainly less than an Obj-C `respondsToSelector` call. Depending on whether you need to swap the delegate for objects of different types, you could also use generics to optimise the checks (and possibly more) away.

- Karl

···

On 15 Nov 2016, at 16:46, Shawn Erickson <shawnce@gmail.com> wrote:

This has been discussed somewhat heavily in the past and nothing yet has really moved forward on it. I do think a good way of doing something like this would be helpful. I have resulted to defining an interface with an extension that provides empty defaults and for each function a match bool var exists to imply if it exists or not. The code accepting a delegate can probe these bool vars to configure itself to efficiently operate based on knowledge about what the delegate expects (some missing from most proposed solutions other then @objc optional).
On Tue, Nov 15, 2016 at 6:59 AM Karl via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 15 Nov 2016, at 12:22, Haravikk via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 15 Nov 2016, at 07:53, Rick Mann via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Nov 14, 2016, at 22:51 , Charlie Monroe via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

One major example is the NS/UITableViewDataSource or Delegate - there are many many methods that you don't need to implement, hence are optional.

But I think that this was partially solved by default implementation of protocol methods, which pretty much does what you want...

I just realized I only responded to someone else, and not the whole list. It does, but it forces me to make the return value of the protocol method optional, so that the default implementation can return nil.

In the end, I guess that's not so bad, since I'm not happy with the entire approach, but it'll do for now.

What's different about having the method return nil vs being optional? You're attempting to call it either way, and presumably need some means of handling the return value, except in Swift it's all nice and explicit and easy to put in a conditional like:

  if let result = myObject.someOptionalMethod() { /* Do some stuff */ }
  print(myObject.someOptionalStringMethod() ?? "")

And so-on. If you need a method to be both optional, and return a nilable result then you can use a double optional like so:

  if let result = myObject.someDoubleOptionalMethod() { // Method was implemented
    if let value = result { // Method returned a value
      /* Do some stuff */
    }
  }

By defining the methods as returning an Optional and throwing in default implementations you can specify fewer, bigger protocols and make clear what the requirements really are, though personally given the choice I'd prefer a dozen smaller protocols that are absolutely explicit in what they do.

But yeah, I think the tools you need are all there already; maybe there's an argument to be made for allowing default return values on protocol methods, to reduce the boiler-plate?
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I think there is a difference between:

- A method which returns an optional result, and
- An optional method which, if present, always returns a result

Perhaps not so much of a difference at the usage site (it’s just a question of placing a ? for optional chaining), but semantically and when conforming to the protocol, they mean different things.

- Karl

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


(Shawn Erickson) #17

Using sub-protocols may be sufficient and make sense... to be honest I
haven't had the time to fully explore this space and convert some things I
have done in objective-c to pure swift. I do wonder how often that those
sub-protocols would degenerate into having single methods.

In a nut shell it isn't atypical for a delegate to only care about
"injecting itself" (e.g. implementing a delegate function) for a subset of
the available delegation points leaving the others unimplemented. In the
objective-c case the delegator can evaluate what delegation points a
delegate implements at time of delegate registration (or more dynamically
... however I often did imp caching for performance reasons in some of my
designs). This probe on delegate registration may make sense for the
delegator if additional bookkeeping, processing, state management, or
potentially whole code path/objects can be avoided if the delegate doesn't
implement a delegation point(s). If the delegation points happened to be
implemented using a default nop implementation this type of optimization
may not be possible.

In a nutshell I see and have the need for the delegator to know if the
delegate has actually provided an implementation of their own or not so I
can potentially leverage optimizations internal to my delegator. As a
delegate is also nice to know clearly what I have to implement or not and
the optional protocol member concept is one way of doing that, it would be
nice to have something like that to help delegate implementors.

I suggest mentally evaluating the delegation points of URLSession with the
perspective of the delegator (URLSession) being able to optimize what it
does based what it delegate has provided and implementation for. For
example the new metrics delegation point like could optimize away book
keeping and related processing if the delegate isn't interested.
Additionally look at it from the point of view of a delegate implementor
noting the despite already having some number of sub-protocols you still
often only implement one or two delegate points. Alternate swifty
implementations likely exist that would be interesting to explore to help
inform what makes sense as a language addition and/or help folks used to
"traditional" delegation pattern under Objective-C follow more Swifty
patterns going forward.

-Shawn

···

On Tue, Nov 15, 2016 at 9:24 AM Karl <razielim@gmail.com> wrote:

On 15 Nov 2016, at 16:46, Shawn Erickson <shawnce@gmail.com> wrote:

This has been discussed somewhat heavily in the past and nothing yet has
really moved forward on it. I do think a good way of doing something like
this would be helpful. I have resulted to defining an interface with an
extension that provides empty defaults and for each function a match bool
var exists to imply if it exists or not. The code accepting a delegate can
probe these bool vars to configure itself to efficiently operate based on
knowledge about what the delegate expects (some missing from most proposed
solutions other then @objc optional).
On Tue, Nov 15, 2016 at 6:59 AM Karl via swift-evolution < > swift-evolution@swift.org> wrote:

On 15 Nov 2016, at 12:22, Haravikk via swift-evolution < > swift-evolution@swift.org> wrote:

On 15 Nov 2016, at 07:53, Rick Mann via swift-evolution < > swift-evolution@swift.org> wrote:

On Nov 14, 2016, at 22:51 , Charlie Monroe via swift-evolution < > swift-evolution@swift.org> wrote:

One major example is the NS/UITableViewDataSource or Delegate - there are
many many methods that you don't need to implement, hence are optional.

But I think that this was partially solved by default implementation of
protocol methods, which pretty much does what you want...

I just realized I only responded to someone else, and not the whole list.
It does, but it forces me to make the return value of the protocol method
optional, so that the default implementation can return nil.

In the end, I guess that's not so bad, since I'm not happy with the entire
approach, but it'll do for now.

What's different about having the method return nil vs being optional?
You're attempting to call it either way, and presumably need some means of
handling the return value, except in Swift it's all nice and explicit and
easy to put in a conditional like:

if let result = myObject.someOptionalMethod() { /* Do some stuff */ }
print(myObject.someOptionalStringMethod() ?? "")

And so-on. If you need a method to be both optional, and return a nilable
result then you can use a double optional like so:

if let result = myObject.someDoubleOptionalMethod() { // Method was
implemented
if let value = result { // Method returned a value
/* Do some stuff */
}
}

By defining the methods as returning an Optional and throwing in default
implementations you can specify fewer, bigger protocols and make clear what
the requirements really are, though personally given the choice I'd prefer
a dozen smaller protocols that are absolutely explicit in what they do.

But yeah, I think the tools you need are all there already; maybe there's
an argument to be made for allowing default return values on protocol
methods, to reduce the boiler-plate?
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I think there is a difference between:

- A method which returns an optional result, and
- An optional method which, if present, always returns a result

Perhaps not so much of a difference at the usage site (it’s just a
question of placing a ? for optional chaining), but semantically and when
conforming to the protocol, they mean different things.

- Karl

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

If you don’t mind me asking, what is your use-case?

Even though I think "optional methods" and “methods returning optionals”
are different things, I don’t really have any examples where optional
methods are better than sub-protocols.

e.g.

// Core callbacks
protocol MyDelegate { }

// Optional callbacks, added like a mixin
protocol MyDelegateWithExtras : MyDelegate { }

// Some more optional callbacks
protocol MySubDelegate : MyDelegate {}

class DelegateImpl : MySubDelegate, MyDelegateWithExtras {
  // Implement all core + optional callbacks
}

var d : MyDelegate = DelegateImpl()

if let extras = d as? MyDelegateWithExtras {
    // invoke optional functionality
}

I don’t know what the overhead of the as? call is, but it’s almost
certainly less than an Obj-C `respondsToSelector` call. Depending on
whether you need to swap the delegate for objects of different types, you
could also use generics to optimise the checks (and possibly more) away.

- Karl


(Karl) #18

You sometimes needed those kind of caching techniques in Objective-C, because it’s such a dynamic language. The question of “does this object respond to this selector” has many complex considerations. For one thing, objects may add and remove methods (or have it done to them) at any time. Objects can even synthesise implementations the first time they receive a selector. It’s been optimised massively over the years, but it can still be a pretty slow operation -- and since hardly anything actually makes use of those features it’s common to ask once and cache the responses in a bitmask. In Objective-C, asking whether or not an object conforms to a protocol just cascades in to a bunch of calls to “respondsToSelector”, so it’s also very painful.

The Swift runtime doesn’t have those dynamic features. If you added any methods to a bridged Swift object via the Obj-C runtime, those methods wouldn’t be callable from your Swift code anyway, so we never have to worry about that. Protocols in Swift are not the loose contracts of Objective-C; you can create empty “marker” protocols and different objects may or may not conform to it, even though it has no functional requirements. That means testing for conformance should be much faster, too (and covers all requirements at once).

Protocol dispatch in Swift is fast, there is something called a “protocol witness table” (vtable + pointer + lifetime func ptrs), which is what is actually getting stored when you declare a variable with only a protocol for a type. So there isn’t really a huge runtime cost from the dispatch anymore either, and you don’t need to explicitly resolve and store the IMPs yourself to get decent performance.

- Karl

···

On 15 Nov 2016, at 19:38, Shawn Erickson <shawnce@gmail.com> wrote:

Using sub-protocols may be sufficient and make sense... to be honest I haven't had the time to fully explore this space and convert some things I have done in objective-c to pure swift. I do wonder how often that those sub-protocols would degenerate into having single methods.

In a nut shell it isn't atypical for a delegate to only care about "injecting itself" (e.g. implementing a delegate function) for a subset of the available delegation points leaving the others unimplemented. In the objective-c case the delegator can evaluate what delegation points a delegate implements at time of delegate registration (or more dynamically ... however I often did imp caching for performance reasons in some of my designs). This probe on delegate registration may make sense for the delegator if additional bookkeeping, processing, state management, or potentially whole code path/objects can be avoided if the delegate doesn't implement a delegation point(s). If the delegation points happened to be implemented using a default nop implementation this type of optimization may not be possible.

In a nutshell I see and have the need for the delegator to know if the delegate has actually provided an implementation of their own or not so I can potentially leverage optimizations internal to my delegator. As a delegate is also nice to know clearly what I have to implement or not and the optional protocol member concept is one way of doing that, it would be nice to have something like that to help delegate implementors.

I suggest mentally evaluating the delegation points of URLSession with the perspective of the delegator (URLSession) being able to optimize what it does based what it delegate has provided and implementation for. For example the new metrics delegation point like could optimize away book keeping and related processing if the delegate isn't interested. Additionally look at it from the point of view of a delegate implementor noting the despite already having some number of sub-protocols you still often only implement one or two delegate points. Alternate swifty implementations likely exist that would be interesting to explore to help inform what makes sense as a language addition and/or help folks used to "traditional" delegation pattern under Objective-C follow more Swifty patterns going forward.

-Shawn

On Tue, Nov 15, 2016 at 9:24 AM Karl <razielim@gmail.com <mailto:razielim@gmail.com>> wrote:

On 15 Nov 2016, at 16:46, Shawn Erickson <shawnce@gmail.com <mailto:shawnce@gmail.com>> wrote:

This has been discussed somewhat heavily in the past and nothing yet has really moved forward on it. I do think a good way of doing something like this would be helpful. I have resulted to defining an interface with an extension that provides empty defaults and for each function a match bool var exists to imply if it exists or not. The code accepting a delegate can probe these bool vars to configure itself to efficiently operate based on knowledge about what the delegate expects (some missing from most proposed solutions other then @objc optional).
On Tue, Nov 15, 2016 at 6:59 AM Karl via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 15 Nov 2016, at 12:22, Haravikk via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 15 Nov 2016, at 07:53, Rick Mann via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Nov 14, 2016, at 22:51 , Charlie Monroe via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

One major example is the NS/UITableViewDataSource or Delegate - there are many many methods that you don't need to implement, hence are optional.

But I think that this was partially solved by default implementation of protocol methods, which pretty much does what you want...

I just realized I only responded to someone else, and not the whole list. It does, but it forces me to make the return value of the protocol method optional, so that the default implementation can return nil.

In the end, I guess that's not so bad, since I'm not happy with the entire approach, but it'll do for now.

What's different about having the method return nil vs being optional? You're attempting to call it either way, and presumably need some means of handling the return value, except in Swift it's all nice and explicit and easy to put in a conditional like:

  if let result = myObject.someOptionalMethod() { /* Do some stuff */ }
  print(myObject.someOptionalStringMethod() ?? "")

And so-on. If you need a method to be both optional, and return a nilable result then you can use a double optional like so:

  if let result = myObject.someDoubleOptionalMethod() { // Method was implemented
    if let value = result { // Method returned a value
      /* Do some stuff */
    }
  }

By defining the methods as returning an Optional and throwing in default implementations you can specify fewer, bigger protocols and make clear what the requirements really are, though personally given the choice I'd prefer a dozen smaller protocols that are absolutely explicit in what they do.

But yeah, I think the tools you need are all there already; maybe there's an argument to be made for allowing default return values on protocol methods, to reduce the boiler-plate?
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I think there is a difference between:

- A method which returns an optional result, and
- An optional method which, if present, always returns a result

Perhaps not so much of a difference at the usage site (it’s just a question of placing a ? for optional chaining), but semantically and when conforming to the protocol, they mean different things.

- Karl

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

If you don’t mind me asking, what is your use-case?

Even though I think "optional methods" and “methods returning optionals” are different things, I don’t really have any examples where optional methods are better than sub-protocols.

e.g.

// Core callbacks
protocol MyDelegate { }

// Optional callbacks, added like a mixin
protocol MyDelegateWithExtras : MyDelegate { }

// Some more optional callbacks
protocol MySubDelegate : MyDelegate {}

class DelegateImpl : MySubDelegate, MyDelegateWithExtras {
  // Implement all core + optional callbacks
}

var d : MyDelegate = DelegateImpl()

if let extras = d as? MyDelegateWithExtras {
    // invoke optional functionality
}

I don’t know what the overhead of the as? call is, but it’s almost certainly less than an Obj-C `respondsToSelector` call. Depending on whether you need to swap the delegate for objects of different types, you could also use generics to optimise the checks (and possibly more) away.

- Karl


(Charles Srstka) #19

This isn’t true; Objective-C stores a list of protocols that a class conforms to, so -respondsToSelector: does not need to be called when checking protocol conformance (also: simply adopting a protocol’s methods will not cause a class to conform to the protocol).

You can test this yourself:

#import <Foundation/Foundation.h>

@protocol P
  
- (void)foo;
  
@end

@interface C: NSObject<P>

- (void)foo;

@end

@implementation C

- (void)foo {
  NSLog(@"foo");
}

- (BOOL)respondsToSelector:(SEL)selector {
  NSLog(@"respondsToSelector: called");
  
  return [super respondsToSelector:selector];
}

@end

int main(int argc, char *argv[]) {
  @autoreleasepool {
    C *c = [C new];
    
    NSLog(@"C is P: %@", [c conformsToProtocol:@protocol(P)] ? @"YES" : @"NO");
  }
}

The output is only:

C is P: YES

The log we put in -respondsToSelector: never gets printed.

Charles

···

On Nov 15, 2016, at 7:27 PM, Karl via swift-evolution <swift-evolution@swift.org> wrote:

In Objective-C, asking whether or not an object conforms to a protocol just cascades in to a bunch of calls to “respondsToSelector”, so it’s also very painful.


(Greg Parker) #20

That's right. -conformsToProtocol: asks "does the class implementation (or some superclass thereof or category thereon) claim to conform to the protocol?" The class's method lists are not consulted.

This affects the result of -conformsToProtocol: with a protocol whose methods are all optional. Devolving to selector checks would say that all classes conform to that protocol. Honoring declared conformances as the runtime actually does gives a different answer.

This also affects the result if you add required methods to a protocol without recompiling all of the protocol's clients. Old classes will still claim to conform to the protocol, even though they might not implement the protocol's new methods.

-conformsToProtocol: is usually slower than a single -respondsToSelector: check. The latter uses the runtime's method cache while the former always walks the protocol lists of the class and all of its superclasses. But -conformsToProtocol: on a flat hierarchy with few protocols can be faster than performing multiple -respondsToSelector: checks.

···

On Nov 15, 2016, at 6:42 PM, Charles Srstka via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 15, 2016, at 7:27 PM, Karl via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

In Objective-C, asking whether or not an object conforms to a protocol just cascades in to a bunch of calls to “respondsToSelector”, so it’s also very painful.

This isn’t true; Objective-C stores a list of protocols that a class conforms to, so -respondsToSelector: does not need to be called when checking protocol conformance (also: simply adopting a protocol’s methods will not cause a class to conform to the protocol).

--
Greg Parker gparker@apple.com <mailto:gparker@apple.com> Runtime Wrangler