Create a new instance of a class

268 zobrazení
Přeskočit na první nepřečtenou zprávu

Ernesto Karim Oltra

nepřečteno,
10. 2. 2012 15:47:3610.02.12
komu: General Dart Discussion
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

Gilad Bracha

nepřečteno,
10. 2. 2012 15:56:0410.02.12
komu: Ernesto Karim Oltra, General Dart Discussion
On Fri, Feb 10, 2012 at 12:47 PM, Ernesto Karim Oltra <ernest...@gmail.com> wrote:
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

Yes, you cannot instantiate a type parameter. 


What's the correct way to create a new instance of a generic class?

new Place<Presenter>();

But perhaps you were asking how to instantiate a type parameter? That is not supported at this time. 

 


Ernesto



--
Cheers, Gilad

Bob Nystrom

nepřečteno,
10. 2. 2012 16:55:3810.02.12
komu: Gilad Bracha, Ernesto Karim Oltra, General Dart Discussion
Since you can't instantiate a type parameter, the simplest workaround right now is probably to pass in a function when you instantiate the generic class:

class Place<P> {
  var pBuilder;

  Place(this.pBuilder);
  P presenter() => pBuilder();
}

new Place<Foo>(() => new Foo());

- bob

Ernesto Oltra

nepřečteno,
10. 2. 2012 17:27:0410.02.12
komu: mi...@dartlang.org
Hi Bob,

I was trying to implement some sort of MVP, so I finally make Place an interface, and each (x)Place returns the correct (x)Presenter. Define a function each time I change the Place it's not a good option I think.

Thanks anyway!

Ernesto

Jay Young

nepřečteno,
10. 2. 2012 19:22:0410.02.12
komu: mi...@dartlang.org
I really liked being able to pass around constructor functions in JS.  :(

Bob Nystrom

nepřečteno,
10. 2. 2012 20:10:3110.02.12
komu: Jay Young, mi...@dartlang.org
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.

- bob

Gilad Bracha

nepřečteno,
10. 2. 2012 20:41:4210.02.12
komu: Bob Nystrom, Jay Young, mi...@dartlang.org
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 typechecking and in terms of efficient implementation. But I hope we'll get there in due course. 


--
Cheers, Gilad

Paul Brauner

nepřečteno,
11. 2. 2012 10:19:3511.02.12
komu: Gilad Bracha, Bob Nystrom, Jay Young, mi...@dartlang.org
On Sat, Feb 11, 2012 at 02:41, Gilad Bracha <gbr...@google.com> wrote:


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.

- bob

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 typechecking

Depending 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

Dirk Detering

nepřečteno,
11. 2. 2012 11:00:0111.02.12
komu: Gilad Bracha, mi...@dartlang.org, Bob Nystrom, Jay Young


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?

Jay Young

nepřečteno,
11. 2. 2012 17:54:3811.02.12
komu: mi...@dartlang.org, Gilad Bracha, Bob Nystrom, Jay Young
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 shortcut

nav.Router.prototype.onNavigate = function() {
  // Much simplified
  var urlHash = location.hash;
  var handler = new this.urlMap[urlHash];
  // ...
};

This pattern is very powerful.  I don't know how well this can translate from Closure's type system to Dart's, but it seems easy enough to statically check.

Ladislav Thon

nepřečteno,
12. 2. 2012 10:04:1712.02.12
komu: Jay Young, mi...@dartlang.org, Gilad Bracha, Bob Nystrom
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:

This looks easy enough to translate using closures.
 
// 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
};

var urlMap = {
  '/new': () => new NewHandler(),
  '/edit': () => new EditHandler(),
  '/delete': () => new EditHandler()
};

Maybe a question here: can I closurize a constructor? I think not, but I might be wrong.

If I'd like to declare a static type, I'd do it like this:

// let's assume that Handler is an interface

interface Handler {
  ...
}

// sadly, I have to create a typedef
typedef Handler HandlerBuilder();

Map<String, HandlerBuilder> urlMap = ...;
 
/**
 * @param {Object.<string, function(new: nav.Handler)>} urlMap
 * @constructor
 */
nav.Router = function(this.urlMap) {...}; // To borrow from Dart's new, awesome shortcut

nav.Router.prototype.onNavigate = function() {
  // Much simplified
  var urlHash = location.hash;
  var handler = new this.urlMap[urlHash];
  // ...
};

class Router {
  final Map<String, HandlerBuilder> urlMap;

  Router(Map<String, HandlerBuilder> this.urlMap);

  onNavigate() {
    String urlHash = document.location.hash;
    Handler handler = urlMap[urlHash]();
    ...
  }
}

Note that I didn't try to run this code, but it has to work :-)

LT

Gilad Bracha

nepřečteno,
13. 2. 2012 10:47:5413.02.12
komu: Paul Brauner, Bob Nystrom, Jay Young, mi...@dartlang.org


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 typechecking

Depending 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.

The next question has been mentioned in other posts on this list: are constructors available as part of the interface of a class object? This is necessary to deal with the problem that prompted this thread.  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>.

Questions arise about whether "this" would be available in static method bodies, denoting the class rather than an instance in that context.  While perfectly logical,  static methods are not inherited in Dart, so there is little point, and it might confuse programmers who are not familiar with that model.  In any case, I don't want to go off on a tangent, so I'll set that discussion aside.



















 
 
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




--
Cheers, Gilad

Jay Young

nepřečteno,
13. 2. 2012 11:50:4313.02.12
komu: mi...@dartlang.org, Jay Young, Gilad Bracha, Bob Nystrom
Yep, this would certainly work for the simple case that I posted, but there are still disadvantages: no access to static properties, cannot use instanceof/"is", requires an extra function object for each constructor used.  There are work-around to each of these as well, of course.  I just find that this is a really nice use-case for first-class classes.

I'm not crying foul or saying Dart sucks (it doesn't, I like it!).  Just wanted to add my +1 to the conversation.

A Matías Quezada

nepřečteno,
13. 2. 2012 12:27:0413.02.12
komu: Jay Young, mi...@dartlang.org, Gilad Bracha, Bob Nystrom
+1

2012/2/13 Jay Young <jayyou...@gmail.com>

Paul Brauner

nepřečteno,
13. 2. 2012 19:42:0013.02.12
komu: Gilad Bracha, Bob Nystrom, Jay Young, mi...@dartlang.org
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 typechecking

Depending 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".

Gilad Bracha

nepřečteno,
13. 2. 2012 19:49:4713.02.12
komu: Paul Brauner, Bob Nystrom, Jay Young, mi...@dartlang.org
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 typechecking

Depending 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

Paul Brauner

nepřečteno,
13. 2. 2012 20:08:0213.02.12
komu: Gilad Bracha, Bob Nystrom, Jay Young, mi...@dartlang.org
On Tue, Feb 14, 2012 at 01:49, Gilad Bracha <gbr...@google.com> wrote:


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 typechecking

Depending 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.   


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

Gilad Bracha

nepřečteno,
13. 2. 2012 20:14:5713.02.12
komu: Paul Brauner, Bob Nystrom, Jay Young, mi...@dartlang.org
On Mon, Feb 13, 2012 at 5:08 PM, Paul Brauner <po...@google.com> wrote:


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"?

Assume class C as before. Then:

var c_class = C;
var c1 = new c_class();
var c2 = new c_class.namedConstructor(3); 
c_class.f();
var l = new List<c_class>(); //compile-time error


What if I want static typing? Well, maybe there is a special type syntax such as C.class for the type of C's class object:

C.class c_class = C;
C c1 = new c_class();
C c2 = new c_class.namedConstructor(3);

Caveat emptor, this is very preliminary.


--
Cheers, Gilad

Paul Brauner

nepřečteno,
13. 2. 2012 20:22:0013.02.12
komu: Gilad Bracha, Bob Nystrom, Jay Young, mi...@dartlang.org
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).


--
Cheers, Gilad

Gilad Bracha

nepřečteno,
13. 2. 2012 20:31:2413.02.12
komu: Paul Brauner, Bob Nystrom, Jay Young, mi...@dartlang.org
On Mon, Feb 13, 2012 at 5:22 PM, Paul Brauner <po...@google.com> wrote:

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).


Yes. You could also use a List<Dynamic> or List<Object> or List.  And we could potentially have Class, but it's not clear what function that would fulfill.  To make this useful, you might want to be able to declare that C.class implemented some other interfaces, and you'd want to be able to express that a type parameter conformed to a type like C.class. So there are a few more pieces you need, but ultimately, this is actually simpler than the Strongtalk type system we developed back 1992-95. I'm sure we can figure it out in 2012 if we chose to go that route.

There is a run time aspect to this of course.  However, given that generics are reified, we already have a lot of the machinery in place.

--
Cheers, Gilad

Jay Young

nepřečteno,
13. 2. 2012 20:38:1613.02.12
komu: mi...@dartlang.org, Jay Young, Gilad Bracha, Bob Nystrom
For anyone interested, the appropriate issue to star or comment on is http://code.google.com/p/dart/issues/detail?id=739

Dirk Detering

nepřečteno,
13. 2. 2012 23:34:5613.02.12
komu: Gilad Bracha, mi...@dartlang.org, Bob Nystrom, Paul Brauner, Jay Young


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.

Bob Nystrom

nepřečteno,
14. 2. 2012 1:54:4014.02.12
komu: Dirk Detering, Gilad Bracha, mi...@dartlang.org, Paul Brauner, Jay Young
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:

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

Paul Brauner

nepřečteno,
14. 2. 2012 4:47:0114.02.12
komu: Bob Nystrom, General Dart Discussion, Gilad Bracha, Dirk Detering, Jay Young

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?

Sean Eagan

nepřečteno,
14. 2. 2012 8:31:0514.02.12
komu: Paul Brauner, Bob Nystrom, General Dart Discussion, Gilad Bracha, Dirk Detering, Jay Young

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.
--
Sean Eagan

Gilad Bracha

nepřečteno,
14. 2. 2012 13:55:3814.02.12
komu: Paul Brauner, Bob Nystrom, General Dart Discussion, Dirk Detering, Jay Young
Bob is correct: there need to be constraints on X if the example is to pass the typechecker without warnings.

On Tue, Feb 14, 2012 at 1:47 AM, Paul Brauner <po...@google.com> wrote:

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?


The type of the class object would indeed be implicitly defined by its static methods and constructors, much as the type of instances is. You would have to put an explicit bound on X however if you wanted to call such statics/constructors. Precise mechanism TBD.

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:


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.

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:

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



--
Cheers, Gilad

Gilad Bracha

nepřečteno,
14. 2. 2012 14:01:0114.02.12
komu: Sean Eagan, Paul Brauner, Bob Nystrom, General Dart Discussion, Dirk Detering, Jay Young
On Tue, Feb 14, 2012 at 5:31 AM, Sean Eagan <seane...@gmail.com> wrote:

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.

Good point. I'd expect that all the class objects would inherit from Object and get the normal noSuchMethod behavior from there. If we wanted to override it, we'd have to do something special :-(.  It's a complication, because static methods and instance methods share the namespace. 



--
Cheers, Gilad
Odpovědět všem
Odpověď autorovi
Přeposlat
0 nových zpráv