Skip to content

FR: Add generic type <T> to Type or suggest alternative #30115

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

Closed
matanlurey opened this issue Jul 8, 2017 · 3 comments
Closed

FR: Add generic type <T> to Type or suggest alternative #30115

matanlurey opened this issue Jul 8, 2017 · 3 comments
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). type-enhancement A request for a change that isn't a bug

Comments

@matanlurey
Copy link
Contributor

matanlurey commented Jul 8, 2017

Apologies and please close if this a duplicate, but I couldn't find it.

In AngularDart, Type is used both as a compile-time symbol/token for many operations, such as dependency injection. For example, here is a way a user might say "allow injecting RpcService, and create a new instance of CachedRpcService to satisfy the dependency":

const Provider(RpcService, useClass: CachedRpcService)

Unfortunately, there is no good way for me to use types to help users from making silly mistakes. For example, this is totally valid, and will appear to work until runtime:

const Provider(RpcService, useClass: LinkedHashMap)

I realize we could write our own lints+analyzer plugin+yada yada, but this seems like a legitimate place where a generic type argument to Type could give this to us for free. For example, imagine we did the following:

abstract class Provider<T> {
  const Provider({Type<T> useClass}); 
}

const Provider<RpcService>(useClass: CachedRpcService) // OK
const Provider<RpcService>(useClass: LinkedHashMap) // Static analysis errors

I considered the alternative of constructor tear-offs, for example:

const Provider<RpcService>(useFactory: CachedRpcService.new)

But I run into a similar issue, there is no way to statically say "a function with any number or type of arguments as long as it returns T". Any ideas?

@lrhn
Copy link
Member

lrhn commented Jul 10, 2017

All in all, I have no good alternative right now.

As a general rule, the Type class, as it is currently declared, is utterly useless and any attempt to use it is probably broken (except perhaps when using mirrors, which I'm guessing that you do).
Adding a type parameter to Type likely won't make that any better, since you still can't use that for anything except putting constraints on the type object, and you still shouldn't be using the type object anyway.

Strong mode allows methods to have type parameters. That's more useful because type parameters can actually be used in is checks. That is the alternative I'd recommend:

class Provider<T>;
  const factory Provider() = _ProviderUseClass<T, U>;
  const factory Provider.useClass<U extends T>() = _ProviderUseClass<T, U>;
}
class _ProviderUseClass<T, U> implements Provider<T> {
  ...
}

or

abstract class Provider<T> {
  const factory Provider = ProviderUSeClass<T, T>;
}
class ProviderUseClass<T, UseClass extends T> implements Provider<T> {
  const ProviderUseClass();
}

The former still requires us to allow type parameters on named constructors, so also not a solution yet, even in strong mode, and strong mode doesn't work in production either.

The latter works, but requires the user to use a different class instead of an argument in the constructor.

Another "solution" would be to not pass raw types, but require the user to wrap them in a class:

const Provider<RpcService>(useClass: const UseClass<CachedRpcService>());

Heck, you could event let the UseClass

The "function with return-type T" is also a known problem. Even with the new Function syntax, you have to specify the arguments in some way, so you can't say "function that returns T, but with any arguments". We generally don't have a way of saying "function with any parameter signature" because that's not a useful type constraint – it won't allow you to call the function in any way – so it's more like a wildcard than an actual type. It's the opposite of a type constraint, so it's not easy to add to the type system.

@lrhn lrhn added area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). type-enhancement A request for a change that isn't a bug labels Jul 10, 2017
@leafpetersen
Copy link
Member

We've discussed both of these in the past. Here was my summary of the final discussion of Function<T>: #26420 (comment)

We generally don't have a way of saying "function with any parameter signature" because that's not a useful type constraint – it won't allow you to call the function in any way – so it's more like a wildcard than an actual type. It's the opposite of a type constraint, so it's not easy to add to the type system.

Not sure I understand this. Function currently means "any function", and is callable as a dynamic call. Function<int> would mean "any function returning an integer", and would be callable as dynamic call. I don't immediately see any semantic or type system difficulties.

@matanlurey
Copy link
Contributor Author

After understanding how types work over the last year, I no longer consider my request valid :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

3 participants