[Pitch] Allow closures/default params to satisfy protocol requirements


(Karl) #1

I’d like to pitch the following two language changes. Both of them are technically possible today if you manually write thunks for the relevant protocol requirements, but it would be nice if we allowed them to be written directly:

1) Allow closures to satisfy function requirements in protocols

protocol MyProtocol {
    func run(param: Int) -> String
}

struct MyStruct : MyProtocol {
    var run : (Int)->String // Satisfies requirement MyProtocol.run
}

Among other things, it would make writing type-erased wrappers in the style of AnyCollection much easier. The only obvious niggle is that the argument label wouldn’t be required when invoking the closure directly. The labels have no type-system significance, but it does make it subtly easier to write less generic code than you intend do. We could solve this by having code-completion favour protocol methods in this situation, or simply to require the label when invoking a closure which implements a known protocol requirement.

2) Allow functions with default parameters to satisfy function requirements in protocols

protocol Sportsplayer {
    func goalsScored() -> Int
}

struct SoccerPlayer: Sportsplayer {
    struct GoalType : RawOptionSet {
        static let Shot = GoalType(0x1)
        static let Volley = GoalType(0x10)
        static let Header = GoalType(0x100)
        static let Any = GoalType(0x111)
    }

    // Default value .Any means this conforms to Sportsplayer
    func goalsScored(type: GoalType = .Any) {
      //...
    }
}

struct Footballer: Sportsplayer {
    struct GoalType : RawOptionSet {
        static let Touchdown = GoalType(0x1)
        static let FieldGoal = GoalType(0x10)
        static let Any = GoalType(0x11)
    }

    // Default value .Any means this conforms to Sportsplayer
    func goalsScored(type: GoalType = .Any) {
      //...
    }
}

I often find that I want to add some optional, implementation-specific parameter to a function which implements a protocol requirement. That’s currently not possible, and it’s a bit annoying.

- Karl


Make closure properties behave like methods
Default parameter on init's should satisfy other required init's
(David Sweeris) #2

IIRC, the issue with #2 is that protocols specify declaration-site details, but default parameters are implemented at the call-site. At least I believe that statement was accurate about a year(ish) ago... Dunno if anything has changed since then.

If it can be made to work, though, I'd be in favor of it, and I think #1 as well.

- Dave Sweeris

···

On Mar 26, 2017, at 11:12, Karl Wagner via swift-evolution <swift-evolution@swift.org> wrote:

I’d like to pitch the following two language changes. Both of them are technically possible today if you manually write thunks for the relevant protocol requirements, but it would be nice if we allowed them to be written directly:

1) Allow closures to satisfy function requirements in protocols

protocol MyProtocol {
    func run(param: Int) -> String
}

struct MyStruct : MyProtocol {
    var run : (Int)->String // Satisfies requirement MyProtocol.run
}

Among other things, it would make writing type-erased wrappers in the style of AnyCollection much easier. The only obvious niggle is that the argument label wouldn’t be required when invoking the closure directly. The labels have no type-system significance, but it does make it subtly easier to write less generic code than you intend do. We could solve this by having code-completion favour protocol methods in this situation, or simply to require the label when invoking a closure which implements a known protocol requirement.

2) Allow functions with default parameters to satisfy function requirements in protocols

protocol Sportsplayer {
    func goalsScored() -> Int
}

struct SoccerPlayer: Sportsplayer {
    struct GoalType : RawOptionSet {
        static let Shot = GoalType(0x1)
        static let Volley = GoalType(0x10)
        static let Header = GoalType(0x100)
        static let Any = GoalType(0x111)
    }

    // Default value .Any means this conforms to Sportsplayer
    func goalsScored(type: GoalType = .Any) {
      //...
    }
}

struct Footballer: Sportsplayer {
    struct GoalType : RawOptionSet {
        static let Touchdown = GoalType(0x1)
        static let FieldGoal = GoalType(0x10)
        static let Any = GoalType(0x11)
    }

    // Default value .Any means this conforms to Sportsplayer
    func goalsScored(type: GoalType = .Any) {
      //...
    }
}

I often find that I want to add some optional, implementation-specific parameter to a function which implements a protocol requirement. That’s currently not possible, and it’s a bit annoying.


(Christopher Kornher) #3

A comment: Your description of #2 is a little confusing. Functions with default arguments can currently satisfy protocols. Perhaps it should be “Allow functions with extra default arguments to satisfy protocols"

I have not had the need for the features you mentioned, but it would be nice to allow them both. Having closures satisfy protocol requirements would improve support for composition.

I would like to add one: Allow protocols to define default arguments. Implementations can define default arguments in protocol implementations but that is not particularly useful for protocol oriented programming. Perhaps I should start a different thread, but these are related. Can we call it

3) Allow protocols to define default parameters

protocol P {
    func f( a:Int )
    func ff( a:Int=1 ) // Error: "Default argument not permitted..."
}

struct S : P {
    func f( a:Int=2 ) { // Currently legal, but not useful for protocol oriented programming
    }
    
    func ff( a:Int=3 ) { // A little confusing to the uninitiated perhaps, but useful
    } // and consistent with method overrides.
}

let p:P = S()

p.f() // Fails (as it should since the protocol does not have a default value)

p.ff() // Would succeed if the protocol could have a default param.
                            // I find myself wanting this behavior frequently

···

On Mar 26, 2017, at 1:04 PM, David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:

On Mar 26, 2017, at 11:12, Karl Wagner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I’d like to pitch the following two language changes. Both of them are technically possible today if you manually write thunks for the relevant protocol requirements, but it would be nice if we allowed them to be written directly:

1) Allow closures to satisfy function requirements in protocols

protocol MyProtocol {
    func run(param: Int) -> String
}

struct MyStruct : MyProtocol {
    var run : (Int)->String // Satisfies requirement MyProtocol.run
}

Among other things, it would make writing type-erased wrappers in the style of AnyCollection much easier. The only obvious niggle is that the argument label wouldn’t be required when invoking the closure directly. The labels have no type-system significance, but it does make it subtly easier to write less generic code than you intend do. We could solve this by having code-completion favour protocol methods in this situation, or simply to require the label when invoking a closure which implements a known protocol requirement.

2) Allow functions with default parameters to satisfy function requirements in protocols

protocol Sportsplayer {
    func goalsScored() -> Int
}

struct SoccerPlayer: Sportsplayer {
    struct GoalType : RawOptionSet {
        static let Shot = GoalType(0x1)
        static let Volley = GoalType(0x10)
        static let Header = GoalType(0x100)
        static let Any = GoalType(0x111)
    }

    // Default value .Any means this conforms to Sportsplayer
    func goalsScored(type: GoalType = .Any) {
      //...
    }
}

struct Footballer: Sportsplayer {
    struct GoalType : RawOptionSet {
        static let Touchdown = GoalType(0x1)
        static let FieldGoal = GoalType(0x10)
        static let Any = GoalType(0x11)
    }

    // Default value .Any means this conforms to Sportsplayer
    func goalsScored(type: GoalType = .Any) {
      //...
    }
}

I often find that I want to add some optional, implementation-specific parameter to a function which implements a protocol requirement. That’s currently not possible, and it’s a bit annoying.

IIRC, the issue with #2 is that protocols specify declaration-site details, but default parameters are implemented at the call-site. At least I believe that statement was accurate about a year(ish) ago... Dunno if anything has changed since then.

If it can be made to work, though, I'd be in favor of it, and I think #1 as well.

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


(Christopher Kornher) #4

I failed to mention that It is currently possible to create a protocol extension with a default argument, but this is not ideal. This has made the topic complex enough to warrant a new thread and I will not hijack this thread any longer. If anyone is interested, I will start a new thread for this proposal.

// Currently works
protocol P {
    func ff( a:Int )
}

extension P
{
    func ff( a:Int=1 ) {
        print( "extension method" ) // I believe that this should be in the protocol
        fatalError( "There is not sensible default implementation. This method exists to make the compiler happy" )
    }
}

struct S : P {
    func ff( a:Int) { // Does not override the extension method. Will not be called unless `a` is passed.
    }
}

let p:P = S()

p.ff() // Will crash. Calls the extension method, which is never "overridden"

···

On Mar 26, 2017, at 3:09 PM, Christopher Kornher via swift-evolution <swift-evolution@swift.org> wrote:

A comment: Your description of #2 is a little confusing. Functions with default arguments can currently satisfy protocols. Perhaps it should be “Allow functions with extra default arguments to satisfy protocols"

I have not had the need for the features you mentioned, but it would be nice to allow them both. Having closures satisfy protocol requirements would improve support for composition.

I would like to add one: Allow protocols to define default arguments. Implementations can define default arguments in protocol implementations but that is not particularly useful for protocol oriented programming. Perhaps I should start a different thread, but these are related. Can we call it

3) Allow protocols to define default parameters

protocol P {
    func f( a:Int )
    func ff( a:Int=1 ) // Error: "Default argument not permitted..."
}

struct S : P {
    func f( a:Int=2 ) { // Currently legal, but not useful for protocol oriented programming
    }
    
    func ff( a:Int=3 ) { // A little confusing to the uninitiated perhaps, but useful
    } // and consistent with method overrides.
}

let p:P = S()

p.f() // Fails (as it should since the protocol does not have a default value)

p.ff() // Would succeed if the protocol could have a default param.
                            // I find myself wanting this behavior frequently

On Mar 26, 2017, at 1:04 PM, David Sweeris via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Mar 26, 2017, at 11:12, Karl Wagner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I’d like to pitch the following two language changes. Both of them are technically possible today if you manually write thunks for the relevant protocol requirements, but it would be nice if we allowed them to be written directly:

1) Allow closures to satisfy function requirements in protocols

protocol MyProtocol {
    func run(param: Int) -> String
}

struct MyStruct : MyProtocol {
    var run : (Int)->String // Satisfies requirement MyProtocol.run
}

Among other things, it would make writing type-erased wrappers in the style of AnyCollection much easier. The only obvious niggle is that the argument label wouldn’t be required when invoking the closure directly. The labels have no type-system significance, but it does make it subtly easier to write less generic code than you intend do. We could solve this by having code-completion favour protocol methods in this situation, or simply to require the label when invoking a closure which implements a known protocol requirement.

2) Allow functions with default parameters to satisfy function requirements in protocols

protocol Sportsplayer {
    func goalsScored() -> Int
}

struct SoccerPlayer: Sportsplayer {
    struct GoalType : RawOptionSet {
        static let Shot = GoalType(0x1)
        static let Volley = GoalType(0x10)
        static let Header = GoalType(0x100)
        static let Any = GoalType(0x111)
    }

    // Default value .Any means this conforms to Sportsplayer
    func goalsScored(type: GoalType = .Any) {
      //...
    }
}

struct Footballer: Sportsplayer {
    struct GoalType : RawOptionSet {
        static let Touchdown = GoalType(0x1)
        static let FieldGoal = GoalType(0x10)
        static let Any = GoalType(0x11)
    }

    // Default value .Any means this conforms to Sportsplayer
    func goalsScored(type: GoalType = .Any) {
      //...
    }
}

I often find that I want to add some optional, implementation-specific parameter to a function which implements a protocol requirement. That’s currently not possible, and it’s a bit annoying.

IIRC, the issue with #2 is that protocols specify declaration-site details, but default parameters are implemented at the call-site. At least I believe that statement was accurate about a year(ish) ago... Dunno if anything has changed since then.

If it can be made to work, though, I'd be in favor of it, and I think #1 as well.

- Dave Sweeris
_______________________________________________
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


(Slava Pestov) #5

I’d like to pitch the following two language changes. Both of them are technically possible today if you manually write thunks for the relevant protocol requirements, but it would be nice if we allowed them to be written directly:

1) Allow closures to satisfy function requirements in protocols

I have mixed feelings about this one because of the argument labels issue.

2) Allow functions with default parameters to satisfy function requirements in protocols

This would be an excellent improvement. I don’t think it needs an SE proposal, it is “obvious” how it would work.

I would also add the following for full generality:

3) Allow enum cases without payloads to satisfy static read-only property requirements
4) Allow enum cases with payloads to satisfy static method requirements

Slava

···

On Mar 26, 2017, at 11:12 AM, Karl Wagner via swift-evolution <swift-evolution@swift.org> wrote:


(Slava Pestov) #6

Sent from my iPad

I’d like to pitch the following two language changes. Both of them are technically possible today if you manually write thunks for the relevant protocol requirements, but it would be nice if we allowed them to be written directly:

1) Allow closures to satisfy function requirements in protocols

I have mixed feelings about this one because of the argument labels issue.

2) Allow functions with default parameters to satisfy function requirements in protocols

This would be an excellent improvement. I don’t think it needs an SE proposal, it is “obvious” how it would work.

I would also add the following for full generality:

3) Allow enum cases without payloads to satisfy static read-only property requirements
4) Allow enum cases with payloads to satisfy static method requirements

I was just thinking about these the other day. Good to know you're already thinking about them!

Want to try your hand at implementing them? :wink: Would be a good starter project for diving into Sema and SILGen. I can give pointers and guidance.

Slava

···

On Mar 26, 2017, at 5:32 PM, Matthew Johnson <matthew@anandabits.com> wrote:
On Mar 26, 2017, at 7:03 PM, Slava Pestov via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Mar 26, 2017, at 11:12 AM, Karl Wagner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Slava

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


(Matthew Johnson) #7

I’d like to pitch the following two language changes. Both of them are technically possible today if you manually write thunks for the relevant protocol requirements, but it would be nice if we allowed them to be written directly:

1) Allow closures to satisfy function requirements in protocols

I have mixed feelings about this one because of the argument labels issue.

2) Allow functions with default parameters to satisfy function requirements in protocols

This would be an excellent improvement. I don’t think it needs an SE proposal, it is “obvious” how it would work.

I would also add the following for full generality:

3) Allow enum cases without payloads to satisfy static read-only property requirements
4) Allow enum cases with payloads to satisfy static method requirements

I was just thinking about these the other day. Good to know you're already thinking about them!

···

Sent from my iPad

On Mar 26, 2017, at 7:03 PM, Slava Pestov via swift-evolution <swift-evolution@swift.org> wrote:

On Mar 26, 2017, at 11:12 AM, Karl Wagner via swift-evolution <swift-evolution@swift.org> wrote:

Slava

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


(Xiaodi Wu) #8

I'm in favor of both of these.

However, the issue outlined in (1) with respect to labels is problematic.
The core team's post-Swift 3 plan (
https://lists.swift.org/pipermail/swift-evolution-announce/2016-July/000233.html)
for evolving from SE-0111 solves that problem without the need to invent
new rules for (1). IMO, that issue should be addressed first, then (1).

···

On Sun, Mar 26, 2017 at 14:04 David Sweeris via swift-evolution < swift-evolution@swift.org> wrote:

On Mar 26, 2017, at 11:12, Karl Wagner via swift-evolution < > swift-evolution@swift.org> wrote:

I’d like to pitch the following two language changes. Both of them are
technically possible today if you manually write thunks for the relevant
protocol requirements, but it would be nice if we allowed them to be
written directly:

1) Allow closures to satisfy function requirements in protocols

protocol MyProtocol {
    func run(param: Int) -> String
}
struct MyStruct : MyProtocol {
    var run : (Int)->String // Satisfies requirement MyProtocol.run}

Among other things, it would make writing type-erased wrappers in the
style of AnyCollection much easier. The only obvious niggle is that the
argument label wouldn’t be required when invoking the closure directly. The
labels have no type-system significance, but it does make it subtly easier
to write less generic code than you intend do. We could solve this by
having code-completion favour protocol methods in this situation, or simply
to require the label when invoking a closure which implements a known
protocol requirement.

2) Allow functions with default parameters to satisfy function
requirements in protocols

protocol Sportsplayer {
    func goalsScored() -> Int
}
struct SoccerPlayer: Sportsplayer {
    struct GoalType : RawOptionSet {
        static let Shot = GoalType(0x1)
        static let Volley = GoalType(0x10)
        static let Header = GoalType(0x100)
        static let Any = GoalType(0x111)
    }

    // Default value .Any means this conforms to Sportsplayer func goalsScored(type: GoalType = .Any) {
      //... }
}
struct Footballer: Sportsplayer {
    struct GoalType : RawOptionSet {
        static let Touchdown = GoalType(0x1)
        static let FieldGoal = GoalType(0x10)
        static let Any = GoalType(0x11)
    }

    // Default value .Any means this conforms to Sportsplayer func goalsScored(type: GoalType = .Any) {
      //... }
}

I often find that I want to add some optional, implementation-specific
parameter to a function which implements a protocol requirement. That’s
currently not possible, and it’s a bit annoying.

IIRC, the issue with #2 is that protocols specify declaration-site
details, but default parameters are implemented at the call-site. At least
I believe that statement was accurate about a year(ish) ago... Dunno if
anything has changed since then.

If it can be made to work, though, I'd be in favor of it, and I think #1
as well.

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


(Matthew Johnson) #9

Sent from my iPad

I’d like to pitch the following two language changes. Both of them are technically possible today if you manually write thunks for the relevant protocol requirements, but it would be nice if we allowed them to be written directly:

1) Allow closures to satisfy function requirements in protocols

I have mixed feelings about this one because of the argument labels issue.

2) Allow functions with default parameters to satisfy function requirements in protocols

This would be an excellent improvement. I don’t think it needs an SE proposal, it is “obvious” how it would work.

I would also add the following for full generality:

3) Allow enum cases without payloads to satisfy static read-only property requirements
4) Allow enum cases with payloads to satisfy static method requirements

I was just thinking about these the other day. Good to know you're already thinking about them!

Want to try your hand at implementing them? :wink: Would be a good starter project for diving into Sema and SILGen. I can give pointers and guidance.

I’d love to but alas I have too many projects and too little time already. :slight_smile:

···

On Mar 26, 2017, at 8:01 PM, Slava Pestov <spestov@apple.com> wrote:

On Mar 26, 2017, at 5:32 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:
On Mar 26, 2017, at 7:03 PM, Slava Pestov via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Mar 26, 2017, at 11:12 AM, Karl Wagner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Slava

Slava

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


(Adrian Zubarev) #10

I really like the roadmap the core team has come up with. The only critic I personally would have is the need of the comma in var op(lhs:,rhs:) : (Int, Int) -> Int. To me it would be consistent enough with selectors if there wasn’t any comma var op(lhs:rhs:) : (Int, Int) -> Int.

I have a few questions about pitch #1.

Assuming we’ll get that functionality, both var and let should satisfy the protocol requirements right?

Will this example be valid?

@objc protocol P : class {
    @objc optional func foo()
}

class A : NSObject, P {
    var foo: (() -> Void)? = nil
}

A.init().foo?()
If it is valid, could we potentially get optional functions in pure Swift as well?

···

--
Adrian Zubarev
Sent with Airmail

Am 26. März 2017 um 22:11:19, Xiaodi Wu via swift-evolution (swift-evolution@swift.org) schrieb:

I'm in favor of both of these.

However, the issue outlined in (1) with respect to labels is problematic. The core team's post-Swift 3 plan (https://lists.swift.org/pipermail/swift-evolution-announce/2016-July/000233.html) for evolving from SE-0111 solves that problem without the need to invent new rules for (1). IMO, that issue should be addressed first, then (1).
On Sun, Mar 26, 2017 at 14:04 David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:

On Mar 26, 2017, at 11:12, Karl Wagner via swift-evolution <swift-evolution@swift.org> wrote:

I’d like to pitch the following two language changes. Both of them are technically possible today if you manually write thunks for the relevant protocol requirements, but it would be nice if we allowed them to be written directly:

1) Allow closures to satisfy function requirements in protocols

protocol MyProtocol {
    func run(param: Int) -> String
}

struct MyStruct : MyProtocol {
    var run : (Int)->String // Satisfies requirement MyProtocol.run
}

Among other things, it would make writing type-erased wrappers in the style of AnyCollection much easier. The only obvious niggle is that the argument label wouldn’t be required when invoking the closure directly. The labels have no type-system significance, but it does make it subtly easier to write less generic code than you intend do. We could solve this by having code-completion favour protocol methods in this situation, or simply to require the label when invoking a closure which implements a known protocol requirement.

2) Allow functions with default parameters to satisfy function requirements in protocols

protocol Sportsplayer {
    func goalsScored() -> Int
}

struct SoccerPlayer: Sportsplayer {
    struct GoalType : RawOptionSet {
        static let Shot = GoalType(0x1)
        static let Volley = GoalType(0x10)
        static let Header = GoalType(0x100)
        static let Any = GoalType(0x111)
    }

    // Default value .Any means this conforms to Sportsplayer
    func goalsScored(type: GoalType = .Any) {
      //...
    }
}

struct Footballer: Sportsplayer {
    struct GoalType : RawOptionSet {
        static let Touchdown = GoalType(0x1)
        static let FieldGoal = GoalType(0x10)
        static let Any = GoalType(0x11)
    }

    // Default value .Any means this conforms to Sportsplayer
    func goalsScored(type: GoalType = .Any) {
      //...
    }
}

I often find that I want to add some optional, implementation-specific parameter to a function which implements a protocol requirement. That’s currently not possible, and it’s a bit annoying.

IIRC, the issue with #2 is that protocols specify declaration-site details, but default parameters are implemented at the call-site. At least I believe that statement was accurate about a year(ish) ago... Dunno if anything has changed since then.

If it can be made to work, though, I'd be in favor of it, and I think #1 as well.

- Dave Sweeris
_______________________________________________
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


(David Hart) #11

Can’t promise I’m up to the task as I have only dipped my toes in AST and Sema but can give it a try if you want.

···

On 27 Mar 2017, at 16:28, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Mar 26, 2017, at 8:01 PM, Slava Pestov <spestov@apple.com <mailto:spestov@apple.com>> wrote:

On Mar 26, 2017, at 5:32 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

Sent from my iPad

On Mar 26, 2017, at 7:03 PM, Slava Pestov via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Mar 26, 2017, at 11:12 AM, Karl Wagner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I’d like to pitch the following two language changes. Both of them are technically possible today if you manually write thunks for the relevant protocol requirements, but it would be nice if we allowed them to be written directly:

1) Allow closures to satisfy function requirements in protocols

I have mixed feelings about this one because of the argument labels issue.

2) Allow functions with default parameters to satisfy function requirements in protocols

This would be an excellent improvement. I don’t think it needs an SE proposal, it is “obvious” how it would work.

I would also add the following for full generality:

3) Allow enum cases without payloads to satisfy static read-only property requirements
4) Allow enum cases with payloads to satisfy static method requirements

I was just thinking about these the other day. Good to know you're already thinking about them!

Want to try your hand at implementing them? :wink: Would be a good starter project for diving into Sema and SILGen. I can give pointers and guidance.

I’d love to but alas I have too many projects and too little time already. :slight_smile:

Slava

Slava

_______________________________________________
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


(Slava Pestov) #12

Assuming we’ll get that functionality, both var and let should satisfy the protocol requirements right?

In theory, there’s no reason not to allow that.

If it is valid, could we potentially get optional functions in pure Swift as well?

I mean, you can already do this:

protocol P {
  var optionalRequirement: ((Int) -> ())? { get }
}

extension P {
  // “default implementation"
  var optionalRequirement: ((Int) -> ())? { return nil }
}

struct A : P {}

struct B : P {
  let optionalRequirement: ((Int) -> ())? = { (x: Int) in print(x) }
}

But it’s kind of tacky.

If you think about it, “optional requirement” is an oxymoron. What’s your use-case?

Slava

···

On Mar 27, 2017, at 1:48 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:


(Adrian Zubarev) #13

It’s probably the influence from iOS development where I have delegate protocols like this one:

@objc public protocol _ContainerViewControllerDelegate: class {
     
    @objc optional func containerViewController(_ containerViewController: ContainerViewController,
                                                willPerform operation: ContainerViewController.Operation,
                                                from oldViewController: UIViewController,
                                                to newViewController: UIViewController,
                                                animated: Bool)
     
    @objc optional func containerViewController(_ containerViewController: ContainerViewController,
                                                didPerform operation: ContainerViewController.Operation,
                                                from oldViewController: UIViewController,
                                                to newViewController: UIViewController,
                                                animated: Bool)
     
    @objc optional func containerViewController(_ containerViewController: ContainerViewController,
                                                willSet oldViewControllers: [UIViewController],
                                                to newViewControllers: [UIViewController],
                                                animated: Bool)
     
    @objc optional func containerViewController(_ containerViewController: ContainerViewController,
                                                didSet newViewControllers: [UIViewController],
                                                from oldViewControllers: [UIViewController],
                                                animated: Bool)
}
Implementing noops for each function in an extension seems kind of a wrong decision for a few reasons:

They don’t make sense, because either the receiver implements a function or not. So optional functions provide a more natural solution to that problem.

We don’t have to pass unnecessarily any arguments to the top functions.

(Personal preference) I tend to avoid @objc in general.

I think there was some technical reason why we don’t have optional functions in pure Swift yet, something that also affects dynamic if I’m not mistaken.

Think of the protocol from above as of an existential of a set of functions. The problem is that, I don’t want to introduce a standalone protocol for every function, so the client can decide which protocol it will conform to to avoid these noops. Furthermore, it’s way easier to check for an optional function in your control flow instead of dealing with default values delegate functions with a more complex return type might have.

···

--
Adrian Zubarev
Sent with Airmail

Am 28. März 2017 um 07:31:50, Slava Pestov (spestov@apple.com) schrieb:

On Mar 27, 2017, at 1:48 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

Assuming we’ll get that functionality, both var and let should satisfy the protocol requirements right?

In theory, there’s no reason not to allow that.

If it is valid, could we potentially get optional functions in pure Swift as well?

I mean, you can already do this:

protocol P {
var optionalRequirement: ((Int) -> ())? { get }
}

extension P {
// “default implementation"
var optionalRequirement: ((Int) -> ())? { return nil }
}

struct A : P {}

struct B : P {
let optionalRequirement: ((Int) -> ())? = { (x: Int) in print(x) }
}

But it’s kind of tacky.

If you think about it, “optional requirement” is an oxymoron. What’s your use-case?

Slava


(Karl) #14

Thanks for that link, it definitely solves the label issue, and even some label issues I didn't consider; for example, you couldn't implement BidirectionalCollection using closures without it:
  
let index: (Index)->Index // should be index(before:)
  
let index: (Index)->Index // should be index(after:)
  
I'm wondering: if somebody were to implement that amendment , would it require an evolution proposal? Presumably not, since the amendment is part of the condition under which SE-0111 was accepted, right?
  
- Karl

···

  
On Mar 26, 2017 at 10:11 pm, <Xiaodi Wu (mailto:xiaodi.wu@gmail.com)> wrote:
  
I'm in favor of both of these.
  
However, the issue outlined in (1) with respect to labels is problematic. The core team's post-Swift 3 plan (https://lists.swift.org/pipermail/swift-evolution-announce/2016-July/000233.html) for evolving from SE-0111 solves that problem without the need to invent new rules for (1). IMO, that issue should be addressed first, then (1).
  
On Sun, Mar 26, 2017 at 14:04 David Sweeris via swift-evolution <swift-evolution@swift.org (mailto:swift-evolution@swift.org)> wrote:
  
>
>
>
>
> On Mar 26, 2017, at 11:12, Karl Wagner via swift-evolution <swift-evolution@swift.org (mailto:swift-evolution@swift.org)> wrote:
>
>
> > I’d like to pitch the following two language changes. Both of them are technically possible today if you manually write thunks for the relevant protocol requirements, but it would be nice if we allowed them to be written directly:
> >
> >
> > 1) Allow closures to satisfy function requirements in protocols
> >
> >
> >
> > >
> > >
> > > protocol MyProtocol { func run(param: Int) -> String } struct MyStruct : MyProtocol { var run : (Int)->String // Satisfies requirement MyProtocol.run }
> > >
> > >
> > >
> > > Among other things, it would make writing type-erased wrappers in the style of AnyCollection much easier. The only obvious niggle is that the argument label wouldn’t be required when invoking the closure directly. The labels have no type-system significance, but it does make it subtly easier to write less generic code than you intend do. We could solve this by having code-completion favour protocol methods in this situation, or simply to require the label when invoking a closure which implements a known protocol requirement.
> >
> > >
> > >
> > > 2) Allow functions with default parameters to satisfy function requirements in protocols
> >
> >
> > >
> > >
> > > protocol Sportsplayer { func goalsScored() -> Int } struct SoccerPlayer: Sportsplayer { struct GoalType : RawOptionSet { static let Shot = GoalType(0x1) static let Volley = GoalType(0x10) static let Header = GoalType(0x100) static let Any = GoalType(0x111) } // Default value .Any means this conforms to Sportsplayer func goalsScored(type: GoalType = .Any) { //... } } struct Footballer: Sportsplayer { struct GoalType : RawOptionSet { static let Touchdown = GoalType(0x1) static let FieldGoal = GoalType(0x10) static let Any = GoalType(0x11) } // Default value .Any means this conforms to Sportsplayer func goalsScored(type: GoalType = .Any) { //... } }
> > >
> > >
> > >
> > > I often find that I want to add some optional, implementation-specific parameter to a function which implements a protocol requirement. That’s currently not possible, and it’s a bit annoying.
> > >
> >
>
>
>
> IIRC, the issue with #2 is that protocols specify declaration-site details, but default parameters are implemented at the call-site. At least I believe that statement was accurate about a year(ish) ago... Dunno if anything has changed since then.
>
>
>
> If it can be made to work, though, I'd be in favor of it, and I think #1 as well.
>
>
>
> - Dave Sweeris
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org (mailto:swift-evolution@swift.org)
> https://lists.swift.org/mailman/listinfo/swift-evolution
>


(Adrian Zubarev) #15

Theoretically speaking optional could potentially become some language sugar right?

protocol P {
    // Variable with label
    var foo(a:) : ((Int) -> Void)? { get }
     
    // more sugared version
    var foo: ((a: Int) -> Void)? { get }
}

extension P {
    // (1)
    var foo: ((a: Int) -> Void)? { return nil }
}

// Everything from above with even more sugar
protocol P {
    // default implementation (1) is inferred
    optional func foo(a: Int)
}

···

--
Adrian Zubarev
Sent with Airmail


(Slava Pestov) #16

It’s probably the influence from iOS development where I have delegate protocols like this one:

@objc public protocol _ContainerViewControllerDelegate: class {
     
    @objc optional func containerViewController(_ containerViewController: ContainerViewController,
                                                willPerform operation: ContainerViewController.Operation,
                                                from oldViewController: UIViewController,
                                                to newViewController: UIViewController,
                                                animated: Bool)
     
    @objc optional func containerViewController(_ containerViewController: ContainerViewController,
                                                didPerform operation: ContainerViewController.Operation,
                                                from oldViewController: UIViewController,
                                                to newViewController: UIViewController,
                                                animated: Bool)
     
    @objc optional func containerViewController(_ containerViewController: ContainerViewController,
                                                willSet oldViewControllers: [UIViewController],
                                                to newViewControllers: [UIViewController],
                                                animated: Bool)
     
    @objc optional func containerViewController(_ containerViewController: ContainerViewController,
                                                didSet newViewControllers: [UIViewController],
                                                from oldViewControllers: [UIViewController],
                                                animated: Bool)
}

This looks like a bad API to begin with. If I was designing something like this I would instead have a single containerViewController() method or something that takes a value which encodes the various states.

You could have something like this:

enum ViewControllerState {
  case willPerform(…)
  case didPerform(…)
  case willSet(…)
  case didSet(…)
}

Slava

···

On Mar 28, 2017, at 12:10 AM, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:
Implementing noops for each function in an extension seems kind of a wrong decision for a few reasons:

They don’t make sense, because either the receiver implements a function or not. So optional functions provide a more natural solution to that problem.

We don’t have to pass unnecessarily any arguments to the top functions.

(Personal preference) I tend to avoid @objc in general.

I think there was some technical reason why we don’t have optional functions in pure Swift yet, something that also affects dynamic if I’m not mistaken.

Think of the protocol from above as of an existential of a set of functions. The problem is that, I don’t want to introduce a standalone protocol for every function, so the client can decide which protocol it will conform to to avoid these noops. Furthermore, it’s way easier to check for an optional function in your control flow instead of dealing with default values delegate functions with a more complex return type might have.

--
Adrian Zubarev
Sent with Airmail

Am 28. März 2017 um 07:31:50, Slava Pestov (spestov@apple.com <mailto:spestov@apple.com>) schrieb:

On Mar 27, 2017, at 1:48 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Assuming we’ll get that functionality, both var and let should satisfy the protocol requirements right?

In theory, there’s no reason not to allow that.

If it is valid, could we potentially get optional functions in pure Swift as well?

I mean, you can already do this:

protocol P {
  var optionalRequirement: ((Int) -> ())? { get }
}

extension P {
  // “default implementation"
  var optionalRequirement: ((Int) -> ())? { return nil }
}

struct A : P {}

struct B : P {
  let optionalRequirement: ((Int) -> ())? = { (x: Int) in print(x) }
}

But it’s kind of tacky.

If you think about it, “optional requirement” is an oxymoron. What’s your use-case?

Slava


(Xiaodi Wu) #17

The core team did call it a future "purely additive proposal"--implying
that there does need to be one written. I do believe that someone did make
a start at implementing compound names, which was not merged as-is because
there has been no proposal. Should be an easy and uncontroversial one to
write though.

···

On Tue, Mar 28, 2017 at 16:27 Karl Wagner <razielim@gmail.com> wrote:

Thanks for that link, it definitely solves the label issue, and even some
label issues I didn't consider; for example, you couldn't implement
BidirectionalCollection using closures without it:

let index: (Index)->Index // should be index(before:)
let index: (Index)->Index // should be index(after:)

I'm wondering: if somebody were to implement that amendment , would it
require an evolution proposal? Presumably not, since the amendment is part
of the condition under which SE-0111 was accepted, right?

- Karl

On Mar 26, 2017 at 10:11 pm, <Xiaodi Wu <xiaodi.wu@gmail.com>> wrote:

I'm in favor of both of these.

However, the issue outlined in (1) with respect to labels is problematic.
The core team's post-Swift 3 plan (
https://lists.swift.org/pipermail/swift-evolution-announce/2016-July/000233.html)
for evolving from SE-0111 solves that problem without the need to invent
new rules for (1). IMO, that issue should be addressed first, then (1).
On Sun, Mar 26, 2017 at 14:04 David Sweeris via swift-evolution < > swift-evolution@swift.org> wrote:

On Mar 26, 2017, at 11:12, Karl Wagner via swift-evolution < > swift-evolution@swift.org> wrote:

I’d like to pitch the following two language changes. Both of them are
technically possible today if you manually write thunks for the relevant
protocol requirements, but it would be nice if we allowed them to be
written directly:

1) Allow closures to satisfy function requirements in protocols

protocol MyProtocol {
    func run(param: Int) -> String
}
struct MyStruct : MyProtocol {
    var run : (Int)->String // Satisfies requirement MyProtocol.run}

Among other things, it would make writing type-erased wrappers in the
style of AnyCollection much easier. The only obvious niggle is that the
argument label wouldn’t be required when invoking the closure directly. The
labels have no type-system significance, but it does make it subtly easier
to write less generic code than you intend do. We could solve this by
having code-completion favour protocol methods in this situation, or simply
to require the label when invoking a closure which implements a known
protocol requirement.

2) Allow functions with default parameters to satisfy function
requirements in protocols

protocol Sportsplayer {
    func goalsScored() -> Int
}
struct SoccerPlayer: Sportsplayer {
    struct GoalType : RawOptionSet {
        static let Shot = GoalType(0x1)
        static let Volley = GoalType(0x10)
        static let Header = GoalType(0x100)
        static let Any = GoalType(0x111)
    }

    // Default value .Any means this conforms to Sportsplayer func goalsScored(type: GoalType = .Any) {
      //... }
}
struct Footballer: Sportsplayer {
    struct GoalType : RawOptionSet {
        static let Touchdown = GoalType(0x1)
        static let FieldGoal = GoalType(0x10)
        static let Any = GoalType(0x11)
    }

