#839 Generics in Fan: an alternative

DanielFath Sat 28 Nov 2009

Ok, let me get this clear, I'm a strong proponent of generics and while not having generics is in its way is an interesting thought experiment I'm still having trouble grasping the dynamic thingamajig.

As of late I've been reading on Go and its interfaces and I think it would be a great way to implement a sort of quasi generics that allow somewhat strong typing while keeping in spirit with Fantom's lax typing style.

By defining an interface by specifying required slots. For instance:

interface Number
{
   This defVal
   This plus(This e);
   This minus(This e);
   This mult(This e);
   This div(This e);
   //This foo(Bool g)
}

Now any class that has the slots defined in in Number like for example Complex,

class Complex
{
  ...
  Complex defVal
  Complex plus(Complex comp)
  Complex minus(Complex comp)
  Complex mult(Complex comp)
  Complex div(Complex comp)
  //Complex foo(Bool bar)
  ...
} 

would satisfy Number interface.

If I define a field or a parameter Number then I basically get all of them to have the same slots. Of course trying to declare a variable Number, would only work if you define it as variable before hand.

Number n 
n := 3 //ok
...
n := Number() //makes no sense since interfaces don't have a constructor

Now that is out of the way, the details would probably go like this. Until declaring a variable an interface field/variable would not be given any type. Once declared the interface field/variable would behave exactly like Lists behave today.

Number n
n.type //returns either Void, some other type or more throws a RuntimeError
n := 3 
n.type //=> sys:Int

Once declared the interface field would behave as if it is Obj+slots from its definition.

Number n := 3
n.toStr //=> 3 belongs to Obj
n+2 // => 5 belongs to Number definition
n.random //Compile Error
n->random //It works, yay!

So any thoughts on this?

brian Sat 28 Nov 2009

I think Go's interfaces are interesting - I'd call them a form of structural typing. I am not sure that sort of structural typing would really provide any value to aid Fantom's lack of generics. I think rather it would more a safer way to do Fantom's duck typing using the dynamic invoke and automatic coercion. The Number example you use is a bit tricky b/c they are such a huge special case in Fantom since Int and Float are value types and so specially optimized by the runtimes.

The problem with introducing such a design into Fantom is that none of the runtime's we use efficiently dispatch using that model - likely it would perform about the same as dynamic calls (without or without the dynamicinvoke opcode in JDK 1.7). Also I think given Fantoms existing design to embrace classes, mixins, and dynamic duck typing - I doubt we'd want to introduce another mechanism to the type system (certainly not for 1.0).

tactics Sat 28 Nov 2009

No one ever complained that Perl, Python, or Ruby didn't have generics. Dynamic languages get by just fine without them. Fantom is really a dynamic language with a thin layer of typing. Whereas languages like C# and Scala aim to give you a type system as strong as the lock on a bank's safe, Fantom's typesystem is a simple padlock. It's only there to guard against careless mistakes.

tcolar Sat 28 Nov 2009

I'm not sure I agree with "Fantom is really a dynamic language with a thin layer of typing"(sound like groovy).

I feel is more like the other way around: Fairly strong typing/static with a layer of dynamism when needed, which is a sweet spot for me.

As for generics personally I like the concept - the most typed the better - but I have also not seen an implementation of generics that is clean enough to be worth it.

Java certainly always felt like a too large amount of pain, and a painful syntax, not worth the return.

Maybe Brian can come up with something much simpler and cleaner, but since it was decided not to do generics I guess not.

The fact that List/Maps have "generics-like" features is a decent tradeof since that's where it's most needed.

I like it the way it is really.

brian Sat 28 Nov 2009

Fantom definitely straddles b/w strong and dynamic typing. My personal slant is to say it is mostly statically typed since all slots and variables have a compile time type. But I think we've done a pretty good job of mixing in the dynamic side of things so that it feels like a dynamic language (but with the performance of Java :-)

I wouldn't say we will never add generics or structural types to Fantom if we could find a pragmatic design that didn't add too much complexity. But any major changes to type system are almost certainly out until we can ship a finished 1.0 with the existing type system and APIs all polished up.

tactics Sun 29 Nov 2009

At least from what I've seen, for some reason, the lack of generics is the biggest criticism of Fantom from Java/C# developers. I presenting Fantom as a dynamic(er) language will help new users come to accept that.

brian Sun 29 Nov 2009

At least from what I've seen, for some reason, the lack of generics is the biggest criticism of Fantom from Java/C# developers

Yeah this does seem get raised a lot, which is a little surprising since both languages started off without generics. And no one seems like them in Java. But explaining the dynamic side of Fantom is another way to approach the problem is definitely a good way to spin it.

alexlamsl Mon 30 Nov 2009

And no one seems like them in Java.

I guess I am the odd one out then ;-)

Although I can certainly understand that some find it over-complicated and difficult to understand, whilst the other half (which I am sometimes on) find it a bit under-powered as it is right now.

brian Mon 30 Nov 2009

Although I can certainly understand that some find it over-complicated and difficult to understand

The problem with generics in an OO type system is that to do them right you have to get into all sorts of nasty issues with covariance, contravariance, wildcards, bounded types, etc. And truth be told, I can't ever remember what this is supposed to mean in Java:

abstract class Enum<E extends Enum<E>>

Every time I see that, it elicits a WTF. Scala gets praise for OO generics done right, but at the expense of extra complexity.

My personal opinion is that having nullablity and immutability built into the Fantom type system provides way more value to the pragmatic programmer than user defined generics.

alexlamsl Mon 30 Nov 2009

My personal opinion is that having nullablity and immutability built into the Fantom type system provides way more value to the pragmatic programmer than user defined generics.

Whilst I am truly thankful about nullability and immutability, I don't see why these features would be mutually exclusive with generics.

One of the problems I am trying to tackle looks like this:

public interface Addition<E extends Element> {
  E plus(E addend);

  public interface Associative<E extends Element> extends Addition<E> {
    E plus(List<? extends E> addends);
  }

  public interface Commutative<E extends Element> extends Associative<E> {
    E plus(Collection<? extends E> addends);
  }
}

public interface Multiplication<E extends Element> {
  E times(E addend);

  public interface Associative<E extends Element> extends Addition<E> {
    E times(List<? extends E> addends);
  }

  public interface Commutative<E extends Element> extends Associative<E> {
    E times(Collection<? extends E> addends);
  }
}

The aim is for the programmer to create use a class by extending the right interfaces, and all the requirements for the system would be immediately obvious.

The users of the system would also benefit from the fact that the compiler would check for all the possible loop-holes in the axioms as they setup the program.

Although, I guess there would exist a counter-argument whereby some users would get rather annoyed when they can't get rid of those compiler errors, and would just duck-type everything together instead :-p

helium Mon 30 Nov 2009

If you add generics do it the C#/Scala way not the Java way. User side variance annotations might allow the user to do some extra things but I believe it's of purely theoretical value and has absolutely no relevance in praxis. I have never had a time where I thought it would be nice to have it or where I felt restricted in any way using Scala's generics.

Scala gets praise for OO generics done right, but at the expense of extra complexity.

Actually I find them a lot easier to use. Of course Scala has a lot of extras but you don't have to implement everything Scala has.

I'd be almost happy with just pure basic generics. An upper bound would be very nice and I think very easy to understand. You can only use types which at least implement a certain interface. For example you can restrict the key type of a tree to types which are comparable to themselves.

Variance on the library designer side like in Scala or C# 4.0 would be nice, too, but I could live without it. But if you use in and out like C# rather than + and - people might have an easier time to understand or at least remember it.

You don't have to remember that input arguments are contravariant and output/return values are covariant. Input -> in, output -> out. Done. (The compiler could even infer it, but I don't recommend this.)

And most importantly as a user of a library you don't have to think about variance at all as the library designer has done that thinking for you. I think that's what's most "wrong" with Java's generics (that and type erasure).

helium Mon 30 Nov 2009

...

qualidafial Tue 1 Dec 2009

abstract class Enum<E extends Enum<E>>

The Java pattern Foo<T extends Foo<T>> is the ugly twin of Fantom's This construct.

The Enum.getDeclaringClass method is parameterized to return Class<E>. By parameterizing the class using E extends Enum<E> the compiler is guaranteeing that subclasses are self-parameterized. Thus when Foo extends Enum<Foo>, Foo.getDeclaringClass is guaranteed to return type Class<Foo>.

Login or Signup to reply.