Programmatically instantiate a typed generic list

150 views
Skip to first unread message

Robert Åkerblom-Andersson

unread,
Aug 27, 2014, 2:54:37 PM8/27/14
to mi...@dartlang.org
Hi, 

I would like to get some input if it is possible or not to programmatically instantiate a typed generic list or not? (aka List<int> and not List/List<dynamic>)

My current conclusion is that it is not possible, but I would be happy if someone could either prove be wrong or agree with me so I know for sure (and can make an issue for it). The reason for this is that I'm working on a Json serialization library and I can recreate most things with mirrors right but not generic lists. 

Here are some code examples to see what I'm referring to:
  // Works
  ClassMirror m1 = reflectClass(List);
  print(m1.newInstance(new Symbol(''), []));

  // Does not work, reflectClass does not allow 'List<int>'
//  ClassMirror m2 = reflectClass(List<int>);
//  print(m2.newInstance(new Symbol(''), []));

  // Does not work, No constructor '_GrowableList.' declared in class 'List'.
//  InstanceMirror m3 = reflect(new List());
//  print(m3.type.newInstance(new Symbol(''), []));

  // Does not work, No constructor '_GrowableList.' declared in class 'List'.
//  InstanceMirror m4 = reflect(new List<int>());
//  print(m4.type.newInstance(new Symbol(''), []));


If I could create "m2" that would be the best I think, but unfortunately I can't get that to happen. Any ideas on this? If I should do an issue, what do you guys think of asking "reflectClass" to support generic types, good or bad idea? Or do you have any other ideas of how to express this behavior, and to be clear, I would like to be able to create any List<UserDefinedClass> list.

Regards, Robert 

Gilad Bracha

unread,
Aug 27, 2014, 3:32:15 PM8/27/14
to General Dart Discussion

  InstanceMirror m4 = reflect(new List<int>());

  ClassMirror listOfInt = m4.type.superinterfaces[0];  // prints List, but it is really List<int>

  print(listOfInt.typeArguments); // prints 'int'



--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new

To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.



--
Cheers, Gilad

Robert Åkerblom-Andersson

unread,
Aug 27, 2014, 3:45:48 PM8/27/14
to mi...@dartlang.org
Hi Gilad and thanks for the quick reply!

Your solutions seems to work. Here are some more examples for the curious reader:

  class TestClass {
    int value = 42;
  }

  InstanceMirror m4 = reflect(new List<int>());
  ClassMirror listOfInt = m4.type.superinterfaces[0];
  var l4 = listOfInt.newInstance(new Symbol(''), []).reflectee;
  print(l4.runtimeType);

  InstanceMirror m5 = reflect(new List<TestClass>());
  ClassMirror listOfTestClass = m5.type.superinterfaces[0];
  var l5 = listOfTestClass.newInstance(new Symbol(''), []).reflectee;
  print(l5.runtimeType);

Prints:
List<int>
List<TestClass>


Cheers, Robert 

Robert Åkerblom-Andersson

unread,
Aug 28, 2014, 2:52:02 PM8/28/14
to mi...@dartlang.org
Hi again Gilad (and others),

Your solution worked on 1 of my 2 use cases. I can now serialization/deserialization lists of objects on the top level, but when a similar list is part of an object, then I run into problems. I have been trying to find a solution during the whole day but now I'm stuck and maybe I'm simply trying to do something that is impossible.

As I mentioned in my original post I am writing a Json serialization/deserialization library. The serialization part works good and is quite simple in comparison to the deserialization stage. Basically what I do is that I use the type information from the objects to do correct deserialization, I don't have any annotation or other added parts, you just have to inherit one model class for your object to become serializable (and have either an empty constructor or and empty .model() constructor). During the deserialization stage you have to send in either the object type or an instance of the object and I then look at that instance for members that have both public getters and setters, build a list of members and type information and then work off of that during the deserialization process.

This leads me to the use case of instantiating a List<int> (for example) using only a TypeMirror, and I wonder is that possible somehow? See this code example code:
  InstanceMirror im = reflect(new ListContainer());
  ClassMirror mirror = im.type;
  TypeMirror tm = mirror.instanceMembers[#myList].returnType;

  print(tm.reflectedType);
  print(tm.typeArguments);

  // How can I create an instance of type [tm.reflectedType] here?
  //.....

  class ListContainer {
    List<int> myList;
  }

Prints:
List<int>
[ClassMirror on 'int']

If it's not possible would it not be a good feature to have? It feels like [tm.reflectedType] has all the information that would be needed?

My current idea for a workaround is to require users to instantiate any typed list in their model/class declaration (List<int> myList; = new List<int>()), but that is not an optimal solution because if they don't, the value is null and I can only create a list of type List<dynamic>. Any tips or ideas would be appreciated!

Sincerely, Robert


On Wednesday, August 27, 2014 9:32:15 PM UTC+2, Gilad Bracha wrote:

Gilad Bracha

unread,
Aug 28, 2014, 3:33:42 PM8/28/14
to General Dart Discussion
Robert,

 
A TypeMirror describes a type. That type may not be instantiable. It might be a type variable or an abstract class or a typedef describing a function type. So the return type of a member won't necessarily give you anything that you can instantiate. If the TypeMirror represents a class, than you can probably test to see if it is ClassMirror, and if so you can check if it isAbstract and if not you can instantiate it with newInstance(). Or the class may be abstract but has a factory constructor, so you can still instantiate by feeding newInstance() the name of said factory constructor. That would be the case with List.

Robert Åkerblom-Andersson

unread,
Aug 28, 2014, 5:38:20 PM8/28/14
to mi...@dartlang.org
Hi Gilad, 

Yes, I understand not all types can be instantiated, but that was not the issue here, maybe I was not clear enough. The question is really if a List<int> or List<Podo> be instantiated without having an existing InstanceMirror prepared in forehand? (or using the "new" keyword, since we can't do that programmaticallyFrom how I understand it, it is currently impossible to do any kind of deserialization into a generic typed list, is that correct? (except if the model classes explicitly called "new" as part of their declaration since otherwise their value is null and can't be used)

This works, since I get an instance of List<int> that I can use:
  List<int> l = VaneModel.decode('[7, 8, 9]', new List<int>());

This does not work since I can't create a List<int> list (I can have a ClassMirror of List<int> prepared and use as a factory, yes. But I can't do that for a class Podo that I don't have access to in before hand. Theoretically I could implement a transformer that creates such factories but that would not be the most convenient solution...)
  List<int> l = VaneModel.decode('{"l": [7, 8, 9]}', new Podo());
 
 
class Podo extends VaneModel {
   
List<int> l;
 
}

Am I right that it is simply impossible to instantiate a "generic typed list" (eg. List<int> and not List<dynamic>) without the "new" keyword? If so, would it not be reasonable to make that possible or do I miss a "can of worms" lurking somewhere in this story? (pun intended)

Don't we want to be able to deserialize a generic list from JSON/Protobuff/[any format] into a List<Podo> list? Or is the official stance on this simply that we only support dynamic lists if we want to recreate an object via deserialization?

(Note: as I said I can somewhat work around this if I require users to write all their model's containing lists like this. But it feels somewhat like a hack and error prone...)
  class Podo extends VaneModel {
   
List<int> = new List<int>();
 
}


Sincerely, Robert 

Gilad Bracha

unread,
Aug 28, 2014, 7:56:50 PM8/28/14
to General Dart Discussion
Hi Robert,

 I do not understand what you are asking.  Please forgive me, I am but a simple soul. Let's forget about your serialization framework and focus on a concise statement of what you are trying to accomplish.  For example: 

"I have an instance of a type X and I need to reflectively create an instance of List<X>".

Alan Knight

unread,
Aug 28, 2014, 8:19:38 PM8/28/14
to General Dart Discussion
I think that what he wants is to create instances of arbitrary types, specifying their type variables. I can get a ClassMirror on List from the mirror system. And I can create a new instance of it, giving me a List<dynamic>.  But if I want to create a new List<Foo> I can't do it, because the only way to create a ClassMirror on List<Foo> is to already have an instance of List<Foo>

The serialization context is pretty relevant. If I have a file that says something like

   {  'type' : 'List',
      'generic' : 'Foo',
      'contents' :  ... some other stuff that de-serializes into Foo instances ... 
   } 

then to de-serialize this properly I need to create an instance of List<Foo>.

So, conceptually,
    var m = new ClassMirror(reflect(List), typeVariables: [reflect(Foo)]);
    m.newInstance();


Gilad Bracha

unread,
Aug 28, 2014, 8:29:56 PM8/28/14
to General Dart Discussion
Thanks Alan.

If that's the question, you've answered it. And of course, the serialization context isn't actually relevant, because the first paragraph is all that matters.

Now, would it be good to provide a way to manufacture a mirror on a parameterized type that doesn't exist in your program? Yes, I think so. 

Robert Åkerblom-Andersson

unread,
Aug 28, 2014, 10:23:33 PM8/28/14
to mi...@dartlang.org
Hi again Gilad. I think what I have described is very similar to Alans description, but my apologizes if I was not clear enough and thanks Alan for giving a more clear description of the exact same thing I tried to describe. I really appreciate both of yours quick replies on the subject, the code I provided is not part of my library but written specifically to isolate the issue (said library is open source but has not be released yet). To answer your question Gilad using your format:

"I have an instance of a type X and I need to reflectively create an instance of List<X>".
----->
"I have an instance of a type 'Foo' that has a member 'List<Bar> list' and I need to reflectively instantiate 'list' as a List<Bar> list (using List<dynamic> is not considered good enough)".

And to be more specific, I can reflectively create 'Foo', but at that point 'list' is Null, that in itself is not unexpected but it leads to the issue of reflectively instantiating 'List<Bar>' only using the information I have (that is a TypeMirror at best), and from my experience it is not possible, Alan seems to agree on this point and you seem to agree with Alan. So I think we can agree here that it is simply not possible but it would be good if we could do this. 

The reason the serialization context is relevant Gilad is because the feature we talk about is needed for a good (some would say even a working one) serialization library. Because of the fact that we can't recreate List<Bar>, you could argue that we pretty much have to throw out the whole concept of generic lists (meaning we can't use them) if we want to use serialization (if not using the sort of workaround I described, which I will do and recommend for now). I think the context of serialization motivates this issue, and for most developers I think it's good to have a real world context of why something is needed. I never said nor meant that this was only relevant for serialization, but serialization libraries are important and their usage of mirrors are a lot bigger than many other types of libraries that might use mirrors. 

I've now created an issue for this here:

I hope you don't mind I used part of your post Alan as a quote. Please feel free to add better descriptions in the issue if either one of you can, although for me it seems quite clear as it is. 

Sincerely, Robert 

Alan Knight

unread,
Aug 29, 2014, 1:00:34 PM8/29/14
to General Dart Discussion
Yes, in the 'serialization' package I just fell back to creating dynamic list types as well.

There are lots of other interesting cases in serialization as well, e.g. ObservableList.


Reply all
Reply to author
Forward
0 new messages