#1601 Type.parameterize equality bug

DanielFath Tue 2 Aug 2011

class TestEq : Test{
  Void testBasic()
  {
       grPersons :=
       [
         0 : [Person {name = "John"; age = 26; canCode = true}],
         1 : [Person {name = "Daniel"; age = 26; canCode = false}],
         2 : [Person {name = "Donovan"; age = 41; canCode = true}]
       ] 

       data := [[Person {name = "John"; age = 26; canCode = true}],
               [Person {name = "Daniel"; age = 26; canCode = false}],
               [Person {name = "Donovan"; age = 41; canCode = true}]] 

       listType := List#.parameterize(["V":data.of])
       type := Map#.parameterize(["K":Int#, "V":listType])
       grPersons2:= Map.make(type)

       grPersons2.add(0, [Person {name = "John"; age = 26; canCode = true}])
       grPersons2.add(1, [Person {name = "Daniel"; age = 26; canCode = false}]) 
       grPersons2.add(2, [Person {name = "Donovan"; age = 41; canCode = true}])

       verifyEq(grPersons, grPersons2)

 }
}

And the Person class just for record.

internal const class Person
{
  const Str? name
  const Int? age
  const Bool? canCode

  new make(|This|? f := null)  { if(f != null) {f(this)} }

  override Bool equals(Obj? o)
  {
     if(o == null) return false
     x := o as Person
     if(x == null) return false
     return (name == x.name && age == x.age && canCode == x.canCode)
  }

  override Int hash()
  {
     hash := 17
     hash += hash*(name?.hash ?: 0)
     hash += hash*(age?.hash ?: 0)
     hash += hash*(canCode?.hash ?: 0)
     return hash 
  }

  override Str toStr()
  {
    return "Person{name:$name age:$age canCode:$canCode}"
  }
}

If I replace

listType := List#.parameterize(["V":data.of])
type := Map#.parameterize(["K":Int#, "V":listType])
grPersons2:= Map.make(type)

with

grPersons2 := [Int:Persons[]][:]

It works fine. I even think that it gives 0 when comparing and that the hashes are equal. I'd love if there was some easier way to compare two maps/lists, but if I have to adhere to adhere to strong casting with verifyEq I'd at least would like to be able to be able to construct it dynamically.

brian Tue 2 Aug 2011

Is the problem that using Type.paramaterize is not treating equality correctly?

Or just that you want a way to do equality in tests without worrying about list/map type?

DanielFath Tue 2 Aug 2011

It's definitively former. Type.parameterize and/or equals (from the Map) isn't behaving properly. Both structures have same hash, contents and type signature and yet yield not equals. Something is fishy (I've looked at the content thoroughly and they are if I'm not mistaken same). I tried debugging it myself but I couldn't for the love of me, see what returned the false result - all I know is that some part of Map equals returns invalid result.

brian Wed 3 Aug 2011

Renamed from Issue with equality to Type.parameterize equality bug

brian Wed 3 Aug 2011

Promoted to ticket #1601 and assigned to brian

ok, will take a look

DanielFath Sat 8 Oct 2011

Brian, I'm quite sorry about this one but it seems the type system was more complicated than I thought. Anyway my test is wrong.

listType := List#.parameterize(["V":data.of])
//Needs to be
listType := List#.parameterize(["V":data.of.params["V"]])

PS. I still managed to get this error:

[0:[Person{name:John age:26 canCode:true}], 1:[Person{name:Daniel age:26  canCode:false}], 2:[Person{name:Donovan age:41 canCode:true}]] [[sys::Int:finq::Person[]]] != [0:[Person{name:John age:26 canCode:true}], 1:[Person{name:Daniel age:26 canCode:false}], 2:[Person{name:Donovan age:41 canCode:true}]] [[sys::Int:finq::Person[]]]

Which looks odd.

DanielFath Sat 8 Oct 2011

Here is the new test that causes error, I'm not sure if it is an error however...

**
** ** A test class for testing 'GROUP BY' statements
**
class GroupByTest : Test
{
  internal static const Person[] persons := 
  [
    Person {name = "John"; age = 26; canCode = true},
    Person {name = "Daniel"; age = 26; canCode = false},
    Person {name = "Donovan"; age = 41; canCode = true}
  ] 

  Void testBasic()
  {
    grPersons:= 
      [
        0 : [Person {name = "John"; age = 26; canCode = true}],
        1 : [Person {name = "Daniel"; age = 26; canCode = false}],
        2 : [Person {name = "Donovan"; age = 41; canCode = true}]
      ]

    data:= persons
    listType := List#.parameterize(["V":data.of] )
    type := Map#.parameterize(["K":Int#, "V":listType])

    [Obj:Obj[]]? retVal := Map.make(type)

    i := 0
    x:= retVal.containsKey(0)
    data.size.times 
    { 
      if(!retVal.containsKey(i))
      {
        retVal.add(i, [,])
      }

      list := retVal[i++]
      list.add(data[it])
    }

    verifyEq(retVal, select)
    verifyEq(select.typeof, grPersons.typeof)
    verifyEq(select, grPersons)

  }

  static [Int:Person[]] select()
  {
    data:= persons
    listType := List#.parameterize(["V":data.of] )
    type := Map#.parameterize(["K":Int#, "V":listType])

    [Obj:Obj[]]? retVal := Map.make(type)

    i := 0
    x:= retVal.containsKey(0)
    data.size.times 
    { 
      if(!retVal.containsKey(i))
      {
        retVal.add(i, [,])
      }

      list := retVal[i++]
      list.add(data[it])
    }

    return retVal    
  }

}

From what I've seen the problem is when that if List passes throught a method it loses some of its type signatures. The first two verify will pass, only third will fail.

EDIT: Error occurs somewhere in Map.java. How do I debug that?

brian Sat 8 Oct 2011

The maps are not equal because their items are not equal. The items are not equal because the inferred type in grPersons is that each list is Person[], but in your select method are creating generic Obj?[] lists:

// create Obj?[]
retVal.add(i, [,])

// should be   
retVal.add(i, Person[,])

Remember that in the end each value of map of list is checked for equality.

So I don't think there is any problem here?

DanielFath Sat 8 Oct 2011

Hmm. Yeah I missed that one list. Tnx for debugging for me :P.

Case closed. It was my error. Still for reference how do you guys debug the Java native/peer clases? You use System.out or could I use Fantom's logger?

brian Sun 9 Oct 2011

Ticket cancelled

Still for reference how do you guys debug the Java native/peer clases

I debug all my code using echo/System.out.println - although virtually all my debugging is spent in test suite itself.

Login or Signup to reply.