example of wanting to override runtimeType?

187 views
Skip to first unread message

Seth Ladd

unread,
Feb 18, 2013, 6:12:38 PM2/18/13
to General Dart Discussion
Hi Dartisans,

I see that it's possible to override runtimeType, like this:

class Foo {
  final runtimeType;
  Foo() : runtimeType = 'whateves';
}

Are there any good examples of benefiting from this behavior? Why is runtimeType not "locked down" in some way? When would a class want to "lie" about this?

Thanks!
Seth

Ladislav Thon

unread,
Feb 19, 2013, 12:01:32 AM2/19/13
to General Dart Discussion

I don't see a good case either, but the "strongly dynamic" folks would probably suggest situations like creating a remote proxy. If you have a transparent remote proxy for object of class C, then it might make sense for the proxy to tell that its type is C.

Myself:
- I don't think it is a good idea just in principle.
- I can't create a Type object. I would have to instantiate C and get its type from it.
- But I would also like the proxy to implement C's interface -- which, for now, immediately leads to compile-time code generation. (Me not like AOT code generation. Me sad.)
- And in the end, I can always reveal the truth via mirrors.

On the other hand, overriding runtimeType is unlikely to break anything and it will be relatively rare, I assume, so why forbidding it? It's a part of Dart's dynamic nature (same like you can't prevent subclassing).

LT

Daniel Rodríguez

unread,
Feb 19, 2013, 12:28:50 AM2/19/13
to mi...@dartlang.org
The only case that comes to mind is when you are interacting with a piece of code that you don't control and uses type information in a map, for example, code that maps Type objects to object pools for that type. Maybe you are testing using mocked versions of the classes but you expect that map to behave the same, so the mocked versions would have to lie about their type.

Would love to see some official answer from the language designers.

Alex Tatumizer

unread,
Feb 19, 2013, 12:41:13 AM2/19/13
to mi...@dartlang.org
Feature is very good for various kinds of abuse. "runtimeType" is a property of every object. I tried to assign it all types of values (not strings) - it worked. It's not necessarily final (non-final works, too).
So, you have a loophole that allows you to associate a piece of data with every object with no hassle.   
I can see the whole continuum of uses, but all of them are hacks.

.


 

Ladislav Thon

unread,
Feb 19, 2013, 1:01:38 AM2/19/13
to General Dart Discussion


> Feature is very good for various kinds of abuse. "runtimeType" is a property of every object. I tried to assign it all types of values (not strings) - it worked. It's not necessarily final (non-final works, too).
> So, you have a loophole that allows you to associate a piece of data with every object with no hassle.

There's an official way of doing this, the Expando class. A little bit more hassle, as you put it, but it lets you do that many times in a controlled manner.

LT

Lasse R.H. Nielsen

unread,
Feb 19, 2013, 4:25:59 AM2/19/13
to mi...@dartlang.org
On Tue, Feb 19, 2013 at 12:12 AM, Seth Ladd <seth...@google.com> wrote:
Hi Dartisans,

I see that it's possible to override runtimeType, like this:

class Foo {
  final runtimeType;
  Foo() : runtimeType = 'whateves';
}

Are there any good examples of benefiting from this behavior?

Only hypothetical so far.

I expect to make all internal classes hide themselves this way, so, e.g., the VM's StringBase class should have
   Type get runtimeType => String;

Why is runtimeType not "locked down" in some way?

You can't lock down members in Dart (you can't prevent overriding or implementing an "isNull" method either :).

It is restricted in that it should return a Type in checked mode (unless you go dynamic like here), and you can't create a real Type object yourself. You can create something implementing Type, but it won't work with the mirror system.
 
When would a class want to "lie" about this?

When it's an internal class that you shouldn't worry about. Look at me, I'm  a "Foo" (and not a "_FooWithCherryOnTop")!
Or if you are proxying something. But it's too primitive for that - you should rather have an "bool operator is(Type t)" method to override "is" checks, if that is what you want.
 
I personally don't like that runtimeType is member. I would have preferred a function somewhere else, so you could do: 
  Type objectType = Object.typeOf(object);
but the designers of the feature *wanted* it to be overridable.

We still leak internal classes in stack traces, and overriding runtimeType won't prevent that. 

/L
--
Lasse R.H. Nielsen - l...@google.com  
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 København K - Denmark - CVR nr. 28 86 69 84
Message has been deleted

Alex Tatumizer

unread,
Feb 19, 2013, 11:42:02 AM2/19/13
to mi...@dartlang.org
Let's check how far our lies can take us:
class Foo {
  var runtimeType;
  Foo(): runtimeType="Bar";
}
void main() {
  var foo=new Foo();
  print(foo.runtimeType);
  print(foo);
}
prints:
Bar
Instance of 'Foo'


BUSTED!!!
So what was the point? Our lies were exposed in a fraction of millisecond!

The only mention of runtimeType in language spec is this:
"The runtime type of every object is represented as an instance of class
Type which can be obtained by calling the getter  runtimeType declared in class Object"
Apparently, dart runtime itself doesn't make any meaningful use of this field.




Gilad Bracha

unread,
Feb 19, 2013, 12:58:24 PM2/19/13
to General Dart Discussion
The reason you need to be able to override runtimeType is so that you can abstract from implementation details.  If you define a proxy for another object, you'd like to make it behave as close to the proxied object as possible.  You make sure it forwards all methods to its target, you make sure its runtimeType is a proxy as well, you make sure it implements the desired interface and you make sure you do not expose the Proxy type itself, so you can't use type tests or casts to discover it is a proxy.    Hopefully we have not missed anything. Of course, if you have access to reflection, you can still bypass all this - but you really have to go out of your way.






--
Consider asking HOWTO questions at Stack Overflow: http://stackoverflow.com/tags/dart
 
 



--
Cheers, Gilad

Alex Tatumizer

unread,
Feb 19, 2013, 1:17:11 PM2/19/13
to mi...@dartlang.org
> ... so you can't use type tests or casts to discover it is a proxy.
But now you CAN use type tests to discover it's a proxy, e.g:

class Bar {}
class Foo {
  final runtimeType;
  Foo(): runtimeType=new Bar().runtimeType;

}
void main() {
  var foo=new Foo();
  print(foo is Bar); 
  print(foo is Foo); // foo is still Foo!
}

prints
false
true

And I didn't really use any mirrors or anything. What gives?


Gilad Bracha

unread,
Feb 19, 2013, 1:19:55 PM2/19/13
to General Dart Discussion
As my message says: hide the proxy type.


--
Consider asking HOWTO questions at Stack Overflow: http://stackoverflow.com/tags/dart
 
 



--
Cheers, Gilad

Lanesa Stubbs

unread,
Feb 19, 2013, 1:21:43 PM2/19/13
to mi...@dartlang.org
Ok how do i remove myself from these emails... I can't seem to find out how i got added?

Lasse R.H. Nielsen

unread,
Feb 19, 2013, 1:24:07 PM2/19/13
to mi...@dartlang.org
You're not trying hard enough to be a secret Bar imposter.

First of all, hide the Foo class from anyone who knows about Bar, so they can't do "x is Foo". 
Then *be* a Bar.

class Bar { 
  int foo() => 42;
}

class _BarProxy implements Bar {
  Type get runtimeType => Bar;
  int foo() {
     log("YOU CALLED FOO");
     return 42;
  }
}

Then, given an instance of _BarProxy, but without knowing about that class, can you see that it is not really an instance of Bar?

/L
-- 

Alex Tatumizer

unread,
Feb 19, 2013, 1:30:39 PM2/19/13
to mi...@dartlang.org
@Lasse: Thanks, finally I see the point. There a whole pattern here. Sorry I was not able to figure it out myself.


Justin Fagnani

unread,
Feb 19, 2013, 1:56:52 PM2/19/13
to General Dart Discussion
On Tue, Feb 19, 2013 at 10:24 AM, Lasse R.H. Nielsen <l...@google.com> wrote:


On Tue, Feb 19, 2013 at 7:17 PM, Alex Tatumizer <tatu...@gmail.com> wrote:
> ... so you can't use type tests or casts to discover it is a proxy.
But now you CAN use type tests to discover it's a proxy, e.g:

class Bar {}
class Foo {
  final runtimeType;
  Foo(): runtimeType=new Bar().runtimeType;

}
void main() {
  var foo=new Foo();
  print(foo is Bar); 
  print(foo is Foo); // foo is still Foo!
}

prints
false
true

And I didn't really use any mirrors or anything. What gives?


You're not trying hard enough to be a secret Bar imposter.

First of all, hide the Foo class from anyone who knows about Bar, so they can't do "x is Foo". 
Then *be* a Bar.

class Bar { 
  int foo() => 42;
}

class _BarProxy implements Bar {

This is the unfortunate part right here. If you didn't need to have "implements Bar" then we're close to allowing real proxies that work in checked mode. Something like:

class Proxy {
  final _instance;
  final Type runtimeType;

  Proxy(this._instance, this.runtimeType);

  noSuchMethod(InvocationMirror im) => im.invokeOn(_instance);
  String toString() => _instance.toString();
  ...
}

main() {
  Foo foo = new Foo();
  var proxy = new Proxy(foo, Foo);
  foo = proxy; // please no checked-mode error!
  print(foo is Foo); // please print 'true'!
}

Another option is to allow overriding the 'is' operator. Here's the proxy bug: http://dartbug.com/5641

-Justin


  Type get runtimeType => Bar;
  int foo() {
     log("YOU CALLED FOO");
     return 42;
  }
}

Then, given an instance of _BarProxy, but without knowing about that class, can you see that it is not really an instance of Bar?

/L
-- 
Lasse R.H. Nielsen - l...@google.com  
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 København K - Denmark - CVR nr. 28 86 69 84

--

Lasse R.H. Nielsen

unread,
Feb 19, 2013, 2:42:34 PM2/19/13
to mi...@dartlang.org
On Tue, Feb 19, 2013 at 7:21 PM, Lanesa Stubbs <msla...@gmail.com> wrote:
Ok how do i remove myself from these emails... I can't seem to find out how i got added?

Try going to https://groups.google.com/a/dartlang.org/forum/?fromgroups#!forum/misc and see if you can change the membership options.

Cheers
/L



--

Alex Tatumizer

unread,
Feb 19, 2013, 3:24:28 PM2/19/13
to mi...@dartlang.org
Now that I finally understand what you people are talking about, I feel even more confused. I can't find a good use case for this contraption.

Now let's compare two situations:
1) you never pretended anything, just said
class _BarProxy implements Bar  -  so you ARE the bar already

2) you "pretended" you are even "more" Bar-ish, by overriding runtimeType
class _BarProxy implements Bar {
  var runtimeType = "Bar";
  ..
}

The point is: your "runtimeType" comes into play ONLY when somebody receives object of (generic) type Bar, and explicitly retrieves runtimeType:
Type myBarType=myBar.runtimeType

So then you have to do something with myBarType, but what exactly? Why did you need it in the first place?
in dart, runtimeType is roughly equivalent to java's getClass(), and there are situations where you need it in java, but all such situations I can remember at the moment are related to reflection (so you retrieve getClass not for fun, but to use reflection in some or other way).

So, could anyone describe the situation when you REALLY need to retrieve runtime type, without the intent of using reflection?

Let's resort to allegory. I can pay 50 bucks and get a licence plate saying "NAPOLEON". How will my life, or somebody else's life, will be affected by this? No one cares, you can see all kinds of dumb things written on license plates. So what?

I'm certainly missing something, but I can't figure out what exactly.



Ladislav Thon

unread,
Feb 19, 2013, 3:30:55 PM2/19/13
to mi...@dartlang.org
So then you have to do something with myBarType, but what exactly? Why did you need it in the first place?
in dart, runtimeType is roughly equivalent to java's getClass(), and there are situations where you need it in java, but all such situations I can remember at the moment are related to reflection (so you retrieve getClass not for fun, but to use reflection in some or other way).

So, could anyone describe the situation when you REALLY need to retrieve runtime type, without the intent of using reflection?

I can imagine that it can be used as a key for some cache. But honestly, that's all I've got.

LT

Colin Putney

unread,
Feb 19, 2013, 3:36:31 PM2/19/13
to General Dart Discussion


On Tue, Feb 19, 2013 at 12:24 PM, Alex Tatumizer <tatu...@gmail.com> wrote:
Now that I finally understand what you people are talking about, I feel even more confused. I can't find a good use case for this contraption.

It's useful if you want to implement a generic proxy, one that can wrap any object. Since you don't know in advance what you're wrapping, you can't use "implements" to give it the right type. (This won't work right in checked mode, but there's an open bug for that.) 

In that case, you can copy the runtime type from the object you're wrapping, without knowing in advance what it is. 

Colin

Alex Tatumizer

unread,
Feb 19, 2013, 3:54:20 PM2/19/13
to mi...@dartlang.org
> (This won't work right in checked mode, but there's an open bug for that.)

Plot thickens. So after the bug is fixed, setting runtimeType will affect "is"? Then this thread was opened prematurely - it depends on Future<Bug>.
Also, in this case probably there's no question about the runtimeType of runtimeType field: it should be Type, not a string or arbitrary object.

Ross Smith

