Compiler should generate code base on the functions that have default values


(Zhao Xin) #1

This proposal is the summary of the previous protocol function default
value proposal and some of my new thinkings all together.

Currently the compiler doesn't stop you defining two functions like:

func printSomething(something:String = "some thing") {

    print(something)

}

func printSomething() {

    print("some thing!")

}

However, when you call it, an error arises.

printSomething() // Ambiguous use of 'printSomething'

You may say just remove the function that has no argument. But protocol
needs it.

protocol A {

    func printSomething(something:String)

    func printSomething()

}

struct Foo:A {

    func printSomething(something:String) {

        print(something)

    }

    func printSomething() {

        self.printSomething("some thing")

    }

}

If you do't define the no-argument function in protocol A. You can not use
the function by (Foo() as A).printSomething().

As we all know, a function with default values, can rewrite to two or more
equivalent functions. For example,

struct Bar {

    func add(int1:Int = 1, int2:Int = 2, int3:Int = 3) {

        print(int1 + int2 + int3)

    }

}

is equivalent to

struct Bar {

    func add(int1:Int, int2:Int, int3:Int) {

        print(int1 + int2 + int3)

    }

    func add() {

        self.add(1, int2: 2, int3: 3)

    }

    func add(int1:Int) {

        self.add(int1, int2: 2, int3: 3)

    }

    func add(int1:Int, int2:Int) {

        self.add(int1, int2: int2, int3: 3)

    }

}

So my proposal is let compiler or pre-compiler to generate the code
internally, without changing the original code, base on the functions that
have default values.

Then we need not to define multiple functions in a protocol when we need
function with default values.

new code:

protocol A {

    func printSomething(something:String)

}

struct Foo:A {

    func printSomething(something:String = "some thing") {

        print(something)

    }

}

If we don't want to change our previous code, we may also need to introduce
another keyword defaultValue. This keyword is used only in a protocol to
restrict if a function's argument can have a default value. If a function
use it, but the implementation doesn't give a default value, or vice versa,
an error arises.

new code:

protocol A {

    func printSomething(something:String = defaultValue)

}

struct Foo:A {

    func printSomething(something:String = "some thing") {

        print(something)

    }

}

This keyword is useful. With it, you can still use Swift in old way. Which
means you need not to change code like below if you don't want to.

old code:

protocol A {

    func printSomething(something:String)

    func printSomething()

}

struct Foo:A {

    func printSomething(something:String) {

        print(something)

    }

    func printSomething() {

        self.printSomething("some thing")

    }

}

But if you want to write new code. You can just write it in the new
way, enjoining the simpler and clearer.

zhaoxin


(Chéyo Jiménez) #2

This is very interesting. The first case seems like a bug because the
compiler should not let you define that function().

Do you have any actual examples when you would need to conform to the same
function name but with different signatures?

···

On Sunday, January 17, 2016, 肇鑫 via swift-evolution < swift-evolution@swift.org> wrote:

This proposal is the summary of the previous protocol function default
value proposal and some of my new thinkings all together.

Currently the compiler doesn't stop you defining two functions like:

func printSomething(something:String = "some thing") {

    print(something)

}

func printSomething() {

    print("some thing!")

}

However, when you call it, an error arises.

printSomething() // Ambiguous use of 'printSomething'

You may say just remove the function that has no argument. But protocol
needs it.

protocol A {

    func printSomething(something:String)

    func printSomething()

}

struct Foo:A {

    func printSomething(something:String) {

        print(something)

    }

    func printSomething() {

        self.printSomething("some thing")

    }

}

If you do't define the no-argument function in protocol A. You can not use
the function by (Foo() as A).printSomething().

As we all know, a function with default values, can rewrite to two or more
equivalent functions. For example,

struct Bar {

    func add(int1:Int = 1, int2:Int = 2, int3:Int = 3) {

        print(int1 + int2 + int3)

    }

}

is equivalent to

struct Bar {

    func add(int1:Int, int2:Int, int3:Int) {

        print(int1 + int2 + int3)

    }

    func add() {

        self.add(1, int2: 2, int3: 3)

    }

    func add(int1:Int) {

        self.add(int1, int2: 2, int3: 3)

    }

    func add(int1:Int, int2:Int) {

        self.add(int1, int2: int2, int3: 3)

    }

}

So my proposal is let compiler or pre-compiler to generate the code
internally, without changing the original code, base on the functions that
have default values.

Then we need not to define multiple functions in a protocol when we need
function with default values.

new code:

protocol A {

    func printSomething(something:String)

}

struct Foo:A {

    func printSomething(something:String = "some thing") {

        print(something)

    }

}

If we don't want to change our previous code, we may also need to
introduce another keyword defaultValue. This keyword is used only in a
protocol to restrict if a function's argument can have a default value. If
a function use it, but the implementation doesn't give a default value, or
vice versa, an error arises.

new code:

protocol A {

    func printSomething(something:String = defaultValue)

}

struct Foo:A {

    func printSomething(something:String = "some thing") {

        print(something)

    }

}

This keyword is useful. With it, you can still use Swift in old way. Which
means you need not to change code like below if you don't want to.

old code:

protocol A {

    func printSomething(something:String)

    func printSomething()

}

struct Foo:A {

    func printSomething(something:String) {

        print(something)

    }

    func printSomething() {

        self.printSomething("some thing")

    }

}

But if you want to write new code. You can just write it in the new
way, enjoining the simpler and clearer.

zhaoxin


(Félix Cloutier) #3

I agree that the compiler should be able to use a function with default values for protocol conformance.

Félix

···

Le 17 janv. 2016 à 11:52:06, J. Cheyo Jimenez via swift-evolution <swift-evolution@swift.org> a écrit :

This is very interesting. The first case seems like a bug because the compiler should not let you define that function().

Do you have any actual examples when you would need to conform to the same function name but with different signatures?

On Sunday, January 17, 2016, 肇鑫 via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
This proposal is the summary of the previous protocol function default value proposal and some of my new thinkings all together.

Currently the compiler doesn't stop you defining two functions like:

func printSomething(something:String = "some thing") {
    print(something)
}

func printSomething() {
    print("some thing!")
}

However, when you call it, an error arises.

printSomething() // Ambiguous use of 'printSomething'

You may say just remove the function that has no argument. But protocol needs it.

protocol A {
    func printSomething(something:String)
    func printSomething()
}

struct Foo:A {
    func printSomething(something:String) {
        print(something)
    }
    
    func printSomething() {
        self.printSomething("some thing")
    }
}

If you do't define the no-argument function in protocol A. You can not use the function by (Foo() as A).printSomething().

As we all know, a function with default values, can rewrite to two or more equivalent functions. For example,

struct Bar {
    func add(int1:Int = 1, int2:Int = 2, int3:Int = 3) {
        print(int1 + int2 + int3)
    }
}

is equivalent to

struct Bar {
    func add(int1:Int, int2:Int, int3:Int) {
        print(int1 + int2 + int3)
    }
    
    func add() {
        self.add(1, int2: 2, int3: 3)
    }
    
    func add(int1:Int) {
        self.add(int1, int2: 2, int3: 3)
    }
    
    func add(int1:Int, int2:Int) {
        self.add(int1, int2: int2, int3: 3)
    }
}

So my proposal is let compiler or pre-compiler to generate the code internally, without changing the original code, base on the functions that have default values.

Then we need not to define multiple functions in a protocol when we need function with default values.

new code:

protocol A {
    func printSomething(something:String)
}

struct Foo:A {
    func printSomething(something:String = "some thing") {
        print(something)
    }
}

If we don't want to change our previous code, we may also need to introduce another keyword defaultValue. This keyword is used only in a protocol to restrict if a function's argument can have a default value. If a function use it, but the implementation doesn't give a default value, or vice versa, an error arises.

new code:

protocol A {
    func printSomething(something:String = defaultValue)
}

struct Foo:A {
    func printSomething(something:String = "some thing") {
        print(something)
    }
}

This keyword is useful. With it, you can still use Swift in old way. Which means you need not to change code like below if you don't want to.

old code:

protocol A {
    func printSomething(something:String)
    func printSomething()
}

struct Foo:A {
    func printSomething(something:String) {
        print(something)
    }
    
    func printSomething() {
        self.printSomething("some thing")
    }
}

But if you want to write new code. You can just write it in the new way, enjoining the simpler and clearer.

zhaoxin

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


(Zhao Xin) #4

It is not to *conform to the same function name but with different
signatures*. It is the protocol limits in current Swift. You can implement
a protocol function with default values. But the protocol can't call the
function with the default value. So you have to add another function that
has no argument in the protocol and change the implementation.

current code:

protocol A {

    func printSomething(something:String)

}

struct Foo:A {

    func printSomething(something:String = "some thing") {

        print(something)

    }

}

Foo().printSomething() // some thing

(Foo() as A).printSomething() // Missing argument for parameter #1 in call

default value part is widely discussed in this thread
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006798.html>,
including other approaches like protocol extension.

zhaoxin

···

On Mon, Jan 18, 2016 at 12:52 AM, J. Cheyo Jimenez <cheyo@masters3d.com> wrote:

This is very interesting. The first case seems like a bug because the
compiler should not let you define that function().

Do you have any actual examples when you would need to conform to the same
function name but with different signatures?

On Sunday, January 17, 2016, 肇鑫 via swift-evolution < > swift-evolution@swift.org> wrote:

This proposal is the summary of the previous protocol function default
value proposal and some of my new thinkings all together.

Currently the compiler doesn't stop you defining two functions like:

func printSomething(something:String = "some thing") {

    print(something)

}

func printSomething() {

    print("some thing!")

}

However, when you call it, an error arises.

printSomething() // Ambiguous use of 'printSomething'

You may say just remove the function that has no argument. But protocol
needs it.

protocol A {

    func printSomething(something:String)

    func printSomething()

}

struct Foo:A {

    func printSomething(something:String) {

        print(something)

    }

    func printSomething() {

        self.printSomething("some thing")

    }

}

If you do't define the no-argument function in protocol A. You can not
use the function by (Foo() as A).printSomething().

As we all know, a function with default values, can rewrite to two or
more equivalent functions. For example,

struct Bar {

    func add(int1:Int = 1, int2:Int = 2, int3:Int = 3) {

        print(int1 + int2 + int3)

    }

}

is equivalent to

struct Bar {

    func add(int1:Int, int2:Int, int3:Int) {

        print(int1 + int2 + int3)

    }

    func add() {

        self.add(1, int2: 2, int3: 3)

    }

    func add(int1:Int) {

        self.add(int1, int2: 2, int3: 3)

    }

    func add(int1:Int, int2:Int) {

        self.add(int1, int2: int2, int3: 3)

    }

}

So my proposal is let compiler or pre-compiler to generate the code
internally, without changing the original code, base on the functions that
have default values.

Then we need not to define multiple functions in a protocol when we need
function with default values.

new code:

protocol A {

    func printSomething(something:String)

}

struct Foo:A {

    func printSomething(something:String = "some thing") {

        print(something)

    }

}

If we don't want to change our previous code, we may also need to
introduce another keyword defaultValue. This keyword is used only in a
protocol to restrict if a function's argument can have a default value. If
a function use it, but the implementation doesn't give a default value, or
vice versa, an error arises.

new code:

protocol A {

    func printSomething(something:String = defaultValue)

}

struct Foo:A {

    func printSomething(something:String = "some thing") {

        print(something)

    }

}

This keyword is useful. With it, you can still use Swift in old way.
Which means you need not to change code like below if you don't want to.

old code:

protocol A {

    func printSomething(something:String)

    func printSomething()

}

struct Foo:A {

    func printSomething(something:String) {

        print(something)

    }

    func printSomething() {

        self.printSomething("some thing")

    }

}

But if you want to write new code. You can just write it in the new
way, enjoining the simpler and clearer.

zhaoxin


(David Hart) #5

Hi Dave,

I agree with 肇鑫. Your issue and his seem like two separate issues, and I’d also like to see his issue implemented. For example, imagine I wanted to define this protocol:

protocol Logger {
    func print()
    func print(message: String)
    func print(path: String)
    func print(line: Int)
    func print(message: String, path: String)
    func print(message: String, line: Int)
    func print(path: String, line: Int)
    func print(message: String, path: String, line: Int)
}

It would be much simpler if I could more simply write:

protocol Logger {
    func print(message: String = default, path: String = default, line: Int = default)
}

Which is a separate issue then what you propose which would allow the same as the following for init as well:

protocol Logger {
    func print(message: String)
}

class NSLogger {
    func print(message: String, path: String, line: Int) {
        // ...
    }
}

extension NSLogger: Logger {
    conformance {
        print(message)
    }
}

···

On 17 Jan 2016, at 18:09, 肇鑫 via swift-evolution <swift-evolution@swift.org> wrote:

It is not to conform to the same function name but with different signatures. It is the protocol limits in current Swift. You can implement a protocol function with default values. But the protocol can't call the function with the default value. So you have to add another function that has no argument in the protocol and change the implementation.

current code:

protocol A {
    func printSomething(something:String)
}

struct Foo:A {
    func printSomething(something:String = "some thing") {
        print(something)
    }
}

Foo().printSomething() // some thing
(Foo() as A).printSomething() // Missing argument for parameter #1 in call

default value part is widely discussed in this thread <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006798.html>, including other approaches like protocol extension.

zhaoxin

On Mon, Jan 18, 2016 at 12:52 AM, J. Cheyo Jimenez <cheyo@masters3d.com <mailto:cheyo@masters3d.com>> wrote:
This is very interesting. The first case seems like a bug because the compiler should not let you define that function().

Do you have any actual examples when you would need to conform to the same function name but with different signatures?

On Sunday, January 17, 2016, 肇鑫 via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
This proposal is the summary of the previous protocol function default value proposal and some of my new thinkings all together.

Currently the compiler doesn't stop you defining two functions like:

func printSomething(something:String = "some thing") {
    print(something)
}

func printSomething() {
    print("some thing!")
}

However, when you call it, an error arises.

printSomething() // Ambiguous use of 'printSomething'

You may say just remove the function that has no argument. But protocol needs it.

protocol A {
    func printSomething(something:String)
    func printSomething()
}

struct Foo:A {
    func printSomething(something:String) {
        print(something)
    }
    
    func printSomething() {
        self.printSomething("some thing")
    }
}

If you do't define the no-argument function in protocol A. You can not use the function by (Foo() as A).printSomething().

As we all know, a function with default values, can rewrite to two or more equivalent functions. For example,

struct Bar {
    func add(int1:Int = 1, int2:Int = 2, int3:Int = 3) {
        print(int1 + int2 + int3)
    }
}

is equivalent to

struct Bar {
    func add(int1:Int, int2:Int, int3:Int) {
        print(int1 + int2 + int3)
    }
    
    func add() {
        self.add(1, int2: 2, int3: 3)
    }
    
    func add(int1:Int) {
        self.add(int1, int2: 2, int3: 3)
    }
    
    func add(int1:Int, int2:Int) {
        self.add(int1, int2: int2, int3: 3)
    }
}

So my proposal is let compiler or pre-compiler to generate the code internally, without changing the original code, base on the functions that have default values.

Then we need not to define multiple functions in a protocol when we need function with default values.

new code:

protocol A {
    func printSomething(something:String)
}

struct Foo:A {
    func printSomething(something:String = "some thing") {
        print(something)
    }
}

If we don't want to change our previous code, we may also need to introduce another keyword defaultValue. This keyword is used only in a protocol to restrict if a function's argument can have a default value. If a function use it, but the implementation doesn't give a default value, or vice versa, an error arises.

new code:

protocol A {
    func printSomething(something:String = defaultValue)
}

struct Foo:A {
    func printSomething(something:String = "some thing") {
        print(something)
    }
}

This keyword is useful. With it, you can still use Swift in old way. Which means you need not to change code like below if you don't want to.

old code:

protocol A {
    func printSomething(something:String)
    func printSomething()
}

struct Foo:A {
    func printSomething(something:String) {
        print(something)
    }
    
    func printSomething() {
        self.printSomething("some thing")
    }
}

But if you want to write new code. You can just write it in the new way, enjoining the simpler and clearer.

zhaoxin

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


(Andrew Bennett) #6

Similar has been discussed in the topic: "two protocols with the same
method name", it starts here:

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160104/005673.html

Here's another solution you may not have considered:

struct Foo:A {

    func printSomething(something:String = "some thing") {

        print(something)

    }

    @implements(A.printSomething)

    private func _printSomething() { self.printSomething() }

}

This was derived from the message by Joe Groff, in the linked thread:

Swift's protocol conformance model doesn't rely on the name of the member

matching the name of the requirement it satisfies. One possibility here is
to introduce an attribute to explicitly declare what protocol
requirement(s) a member is intended to satisfy:

···

class X: A, B {
  @implements(A.ring)
  var weddingRing: String

  @implements(B.ring)
  var ringtone: String
}

On Mon, Jan 18, 2016 at 5:19 AM, David Hart via swift-evolution < swift-evolution@swift.org> wrote:

Hi Dave,

I agree with 肇鑫. Your issue and his seem like two separate issues, and I’d
also like to see his issue implemented. For example, imagine I wanted to
define this protocol:

protocol Logger {
    func print()
    func print(message: String)
    func print(path: String)
    func print(line: Int)
    func print(message: String, path: String)
    func print(message: String, line: Int)
    func print(path: String, line: Int)
    func print(message: String, path: String, line: Int)
}

It would be much simpler if I could more simply write:

protocol Logger {
    func print(message: String = default, path: String = default, line:
Int = default)
}

Which is a separate issue then what you propose which would allow the same
as the following for *init* as well:

protocol Logger {
    func print(message: String)
}

class NSLogger {
    func print(message: String, path: String, line: Int) {
        // ...
    }
}

extension NSLogger: Logger {
    conformance {
        print(message)
    }
}

On 17 Jan 2016, at 18:09, 肇鑫 via swift-evolution < > swift-evolution@swift.org> wrote:

It is not to *conform to the same function name but with different
signatures*. It is the protocol limits in current Swift. You can
implement a protocol function with default values. But the protocol can't
call the function with the default value. So you have to add another
function that has no argument in the protocol and change the implementation.

current code:

protocol A {
    func printSomething(something:String)
}

struct Foo:A {
    func printSomething(something:String = "some thing") {
        print(something)
    }
}

Foo().printSomething() // some thing
(Foo() as A).printSomething() // Missing argument for parameter #1 in call

default value part is widely discussed in this thread
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006798.html>,
including other approaches like protocol extension.

zhaoxin

On Mon, Jan 18, 2016 at 12:52 AM, J. Cheyo Jimenez <cheyo@masters3d.com> > wrote:

This is very interesting. The first case seems like a bug because the
compiler should not let you define that function().

Do you have any actual examples when you would need to conform to the
same function name but with different signatures?

On Sunday, January 17, 2016, 肇鑫 via swift-evolution < >> swift-evolution@swift.org> wrote:

This proposal is the summary of the previous protocol function default
value proposal and some of my new thinkings all together.

Currently the compiler doesn't stop you defining two functions like:

func printSomething(something:String = "some thing") {
    print(something)
}

func printSomething() {
    print("some thing!")
}

However, when you call it, an error arises.

printSomething() // Ambiguous use of 'printSomething'

You may say just remove the function that has no argument. But protocol
needs it.

protocol A {
    func printSomething(something:String)
    func printSomething()
}

struct Foo:A {
    func printSomething(something:String) {
        print(something)
    }

    func printSomething() {
        self.printSomething("some thing")
    }

}

If you do't define the no-argument function in protocol A. You can not
use the function by (Foo() as A).printSomething().

As we all know, a function with default values, can rewrite to two or
more equivalent functions. For example,

struct Bar {
    func add(int1:Int = 1, int2:Int = 2, int3:Int = 3) {
        print(int1 + int2 + int3)
    }

}

is equivalent to

struct Bar {
    func add(int1:Int, int2:Int, int3:Int) {
        print(int1 + int2 + int3)
    }

    func add() {
        self.add(1, int2: 2, int3: 3)
    }

    func add(int1:Int) {
        self.add(int1, int2: 2, int3: 3)
    }

    func add(int1:Int, int2:Int) {
        self.add(int1, int2: int2, int3: 3)
    }

}

So my proposal is let compiler or pre-compiler to generate the code
internally, without changing the original code, base on the functions that
have default values.

Then we need not to define multiple functions in a protocol when we need
function with default values.

new code:

protocol A {
    func printSomething(something:String)
}

struct Foo:A {
    func printSomething(something:String = "some thing") {
        print(something)
    }

}

If we don't want to change our previous code, we may also need to
introduce another keyword defaultValue. This keyword is used only in a
protocol to restrict if a function's argument can have a default value. If
a function use it, but the implementation doesn't give a default value, or
vice versa, an error arises.

new code:

protocol A {
    func printSomething(something:String = defaultValue)
}

struct Foo:A {
    func printSomething(something:String = "some thing") {
        print(something)
    }

}

This keyword is useful. With it, you can still use Swift in old way.
Which means you need not to change code like below if you don't want to.

old code:

protocol A {
    func printSomething(something:String)
    func printSomething()
}

struct Foo:A {
    func printSomething(something:String) {
        print(something)
    }

    func printSomething() {
        self.printSomething("some thing")
    }

}

But if you want to write new code. You can just write it in the new
way, enjoining the simpler and clearer.

zhaoxin

_______________________________________________
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) #7

Hi David,

You understanding is correct.

There is only one thing I have to mention. Unless the other c style
languages which you can call default values in the middle, Swift only
allows you to call default values in the last. That makes you example:

func print(message: String = default, path: String = default, line: Int =
default)

can only wrapped to 4 functions instead of 8.

func print(message: String, path: String, line: Int)
func print()
func print(message: String)
func print(message: String, path: String)

You can't call func print(path: String) by calling func print(message:
String = default, path: String = default, line: Int = default). print(_,
path: "path"t, line: _) is not a valid calling in Swift.

zhaoxin

···

On Mon, Jan 18, 2016 at 2:19 AM, David Hart <david@hartbit.com> wrote:

Hi Dave,

I agree with 肇鑫. Your issue and his seem like two separate issues, and I’d
also like to see his issue implemented. For example, imagine I wanted to
define this protocol:

protocol Logger {
    func print()
    func print(message: String)
    func print(path: String)
    func print(line: Int)
    func print(message: String, path: String)
    func print(message: String, line: Int)
    func print(path: String, line: Int)
    func print(message: String, path: String, line: Int)
}

It would be much simpler if I could more simply write:

protocol Logger {
    func print(message: String = default, path: String = default, line:
Int = default)
}

Which is a separate issue then what you propose which would allow the same
as the following for *init* as well:

protocol Logger {
    func print(message: String)
}

class NSLogger {
    func print(message: String, path: String, line: Int) {
        // ...
    }
}

extension NSLogger: Logger {
    conformance {
        print(message)
    }
}

On 17 Jan 2016, at 18:09, 肇鑫 via swift-evolution < > swift-evolution@swift.org> wrote:

It is not to *conform to the same function name but with different
signatures*. It is the protocol limits in current Swift. You can
implement a protocol function with default values. But the protocol can't
call the function with the default value. So you have to add another
function that has no argument in the protocol and change the implementation.

current code:

protocol A {
    func printSomething(something:String)
}

struct Foo:A {
    func printSomething(something:String = "some thing") {
        print(something)
    }
}

Foo().printSomething() // some thing
(Foo() as A).printSomething() // Missing argument for parameter #1 in call

default value part is widely discussed in this thread
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006798.html>,
including other approaches like protocol extension.

zhaoxin

On Mon, Jan 18, 2016 at 12:52 AM, J. Cheyo Jimenez <cheyo@masters3d.com> > wrote:

This is very interesting. The first case seems like a bug because the
compiler should not let you define that function().

Do you have any actual examples when you would need to conform to the
same function name but with different signatures?

On Sunday, January 17, 2016, 肇鑫 via swift-evolution < >> swift-evolution@swift.org> wrote:

This proposal is the summary of the previous protocol function default
value proposal and some of my new thinkings all together.

Currently the compiler doesn't stop you defining two functions like:

func printSomething(something:String = "some thing") {
    print(something)
}

func printSomething() {
    print("some thing!")
}

However, when you call it, an error arises.

printSomething() // Ambiguous use of 'printSomething'

You may say just remove the function that has no argument. But protocol
needs it.

protocol A {
    func printSomething(something:String)
    func printSomething()
}

struct Foo:A {
    func printSomething(something:String) {
        print(something)
    }

    func printSomething() {
        self.printSomething("some thing")
    }

}

If you do't define the no-argument function in protocol A. You can not
use the function by (Foo() as A).printSomething().

As we all know, a function with default values, can rewrite to two or
more equivalent functions. For example,

struct Bar {
    func add(int1:Int = 1, int2:Int = 2, int3:Int = 3) {
        print(int1 + int2 + int3)
    }

}

is equivalent to

struct Bar {
    func add(int1:Int, int2:Int, int3:Int) {
        print(int1 + int2 + int3)
    }

    func add() {
        self.add(1, int2: 2, int3: 3)
    }

    func add(int1:Int) {
        self.add(int1, int2: 2, int3: 3)
    }

    func add(int1:Int, int2:Int) {
        self.add(int1, int2: int2, int3: 3)
    }

}

So my proposal is let compiler or pre-compiler to generate the code
internally, without changing the original code, base on the functions that
have default values.

Then we need not to define multiple functions in a protocol when we need
function with default values.

new code:

protocol A {
    func printSomething(something:String)
}

struct Foo:A {
    func printSomething(something:String = "some thing") {
        print(something)
    }

}

If we don't want to change our previous code, we may also need to
introduce another keyword defaultValue. This keyword is used only in a
protocol to restrict if a function's argument can have a default value. If
a function use it, but the implementation doesn't give a default value, or
vice versa, an error arises.

new code:

protocol A {
    func printSomething(something:String = defaultValue)
}

struct Foo:A {
    func printSomething(something:String = "some thing") {
        print(something)
    }

}

This keyword is useful. With it, you can still use Swift in old way.
Which means you need not to change code like below if you don't want to.

old code:

protocol A {
    func printSomething(something:String)
    func printSomething()
}

struct Foo:A {
    func printSomething(something:String) {
        print(something)
    }

    func printSomething() {
        self.printSomething("some thing")
    }

}

But if you want to write new code. You can just write it in the new
way, enjoining the simpler and clearer.

zhaoxin

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


(Zhao Xin) #8

Sorry Andrew, you link is not related with this proposal.

As you can see, this proposal starts with no protocol at all. It starts
with the conflicts between a function with a default value comparing to its
version that has no argument. Then this issue combines with the protocol
limits becomes a larger issue. But there is no two different protocols with
the same properties name here. There is only one protocol from the
beginning to the end.

I also discussed in the link your provided. And in my option, this proposal
has nothing related with that at all.

zhaoxin

···

On Mon, Jan 18, 2016 at 7:50 AM, Andrew Bennett <cacoyi@gmail.com> wrote:

Similar has been discussed in the topic: "two protocols with the same
method name", it starts here:

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160104/005673.html

Here's another solution you may not have considered:

struct Foo:A {

    func printSomething(something:String = "some thing") {

        print(something)

    }

    @implements(A.printSomething)

    private func _printSomething() { self.printSomething() }

}

This was derived from the message by Joe Groff, in the linked thread:

> Swift's protocol conformance model doesn't rely on the name of the
member matching the name of the requirement it satisfies. One possibility
here is to introduce an attribute to explicitly declare what protocol
requirement(s) a member is intended to satisfy:
>
> class X: A, B {
> @implements(A.ring)
> var weddingRing: String
>
> @implements(B.ring)
> var ringtone: String
> }
>

On Mon, Jan 18, 2016 at 5:19 AM, David Hart via swift-evolution < > swift-evolution@swift.org> wrote:

Hi Dave,

I agree with 肇鑫. Your issue and his seem like two separate issues, and
I’d also like to see his issue implemented. For example, imagine I wanted
to define this protocol:

protocol Logger {
    func print()
    func print(message: String)
    func print(path: String)
    func print(line: Int)
    func print(message: String, path: String)
    func print(message: String, line: Int)
    func print(path: String, line: Int)
    func print(message: String, path: String, line: Int)
}

It would be much simpler if I could more simply write:

protocol Logger {
    func print(message: String = default, path: String = default, line:
Int = default)
}

Which is a separate issue then what you propose which would allow the
same as the following for *init* as well:

protocol Logger {
    func print(message: String)
}

class NSLogger {
    func print(message: String, path: String, line: Int) {
        // ...
    }
}

extension NSLogger: Logger {
    conformance {
        print(message)
    }
}

On 17 Jan 2016, at 18:09, 肇鑫 via swift-evolution < >> swift-evolution@swift.org> wrote:

It is not to *conform to the same function name but with different
signatures*. It is the protocol limits in current Swift. You can
implement a protocol function with default values. But the protocol can't
call the function with the default value. So you have to add another
function that has no argument in the protocol and change the implementation.

current code:

protocol A {
    func printSomething(something:String)
}

struct Foo:A {
    func printSomething(something:String = "some thing") {
        print(something)
    }
}

Foo().printSomething() // some thing
(Foo() as A).printSomething() // Missing argument for parameter #1 in
call

default value part is widely discussed in this thread
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006798.html>,
including other approaches like protocol extension.

zhaoxin

On Mon, Jan 18, 2016 at 12:52 AM, J. Cheyo Jimenez <cheyo@masters3d.com> >> wrote:

This is very interesting. The first case seems like a bug because the
compiler should not let you define that function().

Do you have any actual examples when you would need to conform to the
same function name but with different signatures?

On Sunday, January 17, 2016, 肇鑫 via swift-evolution < >>> swift-evolution@swift.org> wrote:

This proposal is the summary of the previous protocol function default
value proposal and some of my new thinkings all together.

Currently the compiler doesn't stop you defining two functions like:

func printSomething(something:String = "some thing") {
    print(something)
}

func printSomething() {
    print("some thing!")
}

However, when you call it, an error arises.

printSomething() // Ambiguous use of 'printSomething'

You may say just remove the function that has no argument. But protocol
needs it.

protocol A {
    func printSomething(something:String)
    func printSomething()
}

struct Foo:A {
    func printSomething(something:String) {
        print(something)
    }

    func printSomething() {
        self.printSomething("some thing")
    }

}

If you do't define the no-argument function in protocol A. You can not
use the function by (Foo() as A).printSomething().

As we all know, a function with default values, can rewrite to two or
more equivalent functions. For example,

struct Bar {
    func add(int1:Int = 1, int2:Int = 2, int3:Int = 3) {
        print(int1 + int2 + int3)
    }

}

is equivalent to

struct Bar {
    func add(int1:Int, int2:Int, int3:Int) {
        print(int1 + int2 + int3)
    }

    func add() {
        self.add(1, int2: 2, int3: 3)
    }

    func add(int1:Int) {
        self.add(int1, int2: 2, int3: 3)
    }

    func add(int1:Int, int2:Int) {
        self.add(int1, int2: int2, int3: 3)
    }

}

So my proposal is let compiler or pre-compiler to generate the code
internally, without changing the original code, base on the functions that
have default values.

Then we need not to define multiple functions in a protocol when we
need function with default values.

new code:

protocol A {
    func printSomething(something:String)
}

struct Foo:A {
    func printSomething(something:String = "some thing") {
        print(something)
    }

}

If we don't want to change our previous code, we may also need to
introduce another keyword defaultValue. This keyword is used only in a
protocol to restrict if a function's argument can have a default value. If
a function use it, but the implementation doesn't give a default value, or
vice versa, an error arises.

new code:

protocol A {
    func printSomething(something:String = defaultValue)
}

struct Foo:A {
    func printSomething(something:String = "some thing") {
        print(something)
    }

}

This keyword is useful. With it, you can still use Swift in old way.
Which means you need not to change code like below if you don't want to.

old code:

protocol A {
    func printSomething(something:String)
    func printSomething()
}

struct Foo:A {
    func printSomething(something:String) {
        print(something)
    }

    func printSomething() {
        self.printSomething("some thing")
    }

}

But if you want to write new code. You can just write it in the new
way, enjoining the simpler and clearer.

zhaoxin

_______________________________________________
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


(Jordan Rose) #9

This is not true.

func test(a a: Int = 0, b: Int = 1, c: Int = 2, d: Int = 3) {
  print("\(a) \(b) \(c) \(d)")
}
test()
test(a: 10)
test(b: 10)
test(c: 10)
test(d: 10)
test(b: 20, a: 10)
test(a: 10, b: 20, c: 30)
test(a: 10, d: 20)

All of these calls are legal.

Jordan

···

On Jan 17, 2016, at 19:18 , 肇鑫 via swift-evolution <swift-evolution@swift.org> wrote:

Hi David,

You understanding is correct.

There is only one thing I have to mention. Unless the other c style languages which you can call default values in the middle, Swift only allows you to call default values in the last. That makes you example:

func print(message: String = default, path: String = default, line: Int = default)

can only wrapped to 4 functions instead of 8.

func print(message: String, path: String, line: Int)
func print()
func print(message: String)
func print(message: String, path: String)

You can't call func print(path: String) by calling func print(message: String = default, path: String = default, line: Int = default). print(_, path: "path"t, line: _) is not a valid calling in Swift.


(Zhao Xin) #10

You are right. I didn't know it can do that way.

There is a note in Swift document
<https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html>
.

NOTE

Place parameters with default values at the end of a function’s parameter
list. This ensures that all calls to the function use the same order for
their nondefault arguments, and makes it clear that the same function is
being called in each case.

It makes me think what I did.

zhaoxin

···

On Thu, Jan 21, 2016 at 5:51 AM, Jordan Rose <jordan_rose@apple.com> wrote:

On Jan 17, 2016, at 19:18 , 肇鑫 via swift-evolution < > swift-evolution@swift.org> wrote:

Hi David,

You understanding is correct.

There is only one thing I have to mention. Unless the other c style
languages which you can call default values in the middle, Swift only
allows you to call default values in the last. That makes you example:

func print(message: String = default, path: String = default, line: Int =
default)

can only wrapped to 4 functions instead of 8.

func print(message: String, path: String, line: Int)
func print()
func print(message: String)
func print(message: String, path: String)

You can't call func print(path: String) by calling func print(message:
String = default, path: String = default, line: Int = default). print(_,
path: "path"t, line: _) is not a valid calling in Swift.

This is not true.

func test(a a: Int = 0, b: Int = 1, c: Int = 2, d: Int = 3) {
  print("\(a) \(b) \(c) \(d)")
}
test()
test(a: 10)
test(b: 10)
test(c: 10)
test(d: 10)
test(b: 20, a: 10)
test(a: 10, b: 20, c: 30)
test(a: 10, d: 20)

All of these calls are legal.

Jordan