You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// In class Teststaticpublic <T> Ttransfer(ArrayList<T> l, Stack<T> s) {
while (!s.empty()) {
l.add(s.pop());
}
returnl.get(0); // just so it's not void
}
Right now, calling this in Dart is like this:
Test.transfer(Integer.type, intList, intStack);
Even though in Java, we're able to do
Test.transfer(intList, intStack);
and have it automatically infer the type parameter T.
We could try doing the same in Dart. Instead of passing T as the first ordered argument, we can pass it as an (in this case) optional type parameter.
Also it's useful to have assertions making sure l.$type.$T and s.$type.$T are the exact same. This is because in Dart we could pass ArrayList<Integer> and Stack<Number>. T will be Number but we know that a Number cannot be added to an ArrayList<Integer>!
We'd also need k - 1 equality assertions for k arguments that have T type parameter. Of course, this gets more complicated when we have multiple type parameters.
Different variants
transfer method in the example above can only transfer elements of Stack<T> to an ArrayList<T>. We want to make this method more generic, so that we can transfer any Stack<U> to an ArrayList<T> where U <: T. Let's change the signature to allow this:
// In class Teststaticpublic <T> Ttransfer(ArrayList<T> l, Stack<? extendsT> s) {
while (!s.empty()) {
l.add(s.pop());
}
returnl.get(0);
}
Now the assertion in Dart would have to be changed as well:
This should only work when l.$type.$T is a supertype of s.$type.$T.
Conclusion
As you can see, there are many cases that need to be thoroughly tested.
Performance
The type graph is not going to be super deep. So naive implementation does the job in most cases.
We're using the operations of type is_ancestor? and lowest_common_ancestor a lot. So keeping not only the supertypes but also jumps with powers of two (parent, grandparent, grandparent of grandparent, ...) can improve the performance in cases where we have many layers of subclass/superclasses.
The text was updated successfully, but these errors were encountered:
HosseinYousefi
changed the title
Type "inferring" for generics
Type "inference" for generics
Dec 14, 2022
Simple example
Let's take this add method:
Right now, calling this in Dart is like this:
Even though in Java, we're able to do
and have it automatically infer the type parameter
T
.We could try doing the same in Dart. Instead of passing
T
as the first ordered argument, we can pass it as an (in this case) optional type parameter.In the body of the function, we will have to have something like:
Also it's useful to have assertions making sure
l.$type.$T
ands.$type.$T
are the exact same. This is because in Dart we could passArrayList<Integer>
andStack<Number>
.T
will beNumber
but we know that aNumber
cannot be added to anArrayList<Integer>
!The type parameter in this case looks like so:
Higher depths!
But they can be arbitrarily deep, for example if instead of
ArrayList<T>
we haveArrayList<HashMap<String, T>>
:The generated code also gets more complicated:
We'd also need
k - 1
equality assertions fork
arguments that haveT
type parameter. Of course, this gets more complicated when we have multiple type parameters.Different variants
transfer
method in the example above can only transfer elements ofStack<T>
to anArrayList<T>
. We want to make this method more generic, so that we can transfer anyStack<U>
to anArrayList<T>
whereU <: T
. Let's change the signature to allow this:Now the assertion in Dart would have to be changed as well:
? super T
would be similar to? extends T
.Lowest common ancestor type
Now let's say that we don't have any type
T
directly.In this case
$T
should be the lowest common ancesstor ofs.$type.$T
andt.$type.$T
. Take these classes:Here
Test.randomFirst(listOfC, listOfE)
should have a type ofA
.Supers and extends
What about a combination of
super
andextends
?This should only work when
l.$type.$T
is a supertype ofs.$type.$T
.Conclusion
As you can see, there are many cases that need to be thoroughly tested.
Performance
The type graph is not going to be super deep. So naive implementation does the job in most cases.
We're using the operations of type
is_ancestor?
andlowest_common_ancestor
a lot. So keeping not only the supertypes but also jumps with powers of two (parent, grandparent, grandparent of grandparent, ...) can improve the performance in cases where we have many layers of subclass/superclasses.The text was updated successfully, but these errors were encountered: