operator overloads


(Jon Rafkind) #1

How does the Swift compiler determine which method or operator to call given a set of overloads at a given call site? This question may conflate two issues: method overloads and operator overloads, but it seems at least superficially that they are related. Somehow they end up using different rules as I will demonstrate shortly.

<code>
class A{
}

class B: A {
}

func +(a:A, b:A){
  print("+1")
}

func +(a:A, b:B){
  print("+2")
}

func +(a:B, b:A){
  print("+3")
}

/*
func +(a:B, b:B){
  print("+4")
}
*/

A() + A() // prints +1
A() + B() // prints +1
B() + A() // prints +1
// B() + B() // will come back to this

func f(a: A, b: A){
  print("f1")
}

func f(a: B, b: A){
  print("f2")
}

func f(a: A, b: B){
  print("f3")
}

/*
func f(a: B, b: B){
  print("f4")
}
*/

f(A(), b: A()) // prints f1
f(B(), b: A()) // prints f2
f(A(), b: B()) // prints f3
// f(B(), b: B()) // will come back to this
</code>

The output from the various invocations of f() make sense. It seems that Swift uses similar overload resolution rules as Java where the 'most specific method' is chosen given a set of methods whose parameters are part of the same class hierarchy.

Given the code as-is, the outputs from the operator overloads all seem to call the first operator defined. The order of definition doesn't matter, if +(A, A) is put last it will still be called by all three invocations of +. Already this doesn't make sense to me. Why isn't +(A, B) called for the expression A() + B()?
Something strange happens when the function +(B, B) is uncommented out. All of a sudden the overloads work just like they did in the regular function definition case.

The full code is:

<code>
func +(a:A, b:A){
  print("+1")
}

func +(a:A, b:B){
  print("+2")
}

func +(a:B, b:A){
  print("+3")
}

func +(a:B, b:B){
  print("+4")
}

A() + A() // prints +1
A() + B() // prints +2
B() + A() // prints +3
B() + B() // prints +4
</code>

Without the definition of +(B, B) the expression B() + B() is an error because it is ambiguous whether to choose +(A, B) or +(B, A). I am fine with that behavior. But why do A()+B() and B()+A() suddenly refer to the +2 and +3 operators respectively?

The regular function case does not behave this way. Given the 3 uncommented defintions of f as above the output is as expected, f1, f2, f3 in order. When the definition of f(B, B) is uncommented the expression f(B(), B()) works as expected and prints f4. The other expressions are unaffected.

···

--


(Dmitri Gribenko) #2

This looks like a bug to me, would you mind filing it on
https://bugs.swift.org/ ?

Dmitri

···

On Thu, Dec 17, 2015 at 11:20 AM, Rafkind, Jon via swift-dev <swift-dev@swift.org> wrote:

How does the Swift compiler determine which method or operator to call given a set of overloads at a given call site? This question may conflate two issues: method overloads and operator overloads, but it seems at least superficially that they are related. Somehow they end up using different rules as I will demonstrate shortly.

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Jon Rafkind) #3

Ok I will. I just wanted to make sure it was buggy behavior before filing.

···

On 12/17/2015 11:24 AM, Dmitri Gribenko wrote:

On Thu, Dec 17, 2015 at 11:20 AM, Rafkind, Jon via swift-dev <swift-dev@swift.org><mailto:swift-dev@swift.org> wrote:

How does the Swift compiler determine which method or operator to call given a set of overloads at a given call site? This question may conflate two issues: method overloads and operator overloads, but it seems at least superficially that they are related. Somehow they end up using different rules as I will demonstrate shortly.

This looks like a bug to me, would you mind filing it on
https://bugs.swift.org/ ?

Dmitri

--