Wrong type reported by reflection?

53 views
Skip to first unread message

Paul Jolly

unread,
Jul 23, 2014, 4:41:05 AM7/23/14
to mi...@dartlang.org

Considering the following code:

import 'dart:mirrors';

typedef T1 getterField<T1, T2>(T2);

class A {
  String _name;
  String get name => _name;
  set name(String n) {
    print("setting name to " + n);
    _name = n;
  }
  static final getterField<String, A> nameField = ((A a) {
    return a.name;
  });
}

void main() {
  A a = new A();
  a.name = "Paul";

  InstanceMirror m = reflect(A.nameField);
  print(m.toString());

  // Warning given for the following line (as expected):
  // A value of type 'String' cannot be assigned to a variable
  // of type 'int'
  // num i = A.nameField(a);
}

The output is:

setting name to Paul
ClosureMirror on 'Closure: (A) => dynamic'

However, as the comment in the code illustrates, the assignment to i (that is also commented out) is statically shown as an error.

Am I missing something here? Why is the output not:

setting name to Paul
ClosureMirror on 'Closure: (A) => String'

Thanks

Günter Zöchbauer

unread,
Jul 23, 2014, 6:33:13 AM7/23/14
to mi...@dartlang.org
You are reflecting on the value the field holds.
There could be more than one typedef a closure signature corresponds to.  
There is no 1:1 relation between closure and typedef like with instance and class as far as I know.

If you have another typedef with the same signature like

typedef T1 someTypedef<T1, T2>(T2);

someTypedef nf = A.nameField;

is accepted by the analyzer and works at runtime.

I thought I remember reading a feature request about implementing just that (get the typedef from a closure) which was updated to 'started' recently, but wasn't able to find it.

Only reflection on the field declaration can provide the type information

  var cm = reflectClass(A);
 
List types = (cm.declarations[#nameField] as VariableMirror).type.typeArguments;
 
print(types);

Günter Zöchbauer

unread,
Jul 23, 2014, 6:35:12 AM7/23/14
to mi...@dartlang.org
> I thought I remember reading a feature request about implementing just that (get the typedef from a 
>  closure) which was updated to 'started' recently, but wasn't able to find it.

and wondered here as well how this should be possible,
but this doesn't mean much because my knowledge about Dart language internas is limited.

Paul Jolly

unread,
Jul 23, 2014, 10:43:28 AM7/23/14
to mi...@dartlang.org
You are reflecting on the value the field holds.
There could be more than one typedef a closure signature corresponds to.  
There is no 1:1 relation between closure and typedef like with instance and class as far as I know.

Agreed. I'm not expecting 'getterField' to be returned by m.toString(), rather the type it aliases. 

In this case the type of A.nameField is known statically because the parameterized typedef is made concrete: it is getterField<A, String>, or in other words:

String getterField(A) 

The reflect however shows the type as: (A) => dynamic. 

The editor statically knows the return type is String, because if you uncomment the assignment to i, you will get a warning in the editor.

So in a sense, all I'm doing is pointing out that at runtime the reflected type of the value A.nameField does not correspond to the statically known type. This is what surprised me.

Günter Zöchbauer

unread,
Jul 23, 2014, 11:07:27 AM7/23/14
to mi...@dartlang.org
What I mean is that you are reflecting on the value returned by A.nameField,
that you are actually reflecting the closure and not the getter and that a closure doesn't have specific type information assigned to it (like an instance of a class has).
I'm not sure about that but I have never seen any info about a closure holding type information (beside the types of the arguments). 
Would be glad if someone proves me wrong though.

Alan Knight

unread,
Jul 23, 2014, 12:34:06 PM7/23/14
to General Dart Discussion
I think that the code as written is equivalent to 

  static final getterField<String, A> nameField = dynamic ((A a) {
    return a.name;
  });
except that isn't valid syntax. That is, what you've said is that this variable has a static type, and you've assigned to it a variable which is compatible with that static type, but it's compatible because the return type is "dynamic", not because it's String. 

If you wrote it as 

static final getterField<String, A> nameField = _foo;
static String _foo(A a) {
  return a.name;
}

then you'd get the result you expect. Because you can't name or specify a return type for an inline function, it's hard to get the result you want without going through the hoops of defining an additional method.




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

Paul Jolly

unread,
Jul 23, 2014, 12:50:07 PM7/23/14
to mi...@dartlang.org
Alan - that would definitely explain it. Thanks
Reply all
Reply to author
Forward
0 new messages