#739 Problem with implicit casts?

IvanI Fri 11 Sep 2009

Hello, Today I found the problem with mismatching actual object field type with field definition from class.

Here is an example:

class Foo {

new make(Foo[] foos := [,]) {this.foos = foos}
Foo[] foos
Int i := 1
public static Void main()
{
  echo(Foo().foos.type)  //prints sys::Obj?[]
  echo(Foo([Foo()]).foos.type) //prints sys::Obj[]
}

}

After changing constructor parameter to Foo[] foos := Foo[,] everything works as expected. I think there should be either a compile error (like default parameter value does not match to parameter type), or implicit cast to Foo[], but this does not happen.

As a result, there is a problem with object equality.

For example, we override sys::Obj.equals method like this:

override Bool equals(Obj? that) {

if(that == null || that isnot Foo) return false
return that->foos == foos && that->i == i

}

And then have code like this:

public static Void main() {

foos := [Foo(), Foo()]
a := Foo(foos)
b := Foo()
b.foos.addAll(a.foos)
echo("(a == b) = ${a == b}")  //false!

}

brian Fri 11 Sep 2009

Promoted to ticket #739 and assigned to brian

Yeap, that is a definitely a bug - the compiler should catch that and perform an implicit cast.

brian Thu 5 Nov 2009

Ticket cancelled

Ok, I dug into this and I don't think there is a problem.

The compiler is correctly inserting a coerce opcode. For example:

static Void foo(Obj x := 3) { echo(x) }

Will compile into:

foo (sys::Obj x) -> sys::Void [const public static]
  [Param 0] x -> sys::Obj
    0: LoadInt             3
    3: Coerce              sys::Int => sys::Obj
  [Code]
    0: LoadVar             0
    3: CallStatic          sys::Obj.echo(sys::Obj?) -> sys::Void
    6: Return

In this particular case, casting a list doesn't actually change the type of the original list. So your can use Obj[,] where a Foo[] is expected. But the original list never changes its type. So you fix to change the default parameter to Foo[] is the right solution.

Login or Signup to reply.