#1977 Disregard type parameter when comparing Lists

ikhwanhayat Wed 25 Jul 2012

Hi, lets say I have list1 := Str["a", "b", "c"] and list2 := Obj["a", "b", "c"].

If in my system, I want to treat those as equals (comparing the inner items instead of the List type), what is the best way to do this?

list1 == list2, list1 === list2, and list1.equals(list2) will of course return false. How do I do this without iterating all the items?

SlimerDude Thu 26 Jul 2012

I'm not sure why you'd ever have the same list declared as different types but...

The two lists are different because they are declared with a different type (see sys::List#of) which is read only. So the only way I can think of is creating new lists with a common type and comparing those...

list1.map |o->Obj| { o } == list2.map |o->Obj| { o }

How do I do this without iterating all the items?

Well someone, somewhere would have to iterate over the items! :)

helium Thu 26 Jul 2012

You can't do that without iterating over the items.

brian Thu 26 Jul 2012

There is no built-in method to compare list items without taking type into account. Although I believe it has been discussed before with varying levels of support and dissent

ikhwanhayat Thu 26 Jul 2012

I'm not sure why you'd ever have the same list declared as different types but...

It's not actually declared like that, I'm making it simple for the sake of asking. What I have is a method accepting a generic Obj?[] and the comparison is done in there.

Because the lack of method overloading, I found myself always using Obj? as the argument and then do type checking in the method body to do different things. Is this the right way to do stuff in Fantom?

Well someone, somewhere would have to iterate over the items! :)

I sure hope it's not me :D

Thanks for replies guys...

SlimerDude Thu 26 Jul 2012

using Obj? as the argument and then do type checking in the method body to do different things

Err, that sounds orrible!

As they do different things, can you not break it out into different methods with different names?

And I'd avoid the null type (Obj?) as much as possible unless you really have to. One of the things I like about Fantom is that my objs are usually guaranteed not to be null.

ikhwanhayat Thu 26 Jul 2012

As they do different things, can you not break it out into different methods with different names?

API looks cleaner with method overloading. Let say I have a method that accepts a type, and then I want another one that do the same thing but accepts the type name instead. So basically in Fantom I accepts an Obj then check whether its a Type or an Str.

I'm thinking that maybe Fantom is pushing us to achieve polymorphism via classes instead of methods.

SlimerDude Thu 26 Jul 2012

See Method Overloading for a quick explanation of why Fantom doesn't allow it.

My favourite comment is: (!)

I personally think that no methods/fields overloading is one of the best feature of Fan :)

SlimerDude Fri 27 Jul 2012

When I first moved to Fantom I felt the lack of method overloading a little restrictive, but since I started using Fantom properly, I've barely noticed.

Convention (or an easy way out) is to add the type sig to the method name. e.g. from sys::Int don't have:

plus(Decimal dec) {...
plus(Float float) {...

but rather

plusDecimal(Decimal dec) {...
plusFloat(Float float) {...

which turns out to be a lot more explicit, hence I would say better.

And I'd briefly refer you to StackOverflows Is method overloading a form of polymorphism or something else?

ikhwanhayat Fri 27 Jul 2012

I've read those posts in this forum and agree that no method overloading makes it simpler, like when working with reflections (which I also seem to use a lot in Fantom). Also, when you have default/named parameters you don't really need method overloading. I guess the pro is more than the cons.

I think it would be really good if there's a guide for this kind of things, like how you do it in Fantom when usually you do it with method overloading in other languages. Also for generics, null checking, etc. Some kind of recipes or cookbook.

brian Fri 27 Jul 2012

To get back to the original issue, would everybody like to see something like a a new method on List for:

Bool valsEqual(List that)

Yeah or nay or other ideas?

Akcelisto Fri 27 Jul 2012

No matter. I never compare lists.

SlimerDude Fri 27 Jul 2012

How about a method that returns a new List backed by a new type? That would allow you to up or downcast every item in the list then you could do l1 == l2 as usuall.

ikhwanhayat Fri 27 Jul 2012

Yes, obviously :)

ikhwanhayat Fri 27 Jul 2012

How about a method that returns a new List backed by a new type? That would allow you to up or downcast every item in the list then you could do l1 == l2 as usuall.

Wouldn't that take much more from performance compared to comparing items 1 by 1?

SlimerDude Sat 28 Jul 2012

I was thinking of a method such as

List.toTypeOf(Type typeOf) throws CastErr

which returns a new list of a different type which in your example would allow you to do:

list1.toTypeOf(Str#) == list2.toTypeOf(Str#)

Not that I think I'd ever have use for it.

Though, to be honest, I'd be happy with the List.equals only checking the contents of the List so we don't have to think / bother with this List.typeOf stuff. I can't remember a time when I've been concerned about the List impl. I see a list as a transparent wrapper caring only about what it contains.

Although I believe it has been discussed before with varying levels of support and dissent

Hmm, I'd be interested to find out what the objections were.

brian Sat 28 Jul 2012

which returns a new list of a different type which in your example would allow you to do:

That is already pretty trivial like this (and probably maybe even a little more readable to show intent):

foo := Str[,].addAll(oldList)

Though, to be honest, I'd be happy with the List.equals only checking the contents of the List

I think most people would consider type to be an inherit quality to identity and equality. For example Str[,] really is not the same thing as Int[,] and they will behave quite differently when you go to add stuff.

Hmm, I'd be interested to find out what the objections were.

I don't think this has even bothered me in normal code. Where it gets a bit annoying is testing code. But the basic idea was that if you are actually writing a test case, you should be checking the list type to make sure you aren't returning a Obj[] when you should have been returning a Foo[].

SlimerDude Sat 28 Jul 2012

foo := Str[,].addAll(oldList)

Nice one.

most people would consider type to be an inherit quality to identity and equality

I did quibble with this myself, but then realised I've never cared about the List type, namely because...

example Str[,] is not the same as Int[,] and will behave quite differently

...it's all picked up by the compiler.

Meanwhile, I (myslef) am non-plussed about a Bool valsEqual(List that) for I can't see me using it. And a :

Str[,].addAll(list1) == Str[,].addAll(list2)

would suffice should I ever need to.

ikhwanhayat Sat 28 Jul 2012

I just noticed something.

fansh> a := Obj["1","2"]
[1, 2]
fansh> b := Str["1","2"]
[1, 2]
fansh> a == b
false
fansh> a.hash == b.hash
true

So in List's case, equality doesn't means the hashes are equal.

Also if valsEqual(List other) is to be implemented, it can just be a wrapper around this.hash == other.hash right?

SlimerDude Sat 28 Jul 2012

Err no. Because you're comparing hashes, not Obj contents. Although very unlikely, hashes (by their very nature) are not guaranteed to be unique. They only exist to help hashtables.

From Java's Object#hashcode JavaDoc:

It is not required that if two objects are unequal according to the java.lang.Object#equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.

At most a hash is just a checksum - it doesn't guarantee uniqueness.

Login or Signup to reply.