Hi,
The code & the error speak for themselves:
class Place<P> {
P presenter() => new P();
}
Error: line 31 pos 29: type parameter 'P' cannot be instantiated
What's the correct way to create a new instance of a generic class?
Ernesto
I really liked being able to pass around constructor functions in JS. :(
On Fri, Feb 10, 2012 at 5:10 PM, Bob Nystrom <rnys...@google.com> wrote:
On Fri, Feb 10, 2012 at 4:22 PM, Jay Young <jayyou...@gmail.com> wrote:I really liked being able to pass around constructor functions in JS. :(I do too. We may get there with Dart eventually. We are still very early in and there's lots of work left to do.- bobIMO answer should be to make classes first class, so you could pass them in, and consider static methods and constructors as methods on the classes. In the case above, you would not even need to pass anything (you've already passed it in as the type parameter). However, this is a bit more complicated than it looks in terms of typechecking
and in terms of efficient implementation. But I hope we'll get there in due course.
--
Cheers, Gilad
Am 11.02.2012 02:41 schrieb "Gilad Bracha" <gbr...@google.com>:
> In the case above, you would not even need to pass >anything (you've already passed it in as the type parameter).
Well, there is yet a difference between type and class. So having a type parameter at design time of the generic type does not necessarily give information on how to instanciate the concrete type given as argument at runtime.
For Some<T> let that be Some<int>, Some<MyClass> or Some<MyInterface>. How would you know about the correct way to construct a specific T?
To give a concrete example, the specific case where I've found this most useful in JS is having a map which maps strings to constructors of classes that implement an interface. I have a routing component based on URL hash codes. The routing component is given a map of hash patterns to constructors that implement a Handler interface:
// Using Closure type annotations, this looks like:/*** An object mapping strings to constructors that implement the nav.Handler interface* @Object.<string, function(new: nav.Handler)>*/var urlMap = {'/new': handlers.NewHandler,'/edit': handlers.EditHandler,'/delete': handlers.DeleteHandler};
/*** @param {Object.<string, function(new: nav.Handler)>} urlMap* @constructor*/nav.Router = function(this.urlMap) {...}; // To borrow from Dart's new, awesome shortcutnav.Router.prototype.onNavigate = function() {// Much simplifiedvar urlHash = location.hash;var handler = new this.urlMap[urlHash];// ...};
IMO answer should be to make classes first class, so you could pass them in, and consider static methods and constructors as methods on the classes. In the case above, you would not even need to pass anything (you've already passed it in as the type parameter). However, this is a bit more complicated than it looks in terms of typecheckingDepending on the meaning of "first class" this could even make typechecking undecidable, or force a conversion to Dynamic (I guess that's what you mean by this is a bit more complicated than it looks in terms of typechecking but I wanted to stress it just in case).
and in terms of efficient implementation. But I hope we'll get there in due course.In the meantime, a solution along the lines of the getter/setters discussion could be to mix Bob's solution and extend the closurization operator for constructors. This wouldn't be redundant with first-class classes as there would always be some function waiting for a function of type "() => SomeClass". On the other hand, this sounds like a syntactic gadget.--
Cheers, Gilad
On Sat, Feb 11, 2012 at 7:19 AM, Paul Brauner <po...@google.com> wrote:<snip>IMO answer should be to make classes first class, so you could pass them in, and consider static methods and constructors as methods on the classes. In the case above, you would not even need to pass anything (you've already passed it in as the type parameter). However, this is a bit more complicated than it looks in terms of typecheckingDepending on the meaning of "first class" this could even make typechecking undecidable, or force a conversion to Dynamic (I guess that's what you mean by this is a bit more complicated than it looks in terms of typechecking but I wanted to stress it just in case).Actually, I was not suggesting first class *types*, and all the accompanying baggage of type Type etc. First class classes are much more straightforward, yet still not entirely trivial. If class names denote objects that can be passed along, stored etc., we need to know what their API is. Presumably, static methods are effectively instance methods on these objects.
On Mon, Feb 13, 2012 at 16:47, Gilad Bracha <gbr...@google.com> wrote:On Sat, Feb 11, 2012 at 7:19 AM, Paul Brauner <po...@google.com> wrote:<snip>IMO answer should be to make classes first class, so you could pass them in, and consider static methods and constructors as methods on the classes. In the case above, you would not even need to pass anything (you've already passed it in as the type parameter). However, this is a bit more complicated than it looks in terms of typecheckingDepending on the meaning of "first class" this could even make typechecking undecidable, or force a conversion to Dynamic (I guess that's what you mean by this is a bit more complicated than it looks in terms of typechecking but I wanted to stress it just in case).Actually, I was not suggesting first class *types*, and all the accompanying baggage of type Type etc. First class classes are much more straightforward, yet still not entirely trivial. If class names denote objects that can be passed along, stored etc., we need to know what their API is. Presumably, static methods are effectively instance methods on these objects.Ok, so if you have a list classes of type List<Class>, the static type of the expression new classes[0]() will necessarily be Dynamic. That's what I meant by "[you will have to] force a conversion to Dynamic".
On Mon, Feb 13, 2012 at 4:42 PM, Paul Brauner <po...@google.com> wrote:On Mon, Feb 13, 2012 at 16:47, Gilad Bracha <gbr...@google.com> wrote:On Sat, Feb 11, 2012 at 7:19 AM, Paul Brauner <po...@google.com> wrote:<snip>IMO answer should be to make classes first class, so you could pass them in, and consider static methods and constructors as methods on the classes. In the case above, you would not even need to pass anything (you've already passed it in as the type parameter). However, this is a bit more complicated than it looks in terms of typecheckingDepending on the meaning of "first class" this could even make typechecking undecidable, or force a conversion to Dynamic (I guess that's what you mean by this is a bit more complicated than it looks in terms of typechecking but I wanted to stress it just in case).Actually, I was not suggesting first class *types*, and all the accompanying baggage of type Type etc. First class classes are much more straightforward, yet still not entirely trivial. If class names denote objects that can be passed along, stored etc., we need to know what their API is. Presumably, static methods are effectively instance methods on these objects.Ok, so if you have a list classes of type List<Class>, the static type of the expression new classes[0]() will necessarily be Dynamic. That's what I meant by "[you will have to] force a conversion to Dynamic".a) I have not even suggested that these class types necessarily have a common supertype Class.
b) Actually, this is a static type warning. We don't know that classes necessarily have a nullary unnamed constructor.
c) The key point to avoid an undecidable type system is that that only literal types can be passed as type arguments.
--
Cheers, Gilad
a) I have not even suggested that these class types necessarily have a common supertype Class.Yes sorry, I assumed there had to be one from your sentence "that can be passed along, stored etc."b) Actually, this is a static type warning. We don't know that classes necessarily have a nullary unnamed constructor.I was wondering about that here.c) The key point to avoid an undecidable type system is that that only literal types can be passed as type arguments.Same as a): was mislead by "stored". This sounds like a good strategy indeed. Bu then, what do you mean by "stored"?
--
Cheers, Gilad
Ok, I get it. It looks to me you could always store c_class in a List<C.class> (though such a list would make little sense since all its elements would be either C or null).
Am 13.02.2012 16:48 schrieb "Gilad Bracha" <gbr...@google.com>:
> So, given
>
> class C {
> C() ...
> C.namedConstructor(x) ...
> static f() ...
> }
>
> Foo<X> {
> bar => new X();
> baz => new X.namedConstructor(3);
> bam => X.f();
> }
>
> we might write Foo<C>.
>
Gilad, perhaps I missed something, but how would the checker assure that C is valid for X, i.e. that all the assumptions made in Foo about X are matched?
There are no constraints for X.
That would be some kind of inferred structural type for the static part of the class + structural subtyping for type parameter instantiation (very much like ML modules). Nice, is that the kind of things you have in mind Gilad?
That would be some kind of inferred structural type for the static part of the class + structural subtyping for type parameter instantiation (very much like ML modules). Nice, is that the kind of things you have in mind Gilad?
On Feb 14, 2012 1:55 PM, "Bob Nystrom" <rnys...@google.com> wrote:On Mon, Feb 13, 2012 at 8:34 PM, Dirk Detering <mail...@googlemail.com> wrote:I think the idea is that there would be constraints for X. In particular, there would be constraints that the metaclass of X must satisfy. So, given:
Am 13.02.2012 16:48 schrieb "Gilad Bracha" <gbr...@google.com>:
> So, given
>
> class C {
> C() ...
> C.namedConstructor(x) ...
> static f() ...
> }
>
> Foo<X> {
> bar => new X();
> baz => new X.namedConstructor(3);
> bam => X.f();
> }
>
> we might write Foo<C>.
>Gilad, perhaps I missed something, but how would the checker assure that C is valid for X, i.e. that all the assumptions made in Foo about X are matched?
There are no constraints for X.bar => new X();
baz => new X.namedConstructor(3);
bam => X.f();If you consider X to be a first-class class (i.e. an object), then that object has a class (a metaclass). We could conceivably support specifying type constraints on that, which would basically indicate what static methods are allowed on type parameters. Constructor invocations then are essentially just static methods like they are in Smalltalk and Ruby. (More properly, they are instance methods on the metaclass.)- bob
First-class classes would probably require adding a noSuchMethod at the static level as well. Presumably they could inherit the noSuchMethod of their super-metaclass if they didn't define one.