    // Default value .Any means this conforms to Sportsplayer func goalsScored(type: GoalType = .Any) {
      //... }
}

I often find that I want to add some optional, implementation-specific
parameter to a function which implements a protocol requirement. That’s
currently not possible, and it’s a bit annoying.

IIRC, the issue with #2 is that protocols specify declaration-site
details, but default parameters are implemented at the call-site. At least
I believe that statement was accurate about a year(ish) ago... Dunno if
anything has changed since then.

If it can be made to work, though, I'd be in favor of it, and I think #1
as well.

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


(Adrian Zubarev) #18

I will consider your advice, it’s actually a replay good one. :slight_smile: I guess it was the iOS development influence from Objective-C that let me write such not swifty delegates.

···

--
Adrian Zubarev
Sent with Airmail

Am 29. März 2017 um 04:07:38, Slava Pestov (spestov@apple.com) schrieb:

On Mar 28, 2017, at 12:10 AM, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

It’s probably the influence from iOS development where I have delegate protocols like this one:

@objc public protocol _ContainerViewControllerDelegate: class {
      
    @objc optional func containerViewController(_ containerViewController: ContainerViewController,
                                                willPerform operation: ContainerViewController.Operation,
                                                from oldViewController: UIViewController,
                                                to newViewController: UIViewController,
                                                animated: Bool)
      
    @objc optional func containerViewController(_ containerViewController: ContainerViewController,
                                                didPerform operation: ContainerViewController.Operation,
                                                from oldViewController: UIViewController,
                                                to newViewController: UIViewController,
                                                animated: Bool)
      
    @objc optional func containerViewController(_ containerViewController: ContainerViewController,
                                                willSet oldViewControllers: [UIViewController],
                                                to newViewControllers: [UIViewController],
                                                animated: Bool)
      
    @objc optional func containerViewController(_ containerViewController: ContainerViewController,
                                                didSet newViewControllers: [UIViewController],
                                                from oldViewControllers: [UIViewController],
                                                animated: Bool)
}

This looks like a bad API to begin with. If I was designing something like this I would instead have a single containerViewController() method or something that takes a value which encodes the various states.

You could have something like this:

enum ViewControllerState {
case willPerform(…)
case didPerform(…)
case willSet(…)
case didSet(…)
}

Slava
Implementing noops for each function in an extension seems kind of a wrong decision for a few reasons:

They don’t make sense, because either the receiver implements a function or not. So optional functions provide a more natural solution to that problem.

We don’t have to pass unnecessarily any arguments to the top functions.

(Personal preference) I tend to avoid @objc in general.

I think there was some technical reason why we don’t have optional functions in pure Swift yet, something that also affects dynamic if I’m not mistaken.

Think of the protocol from above as of an existential of a set of functions. The problem is that, I don’t want to introduce a standalone protocol for every function, so the client can decide which protocol it will conform to to avoid these noops. Furthermore, it’s way easier to check for an optional function in your control flow instead of dealing with default values delegate functions with a more complex return type might have.

--
Adrian Zubarev
Sent with Airmail

Am 28. März 2017 um 07:31:50, Slava Pestov (spestov@apple.com) schrieb:

On Mar 27, 2017, at 1:48 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

Assuming we’ll get that functionality, both var and let should satisfy the protocol requirements right?

In theory, there’s no reason not to allow that.

If it is valid, could we potentially get optional functions in pure Swift as well?

I mean, you can already do this:

protocol P {
var optionalRequirement: ((Int) -> ())? { get }
}

extension P {
// “default implementation"
var optionalRequirement: ((Int) -> ())? { return nil }
}

struct A : P {}

struct B : P {
let optionalRequirement: ((Int) -> ())? = { (x: Int) in print(x) }
}

But it’s kind of tacky.

If you think about it, “optional requirement” is an oxymoron. What’s your use-case?

Slava


(Jon Hull) #19

I would be in favor of some sugar allowing optional methods eventually. I am kind of waiting to see how the reflection API shakes out.

I know there was some sort of argument on the list before about it being bad design to have optional methods, but I still really like it as a pattern. In swift, I tend to use optional callback closures instead of delegate methods to achieve the same pattern of enabling or disabling some feature based on whether it is there or not. For example, last week I wrote some code that lets me quickly build a table to edit data structures. When editing an array, there is an optional ‘moveCallback’ closure. If it is there, then the rows of the table can be reordered in the UI, and if it isn’t the UI doesn’t show the reordering handles. Same with ‘deleteCallback' and whether there is UI to delete a row from the array.

I think that basing behavior based on what is possible (or not possible) due to the availability of methods is very intuitive. (But then I have been programming ObjC for almost 20 years, so that may be influencing my thinking. It probably seems strange to those coming from less dynamic languages.)

Thanks,
Jon

···

On Mar 28, 2017, at 12:37 AM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

Theoretically speaking optional could potentially become some language sugar right?

protocol P {
    // Variable with label
    var foo(a:) : ((Int) -> Void)? { get }
     
    // more sugared version
    var foo: ((a: Int) -> Void)? { get }
}

extension P {
    // (1)
    var foo: ((a: Int) -> Void)? { return nil }
}

// Everything from above with even more sugar
protocol P {
    // default implementation (1) is inferred
    optional func foo(a: Int)
}

--
Adrian Zubarev
Sent with Airmail

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