Page 1 of 1

Greatest Common Denominator Type

PostPosted: Sat Mar 22, 2008 5:56 pm
by Charles
Cobra has a concept called the "greatest common denominator type" (GCDT) which comes up in type inference. For example:
vehicles = [Car(), Boat()]
numbers = [1, 2, 3]
plural = if(count==1, '', 's')
config = {'x': 1, 'y': 2}

Assuming that Car and Boat are subclasses of Vehicle, then the GCDT between a car and a boat is Vehicle.

The GCDT of two identical types is the same type. So "[1, 2, 3]" is a List<of int>.

For static types, the worst case GCDT is System.Object or System.Object? because all objects in .NET are considered descendants of it. For example, the inferred type of "if(cond, 5, 'abc')" is System.Object.

Basically, the GCDT is the closest type that both types have in common.

Introducing a "nil" or a nilable type will cause the resulting GCDT type to be nilable as well.

Introducing a "dynamic" type will cause the resulting GCDT to be dynamic as well.

Dictionaries have two type parameters, the key and the value, and Cobra infers their type separately so that you can have a Dictionary<of String, int>.

Overall, this approach works really well, but sometimes I end up with a type that is too specific, usually because I'm seeding the list with one element such as "[Car()]" which will be List<of Car> when maybe I really wanted a List<of Vehicle>. This can be overcome with a typecast such as "[Car() to Vehicle]".

Of course, you can always construct the collection yourself:
v = List<of Vehicle>()
v.add(Car())

What if the collection is empty? Then the type is "dynamic" which you can also explicitly create with "List<of dynamic>()".

Does this make sense? Do you have any questions? If so, let me know.