-
Notifications
You must be signed in to change notification settings - Fork 213
allow more compact definition of generic classes with type parameters that extend other generic classes #102
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
Comments
A problem with the class A<T extends B<U,V,W>> {
U u;
} syntax is that class A<T extends B<U, V, W>, U, W> {
U u;
} which only takes three type arguments. Such "breaking at a distance" is a sign of a fragile language feature design. Readability-wise, a reader has no clue (except the single-letter names) that I think this would be sacrificing significant readability for a very minor gain in characters written. |
I understand that it is important to have all type parameters introduced in the definition of class Suppose, you have a class A<C,?,?> a; Maybe, instead of changing the syntax of class definitions, this situation can also be tackled by extending the possibility of optional type arguments or on the level of the analyzer. Now, if I am not mistaken, type arguments are optional, but you have to either write none or all of them. Suppose you have the following class: class A<T extends num> {
T value;
} Then, when you define a variable Now, suppose you have the following classes: class A<T extends B<U, V, W>, U, W> {
U u;
}
class C extends B<int, bool, String> {
} If you now define a variable A<C,int,String> a; or replace them with A<C,dynamic,dynamic> a; In the latter case, you can not profit from code completion or error detection, because the analyzer does not seem to derive the bounds on Maybe, writing |
I have another example where I want to have "optional generics": B useBloc<B extends Bloc<T>, T>([T initialValue]) =>
Hook.use(_BlocHook<B>(initialValue)); The usage of this function is: useBloc<WithInitialValueBloc, int>(5);
useBloc<WithoutInitialValueBloc, void>(); I think that It'll be much better if I can use above functions without syntactic sugar: useBloc<WithInitialValueBloc>(5); // function will accepts only `int` arguments implicitly
useBloc<WithoutInitialValueBloc>(); |
There is one issue with the following setup: abstract class BaseBloc<S> { Stream<S> get stream; }
abstract class Bloc<S> extends BaseBloc<S> {} // Guessing.
class BaseBlocComponent<T extends Bloc<S>/*,S*/> {
final T bloc;
S currentState;
BaseBlocComponent(this.bloc) {
bloc.stream.listen((state) => currentState = state);
}
}
class MyState {}
class MySmartState implements MyState {}
class MyBloc extends Bloc<MySmartState> { get stream => null; }
class MyComponent extends BaseBlocComponent<MyBloc/*, MyState*/> {
MyComponent(MyBloc bloc): super(bloc);
} If you allow the type argument Also, you can pass type arguments like But if you always want to use a specific type for the type parameter whose bound relies on the remaining type parameters then you could just invert the pattern: class BaseBlocComponent<S> {
final Bloc<S> bloc; // <----- Inline former type parameter `T` here!
S currentState;
BaseBlocComponent(this.bloc) {
bloc.stream.listen((state) => currentState = state);
}
}
class MyComponent extends BaseBlocComponent<MyState> {
MyComponent(MyBloc bloc): super(bloc);
} So do you actually need to know that the If you really do need that, then I think the most workable idea would be to allow partial instantiation to bound (this is a possible extension to the current instantiation to bound mechanism): class C<X extends num> {}
class D<X extends D<X>> {}
class BaseBlocComponent<T extends Bloc<S>, S> {}
// Regular instantiation to bound.
C c; // Means `C<num>`.
D d; // Means `D<D<dynamic>>`.
// Now the partial kind: Type argument `_` is "explicitly omitted".
class Foo extends BaseBlocComponent<_, MyState> {}
PS: Instantiation to bound might change to use |
Seems like similar to #620 |
When defining a generic class which has a generic parameter that should extend a type that in turn is a generic class, you now have to add all the generic parameters of the second type also in the parameter list of the first class to be able to access those type parameters. This is cumbersome and seems unnecessary.
For example, the following definition:
could be simplified to:
I don't think that allowing this syntax would have any implications or breaking changes, it would simply be syntactic sugar for the first syntax.
A concrete example is the following situation. Suppose you are using the BLoC pattern and have a base class for blocs
BaseBloc
which has a generic parameter that defines the state:and a base class for components in
AngularDart
(or widgets orflutter
):You could now implement a concrete state, bloc and component:
The text was updated successfully, but these errors were encountered: