[Proposal] Allow protocols to require functions with default parameter values.


(Vatsal Manot) #1

Currently, the following the code fails with multiple errors:

protocol Protocol
{
    typealias Argument
    
    func function(argument: Argument = default)
}

I propose that we allow protocols to require functions with default parameter values. I can’t see any disadvantages to this, and the change would only be additive.


(Vatsal Manot) #2

It serves as a better (if not simpler) substitute for the following pattern:

protocol Protocol
{
    typealias Argument
    
    func function()
    func function(_: Argument)
}

···

On 16-Jan-2016, at 3:29 PM, 肇鑫 <owenzx@gmail.com> wrote:

I wonder where is the good for a protocol designer on this?

zhaoxin

On Sat, Jan 16, 2016 at 5:23 PM, Vatsal Manot via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Currently, the following the code fails with multiple errors:

protocol Protocol
{
    typealias Argument

    func function(argument: Argument = default)
}

I propose that we allow protocols to require functions with default parameter values. I can’t see any disadvantages to this, and the change would only be additive.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao


(Zhao Xin) #3

Hi Vatsal,

Can you make a formal proposal on this? I think this idea is valuable and
should be discussed formally.

I think this can solved this
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006811.html>
too.

A formal proposal is like this
<https://github.com/apple/swift-evolution/blob/master/proposals/0020-if-swift-version.md>
.

You can learn how to do it here <https://github.com/apple/swift-evolution>.

zhaoxin

···

On Sat, Jan 16, 2016 at 5:23 PM, Vatsal Manot via swift-evolution < swift-evolution@swift.org> wrote:

Currently, the following the code fails with multiple errors:

protocol Protocol
{
    typealias Argument

    func function(argument: Argument = default)
}

I propose that we allow protocols to require functions with default
parameter values. I can’t see any disadvantages to this, and the change
would only be additive.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Zhao Xin) #4

No. Although you protocol's function doesn't has a default parameter value.
Your implementation does. So you don't need to define another func
function() in your protocol.

protocol Good {
    func printSomething(something:String)
}

struct Name:Good {
    func printSomething(something: String = "John") {
        print(something)
    }
}

Name().printSomething()

above code works.

zhaoxin

···

On Sat, Jan 16, 2016 at 6:05 PM, Vatsal Manot <vatsal.manot@yahoo.com> wrote:

It serves as a better (if not simpler) substitute for the following
pattern:

protocol Protocol
{
    typealias Argument

    func function()
    func function(_: Argument)
}

On 16-Jan-2016, at 3:29 PM, 肇鑫 <owenzx@gmail.com> wrote:

I wonder where is the good for a protocol designer on this?

zhaoxin

On Sat, Jan 16, 2016 at 5:23 PM, Vatsal Manot via swift-evolution < > swift-evolution@swift.org> wrote:

Currently, the following the code fails with multiple errors:

protocol Protocol
{
    typealias Argument

    func function(argument: Argument = default)
}

I propose that we allow protocols to require functions with default
parameter values. I can’t see any disadvantages to this, and the change
would only be additive.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao

--

Owen Zhao


(Haravikk) #5

I think that the point of allowing defaults in protocols is so that you can assume a default for all types conforming to that protocol. To use your example, if you receive an instance of Name, you can only call printSomething() without arguments if you test that it is an instance of type Name. If instead you test its conformance to the Good protocol (which you might do if there are a lot of different types conforming to Good) then you have to provide a value, because you can’t infer that every possible implementation will have a default.

Regarding this proposal however I think it might be useful to have a distinction between a protocol function that specifies a default value for all implementations (that they must all conform to) versus one that specifies that implementations must have a default value, but not what that value must be.

For example, to have a fixed and altered default we currently we have to do things like this:

protocol Protocol {
  func functionWithSpecificDefault(argument:String)
  func functionWithAnyDefault(argument:String)
}

extension Protocol {
  func functionWithSpecificDefault() { self.functionWithSpecificDefault(“Foo”) }
  func functionWithAnyDefault() { self.functionWithAnyDefault(“Foo”) }
}

class MyClass : Protocol {
  func functionWithSpecificDefault(argument:String) { /* Implementation here */ }
  func functionWithAnyDefault(argument:String) { /* Implementation here */ }

  func functionWithAnyDefault() { self.functionWithAnyDefault(“Bar”) } // Override default
}

Which could be replaced by:

protocol Protocol {
  func functionWithSpecificDefault(argument:String = “Foo")
  func functionWithAnyDefault(argument:String = default)
}

class MyClass : Protocol {
  func functionWithSpecificDefault(argument:String = “Foo") { /* Implementation here */ }
  func functionWithAnyDefault(argument:String = “Bar") { /* Implementation here */ }
}

However, this has the added advantage that implementing functionWithSpecificDefault with a default other than “Foo” would cause a compiler error, while doing so for functionWithAnyDefault would not (but specifying no default at all would, as one is required).

···

On 16 Jan 2016, at 10:15, 肇鑫 via swift-evolution <swift-evolution@swift.org> wrote:

No. Although you protocol's function doesn't has a default parameter value. Your implementation does. So you don't need to define another func function() in your protocol.

protocol Good {
    func printSomething(something:String)
}

struct Name:Good {
    func printSomething(something: String = "John") {
        print(something)
    }
}

Name().printSomething()

above code works.

zhaoxin

On Sat, Jan 16, 2016 at 6:05 PM, Vatsal Manot <vatsal.manot@yahoo.com <mailto:vatsal.manot@yahoo.com>> wrote:
It serves as a better (if not simpler) substitute for the following pattern:

protocol Protocol
{
    typealias Argument
    
    func function()
    func function(_: Argument)
}

On 16-Jan-2016, at 3:29 PM, 肇鑫 <owenzx@gmail.com <mailto:owenzx@gmail.com>> wrote:

I wonder where is the good for a protocol designer on this?

zhaoxin

On Sat, Jan 16, 2016 at 5:23 PM, Vatsal Manot via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Currently, the following the code fails with multiple errors:

protocol Protocol
{
    typealias Argument

    func function(argument: Argument = default)
}

I propose that we allow protocols to require functions with default parameter values. I can’t see any disadvantages to this, and the change would only be additive.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao

--

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


(David Sweeris) #6

Instead of adding stuff to the protocol declaration, can we add it to the object definition?

Right now, IMHO, there’s a bug in the way protocols and functions w/ default parameters interact (or rather, don’t)…

Say I have this protocol (which, BTW, I end up adding to a lot of my projects for providing default values):
protocol Initable {
    init()
}
// Along with most other builtin types I use
extension Int : Initable {}

and this class:
class Variable <T: Initable> {
    var value: T
    let name: String
    init(path: String = __FILE__, line: Int = __LINE__) {
        self.value = T()
        self.name = getDeclNameFromSource(path: path, line: line)
    }
    init(_ value: T, path: String = __FILE__, line: Int = __LINE__) {
        self.value = value
        self.name = getDeclNameFromSource(path: path, line: line)
    }
    init(name: String, value: T) {
        self.value = value
        self.name = name
    }
}

Now, `Initable` says* that
var x = T() // where T: Initable, of course

is valid code. Do you know what else is valid?
var x = Variable<Int>() // Hooray! Default values!

Yet, despite the fact that, from the API user’s point of view, `Variable` already has everything it needs to conform to `Initable`, you can’t write “extension Variable : Initable” without either getting a non-conformance error or, if you then add init() { fatalError() }, getting an “ambiguous expression” error wherever you actually try to call Variable(). And this is the bug: If your protocol `Foo` has a function `foo(X)`, and your type has a function `foo(Y)` where Y can be turned into X through the use of default parameters, then it’s impossible for your type to conform to `Foo`, even though you could use it as a `Foo` in your code. In practice, I think this only matters if you’re using “macros” like __LINE__ or something as your default parameter, but it’s still annoying (to me, anyway).

I think we might be able to kill two birds with one stone here… What if protocol conformance had to be declared and it was done implicitly for anything for which there was already a perfect match?
extension Int : Initable {
    // Implicitly generated because Int.init() (with no default parameters) already exists
    conformance {
  //(protocol_identifier).(requirement_indentifer) = (expression)
        Initable.init() = init() // or really any expression that evaluates to an Int
    }
}

Then we could get both your default parameter support (I think) and fix this “bug of non-intuitivity” (which people keep telling me isn’t really a bug because of what protocols actually mean*) simply by being able to explicitly write it out:
class Variable <T: Initable> : Initable {
    // Must be explicitly written, since in this case there’s no literal match
    conformance {
        Initable.init() = init(_ value: T, path: String = __FILE__, line: Int = __LINE__)
    }
    …
}

In theory, we could also use this for optimizations:
private let _default_int_: Int = 0
extension Int : Initable {
    conformance {
        Initable.init() = _default_int_ //why bother with a function call when you could substitute a constant?
    }
}

I don’t know how deep into the compiler this “conformance” clause would have to be carried… The generic specializer would certainly need it, but I don’t know enough about how that works to say how much this would actually change anything…

- Dave Sweeris

* Yes, I know that protocol conformance is about the actual function signatures and not just what the compiler can deduce… My point is that, IMHO, it’s counter-intuitive to be able to get the same “user-level” signature, but not be able to semantically express that to the compiler.

···

On Jan 16, 2016, at 03:35, Goffredo Marocchi via swift-evolution <swift-evolution@swift.org> wrote:

I still think that, except in certain very generic cases, default methods are something I would be wary of being easily abused.

Protocols, Java style interfaces, they allow users to focus only on a generic behaviour/contract without having to rely or being able to rely and/or make bonding assumptions on any implementation details of the type conforming to the protocol. Default methods in a protocol still seem to go in the opposite direction although they do offer a lot of convenience and open up new styles.

Sent from my iPhone

On 16 Jan 2016, at 11:04, Haravikk via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I think that the point of allowing defaults in protocols is so that you can assume a default for all types conforming to that protocol. To use your example, if you receive an instance of Name, you can only call printSomething() without arguments if you test that it is an instance of type Name. If instead you test its conformance to the Good protocol (which you might do if there are a lot of different types conforming to Good) then you have to provide a value, because you can’t infer that every possible implementation will have a default.

Regarding this proposal however I think it might be useful to have a distinction between a protocol function that specifies a default value for all implementations (that they must all conform to) versus one that specifies that implementations must have a default value, but not what that value must be.

For example, to have a fixed and altered default we currently we have to do things like this:

protocol Protocol {
  func functionWithSpecificDefault(argument:String)
  func functionWithAnyDefault(argument:String)
}

extension Protocol {
  func functionWithSpecificDefault() { self.functionWithSpecificDefault(“Foo”) }
  func functionWithAnyDefault() { self.functionWithAnyDefault(“Foo”) }
}

class MyClass : Protocol {
  func functionWithSpecificDefault(argument:String) { /* Implementation here */ }
  func functionWithAnyDefault(argument:String) { /* Implementation here */ }

  func functionWithAnyDefault() { self.functionWithAnyDefault(“Bar”) } // Override default
}

Which could be replaced by:

protocol Protocol {
  func functionWithSpecificDefault(argument:String = “Foo")
  func functionWithAnyDefault(argument:String = default)
}

class MyClass : Protocol {
  func functionWithSpecificDefault(argument:String = “Foo") { /* Implementation here */ }
  func functionWithAnyDefault(argument:String = “Bar") { /* Implementation here */ }
}

However, this has the added advantage that implementing functionWithSpecificDefault with a default other than “Foo” would cause a compiler error, while doing so for functionWithAnyDefault would not (but specifying no default at all would, as one is required).

On 16 Jan 2016, at 10:15, 肇鑫 via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

No. Although you protocol's function doesn't has a default parameter value. Your implementation does. So you don't need to define another func function() in your protocol.

protocol Good {
    func printSomething(something:String)
}

struct Name:Good {
    func printSomething(something: String = "John") {
        print(something)
    }
}

Name().printSomething()

above code works.

zhaoxin

On Sat, Jan 16, 2016 at 6:05 PM, Vatsal Manot <vatsal.manot@yahoo.com <mailto:vatsal.manot@yahoo.com>> wrote:
It serves as a better (if not simpler) substitute for the following pattern:

protocol Protocol
{
    typealias Argument
    
    func function()
    func function(_: Argument)
}

On 16-Jan-2016, at 3:29 PM, 肇鑫 <owenzx@gmail.com <mailto:owenzx@gmail.com>> wrote:

I wonder where is the good for a protocol designer on this?

zhaoxin

On Sat, Jan 16, 2016 at 5:23 PM, Vatsal Manot via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Currently, the following the code fails with multiple errors:

protocol Protocol
{
    typealias Argument

    func function(argument: Argument = default)
}

I propose that we allow protocols to require functions with default parameter values. I can’t see any disadvantages to this, and the change would only be additive.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao

--

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

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

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


(Goffredo Marocchi) #7

I still think that, except in certain very generic cases, default methods are something I would be wary of being easily abused.

Protocols, Java style interfaces, they allow users to focus only on a generic behaviour/contract without having to rely or being able to rely and/or make bonding assumptions on any implementation details of the type conforming to the protocol. Default methods in a protocol still seem to go in the opposite direction although they do offer a lot of convenience and open up new styles.

···

Sent from my iPhone

On 16 Jan 2016, at 11:04, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

I think that the point of allowing defaults in protocols is so that you can assume a default for all types conforming to that protocol. To use your example, if you receive an instance of Name, you can only call printSomething() without arguments if you test that it is an instance of type Name. If instead you test its conformance to the Good protocol (which you might do if there are a lot of different types conforming to Good) then you have to provide a value, because you can’t infer that every possible implementation will have a default.

Regarding this proposal however I think it might be useful to have a distinction between a protocol function that specifies a default value for all implementations (that they must all conform to) versus one that specifies that implementations must have a default value, but not what that value must be.

For example, to have a fixed and altered default we currently we have to do things like this:

protocol Protocol {
  func functionWithSpecificDefault(argument:String)
  func functionWithAnyDefault(argument:String)
}

extension Protocol {
  func functionWithSpecificDefault() { self.functionWithSpecificDefault(“Foo”) }
  func functionWithAnyDefault() { self.functionWithAnyDefault(“Foo”) }
}

class MyClass : Protocol {
  func functionWithSpecificDefault(argument:String) { /* Implementation here */ }
  func functionWithAnyDefault(argument:String) { /* Implementation here */ }

  func functionWithAnyDefault() { self.functionWithAnyDefault(“Bar”) } // Override default
}

Which could be replaced by:

protocol Protocol {
  func functionWithSpecificDefault(argument:String = “Foo")
  func functionWithAnyDefault(argument:String = default)
}

class MyClass : Protocol {
  func functionWithSpecificDefault(argument:String = “Foo") { /* Implementation here */ }
  func functionWithAnyDefault(argument:String = “Bar") { /* Implementation here */ }
}

However, this has the added advantage that implementing functionWithSpecificDefault with a default other than “Foo” would cause a compiler error, while doing so for functionWithAnyDefault would not (but specifying no default at all would, as one is required).

On 16 Jan 2016, at 10:15, 肇鑫 via swift-evolution <swift-evolution@swift.org> wrote:

No. Although you protocol's function doesn't has a default parameter value. Your implementation does. So you don't need to define another func function() in your protocol.

protocol Good {
    func printSomething(something:String)
}

struct Name:Good {
    func printSomething(something: String = "John") {
        print(something)
    }
}

Name().printSomething()

above code works.

zhaoxin

On Sat, Jan 16, 2016 at 6:05 PM, Vatsal Manot <vatsal.manot@yahoo.com> wrote:
It serves as a better (if not simpler) substitute for the following pattern:

protocol Protocol
{
    typealias Argument
    
    func function()
    func function(_: Argument)
}

On 16-Jan-2016, at 3:29 PM, 肇鑫 <owenzx@gmail.com> wrote:

I wonder where is the good for a protocol designer on this?

zhaoxin

On Sat, Jan 16, 2016 at 5:23 PM, Vatsal Manot via swift-evolution <swift-evolution@swift.org> wrote:
Currently, the following the code fails with multiple errors:

protocol Protocol
{
    typealias Argument

    func function(argument: Argument = default)
}

I propose that we allow protocols to require functions with default parameter values. I can’t see any disadvantages to this, and the change would only be additive.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao

--

Owen Zhao
_______________________________________________
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


(Zhao Xin) #8

Vatsal thinks the default works as a default value keyword, which restricts
that the implementation of the function must have a default value. The
default value is not set in the protocol. It is a restrict keyword.

Vatsal thinks that will be a good idea, as that will make Protocol like,

protocol A {
    func foo()
    func foo(bar: String)
}

simplified as

protocol A {
    func foo(bar: String = default)
}

So if you implement protocol A

struct X:A {
    func foo(bar: String) { // will show an error as protocol A restricts a
default value
        ..
    }
}

However, there is also a pitfall here. If foo() is not a foo(bar:String)
with a default value, but some operations without using the bar parameter?
Then the logic is not the same. You can't define another func foo() as the
compiler can not distinguish from foo() to foo(bar:String = "John") with
default value.

zhaoxin

···

On Sat, Jan 16, 2016 at 7:35 PM, Goffredo Marocchi <panajev@gmail.com> wrote:

I still think that, except in certain very generic cases, default methods
are something I would be wary of being easily abused.

Protocols, Java style interfaces, they allow users to focus only on a
generic behaviour/contract without having to rely or being able to rely
and/or make bonding assumptions on any implementation details of the type
conforming to the protocol. Default methods in a protocol still seem to go
in the opposite direction although they do offer a lot of convenience and
open up new styles.

Sent from my iPhone

On 16 Jan 2016, at 11:04, Haravikk via swift-evolution < > swift-evolution@swift.org> wrote:

I think that the point of allowing defaults in protocols is so that you
can assume a default for all types conforming to that protocol. To use your
example, if you receive an instance of Name, you can only call
printSomething() without arguments if you test that it is an instance of
type Name. If instead you test its conformance to the Good protocol (which
you might do if there are a lot of different types conforming to Good) then
you have to provide a value, because you can’t infer that every possible
implementation will have a default.

Regarding this proposal however I think it might be useful to have a
distinction between a protocol function that specifies a default value for
all implementations (that they must all conform to) versus one that
specifies that implementations must have a default value, but not what that
value must be.

For example, to have a fixed and altered default we currently we have to
do things like this:

protocol Protocol {
func functionWithSpecificDefault(argument:String)
func functionWithAnyDefault(argument:String)
}

extension Protocol {
func functionWithSpecificDefault() {
self.functionWithSpecificDefault(“Foo”) }
func functionWithAnyDefault() { self.functionWithAnyDefault(“Foo”) }
}

class MyClass : Protocol {
func functionWithSpecificDefault(argument:String) { /* Implementation here
*/ }
func functionWithAnyDefault(argument:String) { /* Implementation here */ }

func functionWithAnyDefault() { self.functionWithAnyDefault(“Bar”) } //
Override default
}

Which could be replaced by:

protocol Protocol {
func functionWithSpecificDefault(argument:String = “Foo")
func functionWithAnyDefault(argument:String = default)
}

class MyClass : Protocol {
func functionWithSpecificDefault(argument:String = “Foo") { /*
Implementation here */ }
func functionWithAnyDefault(argument:String = “Bar") { /* Implementation
here */ }
}

However, this has the added advantage that implementing
functionWithSpecificDefault with a default other than “Foo” would cause a
compiler error, while doing so for functionWithAnyDefault would not (but
specifying no default at all would, as one is required).

On 16 Jan 2016, at 10:15, 肇鑫 via swift-evolution < > swift-evolution@swift.org> wrote:

No. Although you protocol's function doesn't has a default parameter
value. Your implementation does. So you don't need to define another func
function() in your protocol.

protocol Good {
    func printSomething(something:String)
}

struct Name:Good {
    func printSomething(something: String = "John") {
        print(something)
    }
}

Name().printSomething()

above code works.

zhaoxin

On Sat, Jan 16, 2016 at 6:05 PM, Vatsal Manot <vatsal.manot@yahoo.com> > wrote:

It serves as a better (if not simpler) substitute for the following
pattern:

protocol Protocol
{
    typealias Argument

    func function()
    func function(_: Argument)
}

On 16-Jan-2016, at 3:29 PM, 肇鑫 <owenzx@gmail.com> wrote:

I wonder where is the good for a protocol designer on this?

zhaoxin

On Sat, Jan 16, 2016 at 5:23 PM, Vatsal Manot via swift-evolution < >> swift-evolution@swift.org> wrote:

Currently, the following the code fails with multiple errors:

protocol Protocol
{
    typealias Argument

    func function(argument: Argument = default)
}

I propose that we allow protocols to require functions with default
parameter values. I can’t see any disadvantages to this, and the change
would only be additive.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao

--

Owen Zhao
_______________________________________________
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


(Zhao Xin) #9

Hi Haravikk,

I just implement a func like your examples. However, I find the result is
interesting.

protocol Good {

    func printSomething(something:String)

}

extension Good {

    func printSomething() { self.printSomething("Good") }

}

struct Name:Good {

    func printSomething(something: String = "John") {

        print(something)

    }

}

struct Talk:Good {

    func printSomething(something: String = "Hahaha") {

        print(something)

    }

}

var protocols:[Good] = [Name(), Talk()]

for p in protocols {

    p.printSomething() // Good, Good instead of John, Hahaha

}

As you can see, the final result is "Good, Good", not as I expected "John,
Hahaha", is that right or is it a bug?

zhaoxin

···

On Sat, Jan 16, 2016 at 7:04 PM, Haravikk <me@haravikk.com> wrote:

I think that the point of allowing defaults in protocols is so that you
can assume a default for all types conforming to that protocol. To use your
example, if you receive an instance of Name, you can only call
printSomething() without arguments if you test that it is an instance of
type Name. If instead you test its conformance to the Good protocol (which
you might do if there are a lot of different types conforming to Good) then
you have to provide a value, because you can’t infer that every possible
implementation will have a default.

Regarding this proposal however I think it might be useful to have a
distinction between a protocol function that specifies a default value for
all implementations (that they must all conform to) versus one that
specifies that implementations must have a default value, but not what that
value must be.

For example, to have a fixed and altered default we currently we have to
do things like this:

protocol Protocol {
func functionWithSpecificDefault(argument:String)
func functionWithAnyDefault(argument:String)
}

extension Protocol {
func functionWithSpecificDefault() {
self.functionWithSpecificDefault(“Foo”) }
func functionWithAnyDefault() { self.functionWithAnyDefault(“Foo”) }
}

class MyClass : Protocol {
func functionWithSpecificDefault(argument:String) { /* Implementation here
*/ }
func functionWithAnyDefault(argument:String) { /* Implementation here */ }

func functionWithAnyDefault() { self.functionWithAnyDefault(“Bar”) } //
Override default
}

Which could be replaced by:

protocol Protocol {
func functionWithSpecificDefault(argument:String = “Foo")
func functionWithAnyDefault(argument:String = default)
}

class MyClass : Protocol {
func functionWithSpecificDefault(argument:String = “Foo") { /*
Implementation here */ }
func functionWithAnyDefault(argument:String = “Bar") { /* Implementation
here */ }
}

However, this has the added advantage that implementing
functionWithSpecificDefault with a default other than “Foo” would cause a
compiler error, while doing so for functionWithAnyDefault would not (but
specifying no default at all would, as one is required).

On 16 Jan 2016, at 10:15, 肇鑫 via swift-evolution < > swift-evolution@swift.org> wrote:

No. Although you protocol's function doesn't has a default parameter
value. Your implementation does. So you don't need to define another func
function() in your protocol.

protocol Good {
    func printSomething(something:String)
}

struct Name:Good {
    func printSomething(something: String = "John") {
        print(something)
    }
}

Name().printSomething()

above code works.

zhaoxin

On Sat, Jan 16, 2016 at 6:05 PM, Vatsal Manot <vatsal.manot@yahoo.com> > wrote:

It serves as a better (if not simpler) substitute for the following
pattern:

protocol Protocol
{
    typealias Argument

    func function()
    func function(_: Argument)
}

On 16-Jan-2016, at 3:29 PM, 肇鑫 <owenzx@gmail.com> wrote:

I wonder where is the good for a protocol designer on this?

zhaoxin

On Sat, Jan 16, 2016 at 5:23 PM, Vatsal Manot via swift-evolution < >> swift-evolution@swift.org> wrote:

Currently, the following the code fails with multiple errors:

protocol Protocol
{
    typealias Argument

    func function(argument: Argument = default)
}

I propose that we allow protocols to require functions with default
parameter values. I can’t see any disadvantages to this, and the change
would only be additive.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao

--

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


(Zhao Xin) #10

Hi Dave,

Like you said, you approach does not solve the bug.

And this is the bug: If your protocol `Foo` has a function `foo(X)`, and

your type has a function `foo(Y)` *where Y can be turned into X through
the use of default parameters*, then it’s impossible for your type to
conform to `Foo`, even though you could use it as a `Foo` in your code. In
practice, I think this only matters if you’re using “macros” like __LINE__ or something
as your default parameter, but it’s still annoying (to me, anyway).

​as this proposal does​.

I still think if we can call instance.function(), we should also call
(instance as protocol).function(). If we can't, there must be something not
right here.

zhaoxin

···

On Sun, Jan 17, 2016 at 3:32 AM, Dave via swift-evolution < swift-evolution@swift.org> wrote:

Instead of adding stuff to the protocol declaration, can we add it to the
object definition?

Right now, IMHO, there’s a bug in the way protocols and functions w/
default parameters interact (or rather, don’t)…

Say I have this protocol (which, BTW, I end up adding to a lot of my
projects for providing default values):

protocol Initable {
    init()
}
// Along with most other builtin types I use
extension Int : Initable {}

and this class:

class Variable <T: Initable> {
    var value: T
    let name: String
    init(path: String = __FILE__, line: Int = __LINE__) {
        self.value = T()
        self.name = getDeclNameFromSource(path: path, line: line)
    }
    init(_ value: T, path: String = __FILE__, line: Int = __LINE__) {
        self.value = value
        self.name = getDeclNameFromSource(path: path, line: line)
    }
    init(name: String, value: T) {
        self.value = value
        self.name = name
    }
}

Now, `Initable` says* that

var x = T() // where T: Initable, of course

is valid code. Do you know what else is valid?

var x = Variable<Int>() // Hooray! Default values!

Yet, despite the fact that, from the API user’s point of view, `Variable`
already has everything it needs to conform to `Initable`, you can’t write
“extension Variable : Initable” without either getting a non-conformance
error or, if you then add init() { fatalError() }, getting an “ambiguous
expression” error wherever you actually try to call Variable(). And this is
the bug: If your protocol `Foo` has a function `foo(X)`, and your type has
a function `foo(Y)` *where Y can be turned into X through the use of
default parameters*, then it’s impossible for your type to conform to
`Foo`, even though you could use it as a `Foo` in your code. In practice, I
think this only matters if you’re using “macros” like __LINE__ or something
as your default parameter, but it’s still annoying (to me, anyway).

I think we might be able to kill two birds with one stone here… What if
protocol conformance had to be declared *and* it was done implicitly for
anything for which there was already a perfect match?

extension Int : Initable {
    // Implicitly generated because Int.init() (with no default
parameters) already exists
    conformance {
//(protocol_identifier).(requirement_indentifer) = (expression)
        Initable.init() = init() // or really any expression that
evaluates to an Int
    }
}

Then we could get both your default parameter support (I think) *and* fix
this “bug of non-intuitivity” (which people keep telling me isn’t really a
bug because of what protocols *actually* mean*) simply by being able to
explicitly write it out:

class Variable <T: Initable> : Initable {
    // Must be explicitly written, since in this case there’s no literal
match
    conformance {
        Initable.init() = init(_ value: T, path: String = __FILE__, line:
Int = __LINE__)
    }
    …
}

In theory, we could also use this for optimizations:

private let _default_int_: Int = 0
extension Int : Initable {
    conformance {
        Initable.init() = _default_int_ //why bother with a function call
when you could substitute a constant?
    }
}

I don’t know how deep into the compiler this “conformance” clause would
have to be carried… The generic specializer would certainly need it, but I
don’t know enough about how that works to say how much this would actually
change anything…

- Dave Sweeris

* Yes, I know that protocol conformance is about the *actual* function
signatures and not just what the compiler can deduce… My point is that,
IMHO, it’s counter-intuitive to be able to get the same “user-level”
signature, but not be able to semantically express that to the compiler.

On Jan 16, 2016, at 03:35, Goffredo Marocchi via swift-evolution < > swift-evolution@swift.org> wrote:

I still think that, except in certain very generic cases, default methods
are something I would be wary of being easily abused.

Protocols, Java style interfaces, they allow users to focus only on a
generic behaviour/contract without having to rely or being able to rely
and/or make bonding assumptions on any implementation details of the type
conforming to the protocol. Default methods in a protocol still seem to go
in the opposite direction although they do offer a lot of convenience and
open up new styles.

Sent from my iPhone

On 16 Jan 2016, at 11:04, Haravikk via swift-evolution < > swift-evolution@swift.org> wrote:

I think that the point of allowing defaults in protocols is so that you
can assume a default for all types conforming to that protocol. To use your
example, if you receive an instance of Name, you can only call
printSomething() without arguments if you test that it is an instance of
type Name. If instead you test its conformance to the Good protocol (which
you might do if there are a lot of different types conforming to Good) then
you have to provide a value, because you can’t infer that every possible
implementation will have a default.

Regarding this proposal however I think it might be useful to have a
distinction between a protocol function that specifies a default value for
all implementations (that they must all conform to) versus one that
specifies that implementations must have a default value, but not what that
value must be.

For example, to have a fixed and altered default we currently we have to
do things like this:

protocol Protocol {
func functionWithSpecificDefault(argument:String)
func functionWithAnyDefault(argument:String)
}

extension Protocol {
func functionWithSpecificDefault() {
self.functionWithSpecificDefault(“Foo”) }
func functionWithAnyDefault() { self.functionWithAnyDefault(“Foo”) }
}

class MyClass : Protocol {
func functionWithSpecificDefault(argument:String) { /* Implementation here
*/ }
func functionWithAnyDefault(argument:String) { /* Implementation here */ }

func functionWithAnyDefault() { self.functionWithAnyDefault(“Bar”) } //
Override default
}

Which could be replaced by:

protocol Protocol {
func functionWithSpecificDefault(argument:String = “Foo")
func functionWithAnyDefault(argument:String = default)
}

class MyClass : Protocol {
func functionWithSpecificDefault(argument:String = “Foo") { /*
Implementation here */ }
func functionWithAnyDefault(argument:String = “Bar") { /* Implementation
here */ }
}

However, this has the added advantage that implementing
functionWithSpecificDefault with a default other than “Foo” would cause a
compiler error, while doing so for functionWithAnyDefault would not (but
specifying no default at all would, as one is required).

On 16 Jan 2016, at 10:15, 肇鑫 via swift-evolution < > swift-evolution@swift.org> wrote:

No. Although you protocol's function doesn't has a default parameter
value. Your implementation does. So you don't need to define another func
function() in your protocol.

protocol Good {
    func printSomething(something:String)
}

struct Name:Good {
    func printSomething(something: String = "John") {
        print(something)
    }
}

Name().printSomething()

above code works.

zhaoxin

On Sat, Jan 16, 2016 at 6:05 PM, Vatsal Manot <vatsal.manot@yahoo.com> > wrote:

It serves as a better (if not simpler) substitute for the following
pattern:

protocol Protocol
{
    typealias Argument

    func function()
    func function(_: Argument)
}

On 16-Jan-2016, at 3:29 PM, 肇鑫 <owenzx@gmail.com> wrote:

I wonder where is the good for a protocol designer on this?

zhaoxin

On Sat, Jan 16, 2016 at 5:23 PM, Vatsal Manot via swift-evolution < >> swift-evolution@swift.org> wrote:

Currently, the following the code fails with multiple errors:

protocol Protocol
{
    typealias Argument

    func function(argument: Argument = default)
}

I propose that we allow protocols to require functions with default
parameter values. I can’t see any disadvantages to this, and the change
would only be additive.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao

--

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

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

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

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


(David Sweeris) #11

Hi Dave,

Like you said, you approach does not solve the bug.

And this is the bug: If your protocol `Foo` has a function `foo(X)`, and your type has a function `foo(Y)` where Y can be turned into X through the use of default parameters, then it’s impossible for your type to conform to `Foo`, even though you could use it as a `Foo` in your code. In practice, I think this only matters if you’re using “macros” like __LINE__ or something as your default parameter, but it’s still annoying (to me, anyway).

​as this proposal does​.

No, I was saying that (at least at a glance) I didn’t think the original proposal solved the problem I described, and that I thought my “counter” proposal would have all the functionality (albeit from the “other direction”) that Vatsal was proposing *and* fix the glitch.

…Maybe we’re saying the same thing.

I still think if we can call instance.function(), we should also call (instance as protocol).function(). If we can't, there must be something not right here.

zhaoxin

You can, as long as your protocol isn’t restricted to only being used as a generic constraint (no Self or typealiases):
protocol Foo {
    func foo() -> String
}

extension Int : Foo {
    func foo() -> String { return "lovely" }
}

func bar(x: Any) -> String {
    if x is Foo { return "Here, have some \((x as! Foo).foo()) foo." }
    else { return "NO FOO FOR YOU!!!" }
}

print(bar(0)) //Here, have some lovely foo.
print(bar("")) //NO FOO FOR YOU!!!

- Dave Sweeris

···

On Jan 16, 2016, at 17:28, 肇鑫 <owenzx@gmail.com> wrote:


(Zhao Xin) #12

Hi Dave,

If you have read the whole list, you can find this proposal is trying to
simplify a Protocol like:

protocol A {

    func printSomething()

    func printSomething(something:String)

}

to

protocol B {

    func printSomething(something:String = default) // default is a
keyword, not a certain value, meaning the implementation must have a
default parameter value

}

So that we can solve the previous talking bug. Protocol B can use both
printSomething() and printSomething("john")

Currently, if we only have

protocol C {

    func printSomething(something:String)

}

We can not call printSomething() with protocol c.

zhaoxin

···

On Sun, Jan 17, 2016 at 9:51 AM, <davesweeris@mac.com> wrote:

On Jan 16, 2016, at 17:28, 肇鑫 <owenzx@gmail.com> wrote:

Hi Dave,

Like you said, you approach does not solve the bug.

And this is the bug: If your protocol `Foo` has a function `foo(X)`, and

your type has a function `foo(Y)` *where Y can be turned into X through
the use of default parameters*, then it’s impossible for your type to
conform to `Foo`, even though you could use it as a `Foo` in your code. In
practice, I think this only matters if you’re using “macros” like
__LINE__ or something as your default parameter, but it’s still annoying
(to me, anyway).

​as this proposal does​.

No, I was saying that (at least at a glance) I didn’t think the original
proposal solved the problem I described, and that I thought my “counter”
proposal would have all the functionality (albeit from the “other
direction”) that Vatsal was proposing *and* fix the glitch.

…Maybe we’re saying the same thing.

I still think if we can call instance.function(), we should also call
(instance as protocol).function(). If we can't, there must be something not
right here.

zhaoxin

You can, as long as your protocol isn’t restricted to only being used as a
generic constraint (no Self or typealiases):

protocol Foo {
    func foo() -> String
}

extension Int : Foo {
    func foo() -> String { return "lovely" }
}

func bar(x: Any) -> String {
    if x is Foo { return "Here, have some \((x as! Foo).foo()) foo." }
    else { return "NO FOO FOR YOU!!!" }
}

print(bar(0)) //Here, have some lovely foo.
print(bar("")) //NO FOO FOR YOU!!!

- Dave Sweeris


(Sune Foldager) #13

I’m -1 on this feature. Default values is basically compile sugar for not filling in the value at the call site. The protocol should clearly state its purpose and not constrain its implementations with stuff like this.

Also, the reason you’re getting “Good, Good” below is probably because default parameters are a bit of a “last resort” in overload resolution.

-Sune

···

On 16 Jan 2016, at 13:44, 肇鑫 via swift-evolution <swift-evolution@swift.org> wrote:

Hi Haravikk,

I just implement a func like your examples. However, I find the result is interesting.

protocol Good {
    func printSomething(something:String)
}

extension Good {
    func printSomething() { self.printSomething("Good") }
}

struct Name:Good {
    func printSomething(something: String = "John") {
        print(something)
    }
}

struct Talk:Good {
    func printSomething(something: String = "Hahaha") {
        print(something)
    }
}

var protocols:[Good] = [Name(), Talk()]

for p in protocols {
    p.printSomething() // Good, Good instead of John, Hahaha
}

As you can see, the final result is "Good, Good", not as I expected "John, Hahaha", is that right or is it a bug?

zhaoxin

[…snip…]


(Zhao Xin) #14

I’m -1 on this feature. Default values is basically compile sugar for not
filling in the value at the call site. The protocol should clearly state
its purpose and not constrain its implementations with stuff like this.

I
​ disagree. According to the definition of ​

​Protocol
<https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/protocol-method-declaration>
.​

Protocol method declarations have the same form as function declarations,

with two exceptions: They don’t include a function body, and you can’t
provide any default parameter values as part of the function declaration.

The definition doesn't say we can't use default values in implementation​.
The definition doesn't say we can't declare that a function must have or
have not default values. Only you can't set a default value in the protocol
function declaration.

This proposal is an improvement to the protocol and violate nothing.

zhaoxin

···

On Tue, Jan 19, 2016 at 12:53 AM, Sune Foldager <cyano@me.com> wrote:

I’m -1 on this feature. Default values is basically compile sugar for not
filling in the value at the call site. The protocol should clearly state
its purpose and not constrain its implementations with stuff like this.

Also, the reason you’re getting “Good, Good” below is probably because
default parameters are a bit of a “last resort” in overload resolution.

-Sune

On 16 Jan 2016, at 13:44, 肇鑫 via swift-evolution < > swift-evolution@swift.org> wrote:

Hi Haravikk,

I just implement a func like your examples. However, I find the result is
interesting.

protocol Good {
    func printSomething(something:String)
}

extension Good {
    func printSomething() { self.printSomething("Good") }
}

struct Name:Good {
    func printSomething(something: String = "John") {
        print(something)
    }
}

struct Talk:Good {
    func printSomething(something: String = "Hahaha") {
        print(something)
    }
}

var protocols:[Good] = [Name(), Talk()]

for p in protocols {
    p.printSomething() // Good, Good instead of John, Hahaha
}

As you can see, the final result is "Good, Good", not as I expected "John,
Hahaha", is that right or is it a bug?

zhaoxin

[…snip…]


Pitch: Allow functions with default arguments to fulfill protocols