Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subtype relation requires same number of type parameters. Can that be improved? #7

Open
lrhn opened this issue Mar 19, 2015 · 4 comments

Comments

@lrhn
Copy link

lrhn commented Mar 19, 2015

The subtyping relation between generic functions require them to have the same number of generic parameters. For classes that is not always the case. For example:

   class IdentityTranform<T> implements Transformation<T, T> { ... }

Since you "invoke" each type individually, there is no problem.
Instance methods can override the superclass version, and we allow a different number of parameters, as long as its compatible (by some of the parameters being optional).

Would we want a sub-class method to allow more type parameters, or to accept fewer? That is, should we have optional type parameters?
Maybe something like:

     T foo<T, S>(S value, T convert(S value)) ....

being overridden by

    T foo<T, S, [R = S]>(S value, T convert1(S value), [T convert(R value), R otherValue]) ....

Optional type parameters would be written as [T = defaultType, ...] where the default-type can be any type, including earlier parameters of the same function.

Does this make any sense?

@zoechi
Copy link

zoechi commented Mar 19, 2015

How to only pass the 3rd type argument but not the 2nd (in a list of 3+), would you pass dynamic for the 2nd or would this need named optional type arguments, and would it then still take the specified default type for the 2nd? :-/

@leafpetersen
Copy link
Owner

The comparison to class inheritance is a bit of a red herring I think - there is no subtyping between generic classes in Dart, only generic class instantiations. This isn't really observable since any use of a class is either as an explicit instantiation (List<T>) or an implicit instantiation (List), but nonetheless...

That aside, yes, there are things we could do with this that could be interesting. If we relaxed the semantics on arity mismatches on type argument lists so that passing too few parameters filled in the rest with dynamic, and/or passing too many dropped the extra, then we could usefully allow things with different number of type arguments to be subtypes. I don't really like this approach - it doesn't match up with how generic classes behave (where if you get the arity wrong there you get all dynamic) - and it seems kind of error prone. It's not totally unreasonable though.

Adding optional type arguments with a default is something that I think probably work out fairly nicely though. @jakemac53 brought this up in conversation yesterday as something he would be interested in. Your example above is a good one - adding optional arguments is a valid extension, and you might want an additional type argument to describe the type of the optional arguments.

It would probably be useful to provide syntax at the call side to use the default argument at a specific position: e.g. foo<int, _, String> could mean instantiate foo with int, the default for the second position (dynamic if none?) and String.

It would be nice if calling a generic without any type arguments at all used the defaults instead of dynamic. foo(a, b) means foo<_, _, _>(a, b). This might be an argument for adding this to the proposal now, to avoid having a quasi-breaking change later. Alternatively there could be syntax for this: e.g. foo<>(a, b) means use all of the default parameters, or perhaps foo<_>(a, b)?

I had actually considered adding something like this to the generic methods proposal, but felt that it would be nice to add this uniformly to both generic classes and generic methods, and so was considering that it might be useful to do this as a separate DEP. But I'm open to making it part of this DEP - either only for generic methods, or for both.

Named type arguments could also probably be made to work out. My initial reaction is to say that perhaps that's more mechanism then we really need, but if there are good use scenarios then we could consider it.

@jmesserly
Copy link
Contributor

optional args reminded me of class Point<T extends num> where folks pointed out that defaulting T to dynamic isn't very useful. So you almost want to have something more like class Point<T extends num = num> or interpret it as that.

@lrhn
Copy link
Author

lrhn commented Mar 21, 2015

I agree that the comparison with class type parameters doesn't really give anything - the real comparison is with instance method parameters where the corresponding method in a subclass can have more optional parameters. Since generic methods will be part of the class signature, subclasses will need to be compatible with super-classes, but having some wiggle room is usually a good idea.

And it might be better served in another DEP, since adding optional type parameters should also apply to classes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants