two protocols with the same method name

I suggest compile warning if one classes/structs/enums implements
protocols with the same name.
It could lead to confusions, when methods of those protocols will mean
different things.
It will force to implement parent protocol with shared methods or
change method in one of the protocols.
Below is an example.
Regards,
Greg

//:ring:
protocol A {
  var ring: String { get }
}

//:bell:
protocol B {
  var ring: String { get set }
}

class X: A, B {
  var ring: String {
    get {
      return ":ring:"
    }
    set {
      self.ring = newValue
    }
  }
}
let x = X()
let somewhereInTheProject = "\(x.ring) the bell"
x.ring = ":bell:" // ERROR!

Mm. There are two cases here:

- Two protocols use the same method name for completely unrelated things.
- Two protocols use the same method name for similar things.

In the latter case, having one method satisfy both requirements is probably fine. In the former, there would definitely be a problem…but I have a hard time thinking of a type that should actually conform to two protocols that do completely different things and yet manage to use the same name for something. Do you have a real-life example where this has been a problem? Everything I can find online looks contrived.

Jordan

···

On Jan 7, 2016, at 2:18, Grzegorz Leszek via swift-evolution <swift-evolution@swift.org> wrote:

I suggest compile warning if one classes/structs/enums implements
protocols with the same name.
It could lead to confusions, when methods of those protocols will mean
different things.
It will force to implement parent protocol with shared methods or
change method in one of the protocols.
Below is an example.
Regards,
Greg

//:ring:
protocol A {
var ring: String { get }
}

//:bell:
protocol B {
var ring: String { get set }
}

class X: A, B {
var ring: String {
   get {
     return ":ring:"
   }
   set {
     self.ring = newValue
   }
}
}
let x = X()
let somewhereInTheProject = "\(x.ring) the bell"
x.ring = ":bell:" // ERROR!
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I don’t really get what you are driving at. If I rework your example so that it runs:

//:ring:
protocol A {
    var ring: String { get }
}

//:bell:
protocol B {
    var ring: String { get set }
}

class X: A, B {
    var _ring = ":ring:"
    var ring: String {
        get {
            return _ring
        }
        set {
            self._ring = newValue
        }
    }
}
let x = X()
(x as A).ring // :ring:
(x as B).ring // :ring:
x.ring // :ring:
x.ring = ":bell:"
x.ring // :bell:
// (x as A).ring = ":bell:" Error, A doesn't have set

Then the behaviour is exactly what I would expect.

···

On 7 Jan 2016, at 9:18 PM, Grzegorz Leszek via swift-evolution <swift-evolution@swift.org> wrote:

I suggest compile warning if one classes/structs/enums implements
protocols with the same name.
It could lead to confusions, when methods of those protocols will mean
different things.
It will force to implement parent protocol with shared methods or
change method in one of the protocols.
Below is an example.
Regards,
Greg

//:ring:
protocol A {
var ring: String { get }
}

//:bell:
protocol B {
var ring: String { get set }
}

class X: A, B {
var ring: String {
   get {
     return ":ring:"
   }
   set {
     self.ring = newValue
   }
}
}
let x = X()
let somewhereInTheProject = "\(x.ring) the bell"
x.ring = ":bell:" // ERROR!
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

1 Like

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
}

As other noted, protocols with same-named requirements but different semantics are rare in practice, and it's occasionally useful to intentionally overlap requirements (I believe the CollectionType hierarchy does this in places), so the current behavior feels like a reasonable default to me. I can see value in requiring it to be explicit though.

-Joe

···

On Jan 7, 2016, at 2:18 AM, Grzegorz Leszek via swift-evolution <swift-evolution@swift.org> wrote:

I suggest compile warning if one classes/structs/enums implements
protocols with the same name.
It could lead to confusions, when methods of those protocols will mean
different things.
It will force to implement parent protocol with shared methods or
change method in one of the protocols.
Below is an example.
Regards,
Greg

//:ring:
protocol A {
var ring: String { get }
}

//:bell:
protocol B {
var ring: String { get set }
}

class X: A, B {
var ring: String {
   get {
     return ":ring:"
   }
   set {
     self.ring = newValue
   }
}
}
let x = X()
let somewhereInTheProject = "\(x.ring) the bell"
x.ring = ":bell:" // ERROR!

3 Likes

I do the 2nd case on purpose. Usually it’s to refine typealiases rather than for methods/variables, but I’m pretty sure I’ll be dealing with those as well fairly soon.

···

On Jan 7, 2016, at 17:40, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

Mm. There are two cases here:

- Two protocols use the same method name for completely unrelated things.
- Two protocols use the same method name for similar things.

In the latter case, having one method satisfy both requirements is probably fine. In the former, there would definitely be a problem…but I have a hard time thinking of a type that should actually conform to two protocols that do completely different things and yet manage to use the same name for something. Do you have a real-life example where this has been a problem? Everything I can find online looks contrived.

Jordan

On Jan 7, 2016, at 2:18, Grzegorz Leszek via swift-evolution <swift-evolution@swift.org> wrote:

I suggest compile warning if one classes/structs/enums implements
protocols with the same name.
It could lead to confusions, when methods of those protocols will mean
different things.
It will force to implement parent protocol with shared methods or
change method in one of the protocols.
Below is an example.
Regards,
Greg

//:ring:
protocol A {
var ring: String { get }
}

//:bell:
protocol B {
var ring: String { get set }
}

class X: A, B {
var ring: String {
  get {
    return ":ring:"
  }
  set {
    self.ring = newValue
  }
}
}
let x = X()
let somewhereInTheProject = "\(x.ring) the bell"
x.ring = ":bell:" // ERROR!
_______________________________________________
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

I don’t really get what you are driving at.

The point is that, although `A` and `B` both require properties with the same name, they expect different semantics from that property. Let's maybe give these more concrete names so you can understand the idea:

  protocol Marriageable {
    var ring: String? { get set } // File name of image of this person's wedding ring.
  }
  protocol CallReceivable {
    var ring: String? { get set } // File name of ringtone to be used for this person.
  }

  struct Person: Marriageable, CallReceivable {
    var ring: String?
  }

Of course a person is marriageable and can this have "a ring", and of course you can also receive a call from them and they can thus have "a ring". But in reality, the "ring" that satisfies one of these things will not work for the other. If your best friend gets married and you add an image of the ring, then the next time your friend calls you, the phone ringing screen will try to play a JPEG as an MP3.

The "ring" example is, of course, slightly contrived, but I'm sure you can imagine a similar problem with real names, where you end up using the same term for two different and incompatible things.

What the OP is basically asking is, when Swift sees the same type conforming to Marriageable and CallReceivable, should it optimistically assume that the `ring` properties they both require are compatible and allow the code to pass through without comment? Or should it pessimistically assume that the `ring` properties are incompatible and emit a warning or error about them?

···

--
Brent Royal-Gordon
Architechies

Storage properties on protocol or in extension plus something when call
maybe a solution:

       protocol Marriageable {
               var foo:Int = 0; // actual a var.
                var ring: String? // actual a var.
        }
        protocol CallReceivable {
                var ring: String? // actual a var.
        }

        struct Person: Marriageable, CallReceivable { }

OR
        protocol Marriageable {
                var ring: String? { get set }
        }
        protocol CallReceivable {
                var ring: String? { get set }
        }

        struct Person { }

       extension Person: Marriageable{
         var ring: String?
       }

     extension Person: CallReceivable{
         var ring: String?
       }

So:

var person = Person()
person.foo = 1 // ok

person.ring = getRingtone() // error, ring is ambiguous
(person as CallReceivable).ring = getRingtone() // ok
OR
person.CallReceivable.ring = getRingtone() // ok | CallReceivable is a
know person protocol, so can get a implicity dot notation,
like .dynamicType.staticMethod();

Anyway, it's not an easy problem to solve.

···

Em sáb, 9 de jan de 2016 às 01:09, Brent Royal-Gordon via swift-evolution < swift-evolution@swift.org> escreveu:

> I don’t really get what you are driving at.

The point is that, although `A` and `B` both require properties with the
same name, they expect different semantics from that property. Let's maybe
give these more concrete names so you can understand the idea:

        protocol Marriageable {
                var ring: String? { get set } // File name of image of
this person's wedding ring.
        }
        protocol CallReceivable {
                var ring: String? { get set } // File name of ringtone
to be used for this person.
        }

        struct Person: Marriageable, CallReceivable {
                var ring: String?
        }

Of course a person is marriageable and can this have "a ring", and of
course you can also receive a call from them and they can thus have "a
ring". But in reality, the "ring" that satisfies one of these things will
not work for the other. If your best friend gets married and you add an
image of the ring, then the next time your friend calls you, the phone
ringing screen will try to play a JPEG as an MP3.

The "ring" example is, of course, slightly contrived, but I'm sure you can
imagine a similar problem with real names, where you end up using the same
term for two different and incompatible things.

What the OP is basically asking is, when Swift sees the same type
conforming to Marriageable and CallReceivable, should it optimistically
assume that the `ring` properties they both require are compatible and
allow the code to pass through without comment? Or should it
pessimistically assume that the `ring` properties are incompatible and emit
a warning or error about them?

--
Brent Royal-Gordon
Architechies

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

Howard is almost right.

Protocol A means the ring variable must have a getter. For the setter, you
can have it or not. Both won't violate the conformance of the Protocol A.

Actually, you can write as

protocol B:A {
var ring:String { get set }
}

The is more for the last line
// (x as A).ring = ":bell:" Error, A doesn't have set

You will find more that
(x as B).ring = "1"
doesn't work either. The reason is that (x as B) is a let by default.

You need do
var b = x as B
b.ring = "1"

Above works.

zhaoxin

···

On Sat, Jan 9, 2016 at 10:19 AM, Howard Lovatt via swift-evolution < swift-evolution@swift.org> wrote:

I don’t really get what you are driving at. If I rework your example so
that it runs:

//:ring:
protocol A {
    var ring: String { get }
}

//:bell:
protocol B {
    var ring: String { get set }
}

class X: A, B {
    var _ring = ":ring:"
    var ring: String {
        get {
            return _ring
        }
        set {
            self._ring = newValue
        }
    }
}
let x = X()
(x as A).ring // :ring:
(x as B).ring // :ring:
x.ring // :ring:
x.ring = ":bell:"
x.ring // :bell:
// (x as A).ring = ":bell:" Error, A doesn't have set

Then the behaviour is exactly what I would expect.

On 7 Jan 2016, at 9:18 PM, Grzegorz Leszek via swift-evolution < > swift-evolution@swift.org> wrote:

I suggest compile warning if one classes/structs/enums implements
protocols with the same name.
It could lead to confusions, when methods of those protocols will mean
different things.
It will force to implement parent protocol with shared methods or
change method in one of the protocols.
Below is an example.
Regards,
Greg

//:ring:
protocol A {
var ring: String { get }
}

//:bell:
protocol B {
var ring: String { get set }
}

class X: A, B {
var ring: String {
   get {
     return ":ring:"
   }
   set {
     self.ring = newValue
   }
}
}
let x = X()
let somewhereInTheProject = "\(x.ring) the bell"
x.ring = ":bell:" // ERROR!
_______________________________________________
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

--

Owen Zhao

1 Like

That's totally wrong!

        protocol Marriageable {
                var ringImageFileName: String? { get set } // File name
of image of this person's wedding ring.
        }
        protocol CallReceivable {
                var ringtoneFileName: String? { get set } // File name of
ringtone to be used for this person.
        }

···

On Sat, Jan 9, 2016 at 11:09 AM, Brent Royal-Gordon via swift-evolution < swift-evolution@swift.org> wrote:

> I don’t really get what you are driving at.

The point is that, although `A` and `B` both require properties with the
same name, they expect different semantics from that property. Let's maybe
give these more concrete names so you can understand the idea:

        protocol Marriageable {
                var ring: String? { get set } // File name of image of
this person's wedding ring.
        }
        protocol CallReceivable {
                var ring: String? { get set } // File name of ringtone
to be used for this person.
        }

        struct Person: Marriageable, CallReceivable {
                var ring: String?
        }

Of course a person is marriageable and can this have "a ring", and of
course you can also receive a call from them and they can thus have "a
ring". But in reality, the "ring" that satisfies one of these things will
not work for the other. If your best friend gets married and you add an
image of the ring, then the next time your friend calls you, the phone
ringing screen will try to play a JPEG as an MP3.

The "ring" example is, of course, slightly contrived, but I'm sure you can
imagine a similar problem with real names, where you end up using the same
term for two different and incompatible things.

What the OP is basically asking is, when Swift sees the same type
conforming to Marriageable and CallReceivable, should it optimistically
assume that the `ring` properties they both require are compatible and
allow the code to pass through without comment? Or should it
pessimistically assume that the `ring` properties are incompatible and emit
a warning or error about them?

--
Brent Royal-Gordon
Architechies

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

--
Best Regards!

Yang Wu
--------------------------------------------------------
Location: Pudong, Shanghai, China.
EMail : pinxue@gmail.com
Website: http://www.time2change.mobi http://rockplayer.com
Twitter/Weibo : @pinxue
<http://www.pinxue.net>

Thanks, I understand what you are driving at now.

This is true in many languages that have interfaces (protocols), e.g. Java and duck-typed languages, it doesn’t seem to be a big deal. Languages that have traits or mixins, e.g. Scala, can deal with this.

I suggest that it isn’t a big enough problem to worry about. It might go away if protocols morph into traits :).

···

On 9 Jan 2016, at 2:09 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

I don’t really get what you are driving at.

The point is that, although `A` and `B` both require properties with the same name, they expect different semantics from that property. Let's maybe give these more concrete names so you can understand the idea:

  protocol Marriageable {
    var ring: String? { get set } // File name of image of this person's wedding ring.
  }
  protocol CallReceivable {
    var ring: String? { get set } // File name of ringtone to be used for this person.
  }

  struct Person: Marriageable, CallReceivable {
    var ring: String?
  }

Of course a person is marriageable and can this have "a ring", and of course you can also receive a call from them and they can thus have "a ring". But in reality, the "ring" that satisfies one of these things will not work for the other. If your best friend gets married and you add an image of the ring, then the next time your friend calls you, the phone ringing screen will try to play a JPEG as an MP3.

The "ring" example is, of course, slightly contrived, but I'm sure you can imagine a similar problem with real names, where you end up using the same term for two different and incompatible things.

What the OP is basically asking is, when Swift sees the same type conforming to Marriageable and CallReceivable, should it optimistically assume that the `ring` properties they both require are compatible and allow the code to pass through without comment? Or should it pessimistically assume that the `ring` properties are incompatible and emit a warning or error about them?

--
Brent Royal-Gordon
Architechies

I know what you mean at the beginning. However, as your example shows, the
warning means nothing if it really happens.

Because you cannot solve the problem by revising your own code. You
definitely have to change the protocols. If you have no way to change the
protocols, you will have to drop either of them.

My point is that it is the protocols' programmer who should take care of
it, not you. Or if you write the protocols, you should avoid this at the
beginning.

zhaoxin

···

On Sat, Jan 9, 2016 at 11:09 AM, Brent Royal-Gordon via swift-evolution < swift-evolution@swift.org> wrote:

> I don’t really get what you are driving at.

The point is that, although `A` and `B` both require properties with the
same name, they expect different semantics from that property. Let's maybe
give these more concrete names so you can understand the idea:

        protocol Marriageable {
                var ring: String? { get set } // File name of image of
this person's wedding ring.
        }
        protocol CallReceivable {
                var ring: String? { get set } // File name of ringtone
to be used for this person.
        }

        struct Person: Marriageable, CallReceivable {
                var ring: String?
        }

Of course a person is marriageable and can this have "a ring", and of
course you can also receive a call from them and they can thus have "a
ring". But in reality, the "ring" that satisfies one of these things will
not work for the other. If your best friend gets married and you add an
image of the ring, then the next time your friend calls you, the phone
ringing screen will try to play a JPEG as an MP3.

The "ring" example is, of course, slightly contrived, but I'm sure you can
imagine a similar problem with real names, where you end up using the same
term for two different and incompatible things.

What the OP is basically asking is, when Swift sees the same type
conforming to Marriageable and CallReceivable, should it optimistically
assume that the `ring` properties they both require are compatible and
allow the code to pass through without comment? Or should it
pessimistically assume that the `ring` properties are incompatible and emit
a warning or error about them?

--
Brent Royal-Gordon
Architechies

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

--

Owen Zhao

In Eiffel you would have to rename at least one of the conflicting members in the implementing class to distinguish the cases there.
When called through one of the protocols the correct renamed member would be used, i.e. (translated to pseudo-Swift):

protocol Marriageable {
  var ring: String? { get set } // File name of image of this person's wedding ring.
}

protocol CallReceivable {
  var ring: String? { get set } // File name of ringtone to be used for this person.
}

// In this example I choose to rename both
struct Person: Marriageable rename ring to ringImage, CallReceivable rename ring to ringTone {
  var ringImage: String?
  var ringTone: String?
}

let friend: Person = ...
let m: Marriageable = friend
let callee: CallReceivable = friend

friend.ring // type error (the Person type only has vars ringImage and ringTone)
friend.ringImage // file name of image of wedding ring
friend.ringTone // file name of ring tone
m.ring // result of friend.ringImage because of rename
callee.ring // result of friend.ringTone because of rename

This always does the right thing and solves the problem nicely.

-Thorsten

···

Am 09.01.2016 um 04:09 schrieb Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org>:

I don’t really get what you are driving at.

The point is that, although `A` and `B` both require properties with the same name, they expect different semantics from that property. Let's maybe give these more concrete names so you can understand the idea:

  protocol Marriageable {
    var ring: String? { get set } // File name of image of this person's wedding ring.
  }
  protocol CallReceivable {
    var ring: String? { get set } // File name of ringtone to be used for this person.
  }

  struct Person: Marriageable, CallReceivable {
    var ring: String?
  }

Of course a person is marriageable and can this have "a ring", and of course you can also receive a call from them and they can thus have "a ring". But in reality, the "ring" that satisfies one of these things will not work for the other. If your best friend gets married and you add an image of the ring, then the next time your friend calls you, the phone ringing screen will try to play a JPEG as an MP3.

The "ring" example is, of course, slightly contrived, but I'm sure you can imagine a similar problem with real names, where you end up using the same term for two different and incompatible things.

What the OP is basically asking is, when Swift sees the same type conforming to Marriageable and CallReceivable, should it optimistically assume that the `ring` properties they both require are compatible and allow the code to pass through without comment? Or should it pessimistically assume that the `ring` properties are incompatible and emit a warning or error about them?

--
Brent Royal-Gordon
Architechies

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

Good point.

Protocol is a contract, it is natural to allow same item in multiple
protocol and eventually pointing to one single implementation.

By giving warning simply for same name, it will be quite annoying when the
project run into this situation without any wrong. For example:

protocol ForwardIndexType : _Incrementable {

    @warn_unused_result

    public func advancedBy(n: Self.Distance) -> Self

}

extension ForwardIndexType {

    @warn_unused_result

    public func advancedBy(n: Self.Distance) -> Self

    @warn_unused_result

    public func advancedBy(n: Self.Distance, limit: Self) -> Self

    @warn_unused_result

    public func distanceTo(end: Self) -> Self.Distance

}

protocol BidirectionalIndexType : ForwardIndexType

extension BidirectionalIndexType {

    @warn_unused_result

    public func advancedBy(n: Self.Distance) -> Self

    @warn_unused_result

    public func advancedBy(n: Self.Distance, limit: Self) -> Self

}

If a type conforms BidirectionalIndexType, it gets all these advancedBy().
OK, for this specific case we may workaround by assuming safe for those
inherited. Which means we only warn for same name item from protocols in
different protocol hierarchy without common root.

It is still doubtful even for this filtered case, because compiler cannot
tell it appears by intention or by mistake. We have to suppress it for
acceptable cases, that's annoying as protocol should allow it naturally.

There is a case good for throwing error: receiving item with same name but
different type from two protocols, but it is already an error now.

···

On Sat, Jan 9, 2016 at 11:47 AM, Wallacy via swift-evolution < swift-evolution@swift.org> wrote:

Storage properties on protocol or in extension plus something when call
maybe a solution:

       protocol Marriageable {
               var foo:Int = 0; // actual a var.
                var ring: String? // actual a var.
        }
        protocol CallReceivable {
                var ring: String? // actual a var.
        }

        struct Person: Marriageable, CallReceivable { }

OR
        protocol Marriageable {
                var ring: String? { get set }
        }
        protocol CallReceivable {
                var ring: String? { get set }
        }

        struct Person { }

       extension Person: Marriageable{
         var ring: String?
       }

     extension Person: CallReceivable{
         var ring: String?
       }

So:

var person = Person()
person.foo = 1 // ok

person.ring = getRingtone() // error, ring is ambiguous
(person as CallReceivable).ring = getRingtone() // ok
OR
person.CallReceivable.ring = getRingtone() // ok | CallReceivable is a
know person protocol, so can get a implicity dot notation,
like .dynamicType.staticMethod();

Anyway, it's not an easy problem to solve.

Em sáb, 9 de jan de 2016 às 01:09, Brent Royal-Gordon via swift-evolution < > swift-evolution@swift.org> escreveu:

> I don’t really get what you are driving at.

The point is that, although `A` and `B` both require properties with the
same name, they expect different semantics from that property. Let's maybe
give these more concrete names so you can understand the idea:

        protocol Marriageable {
                var ring: String? { get set } // File name of image of
this person's wedding ring.
        }
        protocol CallReceivable {
                var ring: String? { get set } // File name of ringtone
to be used for this person.
        }

        struct Person: Marriageable, CallReceivable {
                var ring: String?
        }

Of course a person is marriageable and can this have "a ring", and of
course you can also receive a call from them and they can thus have "a
ring". But in reality, the "ring" that satisfies one of these things will
not work for the other. If your best friend gets married and you add an
image of the ring, then the next time your friend calls you, the phone
ringing screen will try to play a JPEG as an MP3.

The "ring" example is, of course, slightly contrived, but I'm sure you
can imagine a similar problem with real names, where you end up using the
same term for two different and incompatible things.

What the OP is basically asking is, when Swift sees the same type
conforming to Marriageable and CallReceivable, should it optimistically
assume that the `ring` properties they both require are compatible and
allow the code to pass through without comment? Or should it
pessimistically assume that the `ring` properties are incompatible and emit
a warning or error about them?

--
Brent Royal-Gordon
Architechies

_______________________________________________
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

--
Best Regards!

Yang Wu
--------------------------------------------------------
Location: Pudong, Shanghai, China.
EMail : pinxue@gmail.com
Website: http://www.time2change.mobi http://rockplayer.com
Twitter/Weibo : @pinxue
<http://www.pinxue.net>

Exactly there are two cases. I am working on a legacy project (aka
working effective with legacy code). It is written in objective-c.
There is a real life example where it was a problem. Of course it is
different language, but I have stared experimenting with swift and
found the same behavior. Object was conforming to 10 protocols. I was
just expecting different behavior of the class looking at the first
protocol.

I agree that it was easy to find a problem, yes it was different
language and yes it was bad naming and bad code. But we do not always
design every single class and protocol. Devs on the project have
different level of knowledge. Swift is new, so it is not a problem
now, but legacy code evolves after years and years. I think it would
be really great if Swift as a protocol oriented language could give a
hint that protocols declare the same requirements. Similar to warning
'unused variable'.

Brent ask a really good question: 'so we have to decide if "two
unrelated protocols declare the same requirement" is a strong enough
signal on its own to conclude that something's wrong'.
I believe it is strong enough.

Below is another example, similar to what I was struggling with:

protocol PrivatePhotos {
  func photos() -> String
}
protocol PublicPhotos {
  func photos() -> String
}
class Flickr: PublicPhotos {
}
extension Flickr: PrivatePhotos {
  func photos() -> String {
    return ":rage:"
  }
}
class Newspaper {
  func printPaper(stock: PublicPhotos) {
    print(stock.photos())
  }
}
let stock: PublicPhotos = Flickr()
let dailyNews = Newspaper()
dailyNews.printPaper(stock) // private photos will be printed

Greg

···

2016-01-08 1:40 GMT+00:00 Jordan Rose <jordan_rose@apple.com>:

Mm. There are two cases here:

- Two protocols use the same method name for completely unrelated things.
- Two protocols use the same method name for similar things.

In the latter case, having one method satisfy both requirements is probably fine. In the former, there would definitely be a problem…but I have a hard time thinking of a type that should actually conform to two protocols that do completely different things and yet manage to use the same name for something. Do you have a real-life example where this has been a problem? Everything I can find online looks contrived.

Jordan

On Jan 7, 2016, at 2:18, Grzegorz Leszek via swift-evolution <swift-evolution@swift.org> wrote:

I suggest compile warning if one classes/structs/enums implements
protocols with the same name.
It could lead to confusions, when methods of those protocols will mean
different things.
It will force to implement parent protocol with shared methods or
change method in one of the protocols.
Below is an example.
Regards,
Greg

//:ring:
protocol A {
var ring: String { get }
}

//:bell:
protocol B {
var ring: String { get set }
}

class X: A, B {
var ring: String {
   get {
     return ":ring:"
   }
   set {
     self.ring = newValue
   }
}
}
let x = X()
let somewhereInTheProject = "\(x.ring) the bell"
x.ring = ":bell:" // ERROR!
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

1 Like

I like this approach, @implements is nice, clear, concise and handles many
cases.

It will require your proposal, or similar, to be universally applicable
though, but I expect it will pass: Naming Functions with Argument Labels.

Many Cocoa delegate protocols will have similar function names, ie.
collectionView(...).

···

On Thursday, 14 January 2016, Joe Groff via swift-evolution < swift-evolution@swift.org <javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>> wrote:

> On Jan 7, 2016, at 2:18 AM, Grzegorz Leszek via swift-evolution < > swift-evolution@swift.org> wrote:
>
> I suggest compile warning if one classes/structs/enums implements
> protocols with the same name.
> It could lead to confusions, when methods of those protocols will mean
> different things.
> It will force to implement parent protocol with shared methods or
> change method in one of the protocols.
> Below is an example.
> Regards,
> Greg
>
> //:ring:
> protocol A {
> var ring: String { get }
> }
>
> //:bell:
> protocol B {
> var ring: String { get set }
> }
>
> class X: A, B {
> var ring: String {
> get {
> return ":ring:"
> }
> set {
> self.ring = newValue
> }
> }
> }
> let x = X()
> let somewhereInTheProject = "\(x.ring) the bell"
> x.ring = ":bell:" // ERROR!

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
}

As other noted, protocols with same-named requirements but different
semantics are rare in practice, and it's occasionally useful to
intentionally overlap requirements (I believe the CollectionType hierarchy
does this in places), so the current behavior feels like a reasonable
default to me. I can see value in requiring it to be explicit though.

-Joe

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

Nice!

-Thorsten

···

Am 14.01.2016 um 00:48 schrieb Joe Groff via swift-evolution <swift-evolution@swift.org>:

On Jan 7, 2016, at 2:18 AM, Grzegorz Leszek via swift-evolution <swift-evolution@swift.org> wrote:

I suggest compile warning if one classes/structs/enums implements
protocols with the same name.
It could lead to confusions, when methods of those protocols will mean
different things.
It will force to implement parent protocol with shared methods or
change method in one of the protocols.
Below is an example.
Regards,
Greg

//:ring:
protocol A {
var ring: String { get }
}

//:bell:
protocol B {
var ring: String { get set }
}

class X: A, B {
var ring: String {
  get {
    return ":ring:"
  }
  set {
    self.ring = newValue
  }
}
}
let x = X()
let somewhereInTheProject = "\(x.ring) the bell"
x.ring = ":bell:" // ERROR!

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
}

As other noted, protocols with same-named requirements but different semantics are rare in practice, and it's occasionally useful to intentionally overlap requirements (I believe the CollectionType hierarchy does this in places), so the current behavior feels like a reasonable default to me. I can see value in requiring it to be explicit though.

-Joe

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

Because you cannot solve the problem by revising your own code. You definitely have to change the protocols. If you have no way to change the protocols, you will have to drop either of them.

My point is that it is the protocols' programmer who should take care of it, not you. Or if you write the protocols, you should avoid this at the beginning.

Well, that's exactly the point. In a perfect world, where the compiler could read your mind and figure out that the two protocols are incompatible, you would want Swift to raise an error indicating that the two protocols can't be used together. But the compiler can't read your mind, so we have to decide if "two unrelated protocols declare the same requirement" is a strong enough signal on its own to conclude that something's wrong.

···

--
Brent Royal-Gordon
Architechies

Wallacy's solution above is similar to how Rust handles a very similar
situation. Rust errors out where there are conflicting implementations of
trait requirements in the same "scope". See
Rust Playground for an
example.

···

On Sat, Jan 9, 2016 at 3:05 PM, Brent Royal-Gordon via swift-evolution < swift-evolution@swift.org> wrote:

> Because you cannot solve the problem by revising your own code. You
definitely have to change the protocols. If you have no way to change the
protocols, you will have to drop either of them.
>
> My point is that it is the protocols' programmer who should take care of
it, not you. Or if you write the protocols, you should avoid this at the
beginning.

Well, that's exactly the point. In a perfect world, where the compiler
could read your mind and figure out that the two protocols are
incompatible, you would want Swift to raise an error indicating that the
two protocols can't be used together. But the compiler can't read your
mind, so we have to decide if "two unrelated protocols declare the same
requirement" is a strong enough signal on its own to conclude that
something's wrong.

--
Brent Royal-Gordon
Architechies

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

--
Trent Nadeau

By giving warning simply for same name, it will be quite annoying when the project run into this situation without any wrong. For example:

protocol ForwardIndexType : _Incrementable {
    @warn_unused_result
    public func advancedBy(n: Self.Distance) -> Self
}

extension ForwardIndexType {
    @warn_unused_result
    public func advancedBy(n: Self.Distance) -> Self
    @warn_unused_result
    public func advancedBy(n: Self.Distance, limit: Self) -> Self
    @warn_unused_result
    public func distanceTo(end: Self) -> Self.Distance
}

protocol BidirectionalIndexType : ForwardIndexType
extension BidirectionalIndexType {
    @warn_unused_result
    public func advancedBy(n: Self.Distance) -> Self
    @warn_unused_result
    public func advancedBy(n: Self.Distance, limit: Self) -> Self
}

Firstly, for methods and subscriptors the "name" would actually encompass the entire signature, so `advancedBy(_:)` and `advancedBy(_:limit:)` would not conflict because they have different signatures.

Secondly, `ForwardIndexType` and `BidirectionalIndexType` are *not* unrelated protocols—one of them conforms to the other. Thus, we can assume that `BidirectionalIndexType` knows about `ForwardIndexType`'s `advancedBy` methods and intends for its versions to have compatible semantics.

If instead `BidirectionalIndexType` did *not* conform to `ForwardIndexType`, and `RandomAccessIndexType` tried to conform to both `ForwardIndexType` and `BidirectionalIndexType`, *then* we would get an error, because two independent protocols would have declared `advancedBy(_: Self.Distance) -> Self` methods and it's possible they meant for them to have different semantics.

···

--
Brent Royal-Gordon
Architechies

Sorry if this is already mentioned, but I quite like C#'s "Explicit
Interface Implementation" approach:

Basically:

var Marriageable.ring: String? { ... }
var CallReceivable.ring: String? { ... }

to call it you could do self.ring if it was unambiguous, otherwise:

(self as Marriageable).ring
(self as CallReceivable).ring

···

On Mon, Jan 11, 2016 at 9:51 AM, Brent Royal-Gordon via swift-evolution < swift-evolution@swift.org> wrote:

> By giving warning simply for same name, it will be quite annoying when
the project run into this situation without any wrong. For example:
>
> protocol ForwardIndexType : _Incrementable {
> @warn_unused_result
> public func advancedBy(n: Self.Distance) -> Self
> }
>
> extension ForwardIndexType {
> @warn_unused_result
> public func advancedBy(n: Self.Distance) -> Self
> @warn_unused_result
> public func advancedBy(n: Self.Distance, limit: Self) -> Self
> @warn_unused_result
> public func distanceTo(end: Self) -> Self.Distance
> }
>
> protocol BidirectionalIndexType : ForwardIndexType
> extension BidirectionalIndexType {
> @warn_unused_result
> public func advancedBy(n: Self.Distance) -> Self
> @warn_unused_result
> public func advancedBy(n: Self.Distance, limit: Self) -> Self
> }

Firstly, for methods and subscriptors the "name" would actually encompass
the entire signature, so `advancedBy(_:)` and `advancedBy(_:limit:)` would
not conflict because they have different signatures.

Secondly, `ForwardIndexType` and `BidirectionalIndexType` are *not*
unrelated protocols—one of them conforms to the other. Thus, we can assume
that `BidirectionalIndexType` knows about `ForwardIndexType`'s `advancedBy`
methods and intends for its versions to have compatible semantics.

If instead `BidirectionalIndexType` did *not* conform to
`ForwardIndexType`, and `RandomAccessIndexType` tried to conform to both
`ForwardIndexType` and `BidirectionalIndexType`, *then* we would get an
error, because two independent protocols would have declared `advancedBy(_:
Self.Distance) -> Self` methods and it's possible they meant for them to
have different semantics.

--
Brent Royal-Gordon
Architechies

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