Fan has two design decisions that might work out together: no generics and no overloading. I have mixed feelings on the generics subject, since I don't think generics need to be as complicated as Java and Scala make them. But leaving that aside, disallowing overloading makes for the wonderful option of ad hoc covariant and contravariant parameters. If we don't use those words, I think the concepts are easy to understand for most programmers, and it gets around some of the lack of generics. For example, here's the hypothetical Collection type from another thread:
Contravariance should be allowed, too. Or in other words, the same rules already available for casting.
In my experience, people inherently know what they are doing when they do things like this. It's natural and easy to do. I know it's not fandangledy pure from a typing perspective, but I just don't care since it works in practice.
At the binary level, the methods would really take Java and C# Object under the covers. Otherwise the overriding wouldn't work in those languages, since they do overloading. But I don't think that will ruin anything. And in fact, we could potentially generate overloaded (final?) versions that use the sub or super type and just call the common case. And for odd cases of overriding methods with different param types from different super classes/mixins, there might be some requirement to sneak in these extra methods. But I think it would work.
And I really think this kind of feature is necessary for easy/clear coding if Fan doesn't support generics directly.
Just some thoughts.
tompalmerSat 21 Jun 2008
Oh, and there would also be a cast under the covers, generated by the compiler (or rather, the JVM/CLR bytecode generator) in the overriding method, for example:
OK, so what exactly is the type system in Fan suppost to do? At least it seems not to be there to catch any kind of type errors.
Perhaps Fan should switch to a system like in Dylan or something?
A little off-topic: What is complicated about Scala's generics?
tompalmerSat 21 Jun 2008
Concerning Scala, I still don't understand different nesting levels of existential types. I think I understand everything else, but there's still a lot to learn and lots of rules to follow. Perfect static typing is a red herring.
Old-timey Java could always guarantee it knew the class of an object before calling an operation, and Fan (including all my recommendations) can do the same. Execution is fast, and find references and refactoring still would work easily.
How often did you actually see ClassCastExceptions in Java before Java 5? I've seen large code bases (1000s of files) maintained for years by large teams of varied experience levels with almost never a ClassCastException. Generics, if they exist, should only exist for a bit of extra understanding (and they're great that way), not for perfect guarantees of static type safety.
Just my own perspective, of course.
heliumSat 21 Jun 2008
Yes, existential types in Scala are confusing, but you don't need them very often. Normaly you should try to model your problem using abstract type members. But existential types aren't directly related to generics. You can write
def foo(x : t forSome { type t }) = ...
or
def bar(x : t forSome { type t <: A }) = ...
. (OK, I assume you won't do this.)
I like type systems, but I absolutly don't like Java's type system and Java's generics are broken.
tompalmerSat 21 Jun 2008
I've read Odersky recommending nested types. I think there are pros and cons. (Not that I have the years of experience to state what works best there.) But in general, I'd take Fan's current system over Scala's generics and abstract types. Time will tell what proves popular (not necessarily what works best, though). I imagine it's hard to constrain experimental controls in programming languages to vary only one aspect of a system. Push one thing in here, something else pops out there. (I think I heard Gosling using the analogy of "whack-a-mole".
Anyway, to my original example, here's how you'd have to code it in Fan today (not tested, so I could be making mistakes):
which is not verbose and typesafe. (I used "of" here for the typeparameter.)
Covariant types in contravariant positions are IMO bad. Well, I think that "no generics" is a not good thing.
To me downcasting in general feels wrong. In most cases you either made a design error or your type system is just too week to express what you realy mean, you are just fighting against the type system and just because it lacks information that it could/should have.
So you see I come from a complitly different camp than you. And perhpas my preferences don't fit to Fan very well.
tompalmerSat 21 Jun 2008
I can't speak for Andy or Brian. I'm just describing my own perspective.
Anyway, you must be here for a reason (as we all are for our own reasons). What are your gripes with Scala?
I agree that contravariance happens in the real world, but it doesn't work with OO type systems very well.
And I definitely can see how you arrived at this issue - trying to figure out how do unified collections with a mixin. But I just assume solve that problem using duck typing.
To me the quintessential APIs which really scream for contravariance are Obj.equals and Obj.compare (which we talked about a bit on the other thread).
tompalmer Sat 21 Jun 2008
Fan has two design decisions that might work out together: no generics and no overloading. I have mixed feelings on the generics subject, since I don't think generics need to be as complicated as Java and Scala make them. But leaving that aside, disallowing overloading makes for the wonderful option of ad hoc covariant and contravariant parameters. If we don't use those words, I think the concepts are easy to understand for most programmers, and it gets around some of the lack of generics. For example, here's the hypothetical Collection type from another thread:
Well, say I want to make a composite Widget class. Just let me use covariance if I want to do so:
Contravariance should be allowed, too. Or in other words, the same rules already available for casting.
In my experience, people inherently know what they are doing when they do things like this. It's natural and easy to do. I know it's not fandangledy pure from a typing perspective, but I just don't care since it works in practice.
At the binary level, the methods would really take Java and C#
Object
under the covers. Otherwise the overriding wouldn't work in those languages, since they do overloading. But I don't think that will ruin anything. And in fact, we could potentially generate overloaded (final?) versions that use the sub or super type and just call the common case. And for odd cases of overriding methods with different param types from different super classes/mixins, there might be some requirement to sneak in these extra methods. But I think it would work.And I really think this kind of feature is necessary for easy/clear coding if Fan doesn't support generics directly.
Just some thoughts.
tompalmer Sat 21 Jun 2008
Oh, and there would also be a cast under the covers, generated by the compiler (or rather, the JVM/CLR bytecode generator) in the overriding method, for example:
helium Sat 21 Jun 2008
OK, so what exactly is the type system in Fan suppost to do? At least it seems not to be there to catch any kind of type errors.
Perhaps Fan should switch to a system like in Dylan or something?
A little off-topic: What is complicated about Scala's generics?
tompalmer Sat 21 Jun 2008
Concerning Scala, I still don't understand different nesting levels of existential types. I think I understand everything else, but there's still a lot to learn and lots of rules to follow. Perfect static typing is a red herring.
Old-timey Java could always guarantee it knew the class of an object before calling an operation, and Fan (including all my recommendations) can do the same. Execution is fast, and find references and refactoring still would work easily.
How often did you actually see ClassCastExceptions in Java before Java 5? I've seen large code bases (1000s of files) maintained for years by large teams of varied experience levels with almost never a ClassCastException. Generics, if they exist, should only exist for a bit of extra understanding (and they're great that way), not for perfect guarantees of static type safety.
Just my own perspective, of course.
helium Sat 21 Jun 2008
Yes, existential types in Scala are confusing, but you don't need them very often. Normaly you should try to model your problem using abstract type members. But existential types aren't directly related to generics. You can write
or
. (OK, I assume you won't do this.)
I like type systems, but I absolutly don't like Java's type system and Java's generics are broken.
tompalmer Sat 21 Jun 2008
I've read Odersky recommending nested types. I think there are pros and cons. (Not that I have the years of experience to state what works best there.) But in general, I'd take Fan's current system over Scala's generics and abstract types. Time will tell what proves popular (not necessarily what works best, though). I imagine it's hard to constrain experimental controls in programming languages to vary only one aspect of a system. Push one thing in here, something else pops out there. (I think I heard Gosling using the analogy of "whack-a-mole".
Anyway, to my original example, here's how you'd have to code it in Fan today (not tested, so I could be making mistakes):
Same effect, but more code and less clear. That's why I recommend co/contravariant parameters.
helium Sat 21 Jun 2008
But only because there are no generics. Otherwise you'd write:
which is not verbose and typesafe. (I used "of" here for the typeparameter.)
Covariant types in contravariant positions are IMO bad. Well, I think that "no generics" is a not good thing.
To me downcasting in general feels wrong. In most cases you either made a design error or your type system is just too week to express what you realy mean, you are just fighting against the type system and just because it lacks information that it could/should have.
So you see I come from a complitly different camp than you. And perhpas my preferences don't fit to Fan very well.
tompalmer Sat 21 Jun 2008
I can't speak for Andy or Brian. I'm just describing my own perspective.
Anyway, you must be here for a reason (as we all are for our own reasons). What are your gripes with Scala?
brian Sun 22 Jun 2008
There was an earlier discussion on contravariance when designing this types: http://www.fandev.org/sidewalk/topic/205.
I agree that contravariance happens in the real world, but it doesn't work with OO type systems very well.
And I definitely can see how you arrived at this issue - trying to figure out how do unified collections with a mixin. But I just assume solve that problem using duck typing.
To me the quintessential APIs which really scream for contravariance are Obj.equals and Obj.compare (which we talked about a bit on the other thread).
tompalmer Sun 22 Jun 2008
Thanks for the pointer.