unread,
Feb 19, 2013, 3:56:25 PM2/19/13
to mi...@dartlang.org
Example:  You are writing an IDE in Dart (woot!).  You want to broadcast the current 'selection' from your explorer to all of your open editors.  You want your editors to interact with a proxy to the actual 'selection' object, so that you can intercept all interaction with the wrapped object for undo and redo.  Those editors should think it is the real object's real type (so they can be Editor<T>), and they shouldn't need to bring in mirrors and deal with Futures to interact with said object.

Alex Tatumizer

unread,
Feb 19, 2013, 4:08:34 PM2/19/13
to mi...@dartlang.org
@Ross: sorry, I don't understand your example. In java, there's no overridable runtimeType, and people write proxies, and IDEs, and everything, with no problem whatsoever. Just implement correct interface (like in Lasse's example) - and you are good.
When (and if) the *bug* is fixed, maybe it will be easier to write proxies, but for now, you still have to explicitly "implement" interface.
 


Ross Smith

unread,
Feb 19, 2013, 4:21:35 PM2/19/13
to mi...@dartlang.org
> @Ross: sorry, I don't understand your example. In java, there's no overridable runtimeType, and people write proxies, and IDEs, and everything, with no problem whatsoever

I wouldn't say 'with no problem whatsoever'.  There are ways to make things happen in Java and C# and some people go to great lengths to duck type in those languages.  If Dart can make it much easier that is a big win for Dart :)


> Just implement correct interface (like in Lasse's example) - and you are good.

In my example, you don't know ahead of time the type of the 'selection' object.  This is why your proxy needs to be generic, and why I starred that bug :)

Alex Tatumizer

unread,
Feb 19, 2013, 4:29:11 PM2/19/13
to mi...@dartlang.org
@Ross: now finally I understand! Thanks! Yes, I agree with this, current implementation doesn't fully utilize dart flexibility, it does everything except the last point: overridable "is" (as you mentioned, it might be related, or unrelated, to runtimeType field).
 


Message has been deleted

Alex Tatumizer

unread,
Feb 20, 2013, 8:38:36 AM2/20/13
to mi...@dartlang.org
@Ross: in your example
main() {
  Foo foo = new Foo();
  var proxy = new Proxy(foo, Foo);
  foo = proxy; // please no checked-mode error!
  print(foo is Foo); // please print 'true'!
}

why do you need a proxy? Why not use "foo" as it is? The only use case I can see is for instrumentation of Foo, e.g
class Proxy {
  ...
  noSuchMethod(InvocationMirror im) {
    ...print something on entry 
    im.invokeOn(_instance)
    ... print something on exit
  };
   ...
}
Otherwise, the instance itself is as good as a proxy, Am I missing something?


On Wed, Feb 20, 2013 at 1:43 AM, mezoni <andrew...@gmail.com> wrote:
All clear. Easy way to solve complex problem.
I wonder how do respond standalone VM, if I substitute types and pass this "proxied" object back to VM?
For example, int type.
Message has been deleted

Alex Tatumizer

unread,
Feb 20, 2013, 10:24:21 AM2/20/13
to mi...@dartlang.org
If you want Proxies as defined in Java, then runtimeType, as defined now, doesn't cut it anyway.
Proxy should be able to implement several interfaces
And you can't have array of Types in runtimeType, it will be confusing (current definition allows to read one topmost Type via runtimeType - completely different meaning)


Alex Tatumizer

unread,
Feb 20, 2013, 11:21:53 AM2/20/13
to mi...@dartlang.org
There's a repeating pattern of confusion in this and other threads caused by a failure to clearly define a problem under discussion.
@Seth, you may agree that two problems:
A) When would a class want to "lie" about runtimeType?
B) come up with a mechanism that allows object to dynamically declare "I implement interfaces T1,T2...Tn"
- are not exactly the same problem


Bob Nystrom

unread,
Feb 20, 2013, 12:24:14 PM2/20/13
to General Dart Discussion

On Tue, Feb 19, 2013 at 10:43 PM, mezoni <andrew...@gmail.com> wrote:
I wonder how do respond standalone VM, if I substitute types and pass this "proxied" object back to VM?
For example, int type.

The built-in types int, bool, double, and String cannot be subclassed and you cannot implement their implicit interface. (They're like "sealed" in C# or "final" in Java.)

So you shouldn't be able to get in a situation where you pass a proxied primitive object to the VM.

For other corelib types (Iterable, List, Map, etc.) I believe the core library should handle the type correctly and not assume it's of some known concrete implementation class. It should only rely on the interface the type exposes.

Cheers,

- bob
Reply all
Reply to author
Forward
Message has been deleted
Message has been deleted
0 new messages