Ayende @ Rahien

Hi!
My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 5,971 | Comments: 44,508

filter by tags archive

Dynamic resolution rules joy


In the following code, what do you believe the output should be?

class Program
{
    static void Main(string[] args)
    {
        dynamic stupid = new Stupid{Age = 3};

        Console.WriteLine(stupid.Age);
    }
}

public class Stupid : DynamicObject
{
    public int Age { get; set; }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = 1;
        return true;
    }
}

Argh!

The default is to use the actual type members, and then fall back to the dynamic behavior. Whereas I would expect it to first check the dynamic behavior and then fall back to the actual members if it can’t find dynamic stuff.

Quite annoying.


Comments

tobi

Never worked with the DLR but I believe that DynamicObject is not the lowest level of abstraction. Maybe you can overrride this stupid behavior by overriding DynamicMetaObject GetMetaObject and returning a more well-behaved object.

sw
sw

Why should it go the slower route of dynamic/reflection when there is a simple fast property on the object?

tobi

Because the whole point of dynamic is to get in control of the members that your object demonstrates to have.

Mix
Mix

So what did you actually expect it to show? 3 is printed as I would've expected it.

Matt

Seems perfectly reasonable to me. I'd consider it stupid if it had printed 1.

Mix
Mix

MSDN article on TryGetMember is completely misleading - had I read it before posting my comment I would've expected 1 indeed.

Bogdan Marian

@Ayende I find this behaviour normal. The notion of TryXXX (found when parsing numbers or getting stuff out of dictionaries) is related to uncertainty. Thus, if the CLR sees a getter, it should call that getter and not call the TryGetMember method.

Khalid Abuhakmeh

I find that quite annoying as well, that if I want to use a dynamic object's property I have to cast it before passing it into any method. In my eyes that defeats the purpose of using a dynamic to begin with since it has that additional development overhead/noise.

Maybe they can fix it in the next .Net where it can inspect the parameter type of the method and just try to do a best guess auto-cast.

Frederico Pinto

This comes from the "Remarks" section of the MSDN article on TryGetMember:

"You can also add your own members to classes derived from the DynamicObject class. If your class defines properties and also overrides the TrySetMember method, the dynamic language runtime (DLR) first uses the language binder to look for a static definition of a property in the class. If there is no such property, the DLR calls the TrySetMember method."

3 it is... or am I missing something?

Bogdan Marian

Reading the MSDN link for DynamicObject.TryGetMember (http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.trygetmember.aspx), I found this inside the remarks block: "You can also add your own members to classes derived from the DynamicObject class. If your class defines properties and also overrides the TrySetMember method, the dynamic language runtime (DLR) first uses the language binder to look for a static definition of a property in the class. If there is no such property, the DLR calls the TrySetMember method.". So, the behaviour encountered inside the code above seems to be the correct one and is similar to the one described by the official documentation.

flukus

I've never used dynamic object at all, nor read much about it.

Intuitively I would expect the getter t8o take precedence.

zdeslav

seems completely logical to me. Imagine:

public class Stupid : DynamicObject { public int Age { get; set; } public int OtherProperty { get; set; } public int AndAnother { get; set; } ...

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
    // if this would have precedence over the specified properties
    // here you would have to filter all of those properties
    // that would render explicit properties quite useless
    // if(binder.Name == "Age" ...
}

}

Lee Atkinson

I think the confusion lies in that people assume that the dynamic keyword and the DynamicObject type are somewhat related - they aren't (they just happen to be used together lots of times).

It makes sense to me that you get the 'statically-defined' member rather than the result of TryGetMember. It most closely resembles 'normal' inheritance - start with the object and work up the inheritance tree until you find member you are looking for.

(The dynamic keyword just kets you late-bind to the object and thus make it 'more readable' as a simple member.)

Bill Barry

@zdeslav:

public override bool TryGetMember(GetMemberBinder binder, out object result) { if(binder.StaticInvoke!=null) return binder.StaticInvoke(out result); }

Still I think the current design is better, but it wouldn't have to be as bad as you are assuming.

Frank Quednau

Just proves that however logical an API appears to be, there is always someone who doesn't like it the way it is. I like that as a sort of comforting start of weekend thought.

Jamie

It seems like what you want is to use the dynamic behavior to essentially override a default value for some property: the only time you want to get the actual property value would be if nothing had been assigned. So the "setter" seems quite pointless if you expect the dynamic behavior to take precedence.

So why not just create a default dynamic value instead of a property? E.g. in your constructor just call TrySetMember to add some default for a dynamic value, instead of hardcoding a property that you want to allow to be overridden.

I think this makes sense, but if you don't like it, then just implement your own IDynamicMetaObjectProvider.

Michael L Perry

This is standard behavior for any dynamic language. Smalltalk's doesNotUnderstand is only called if the object is sent a message that it does not understand. Ruby's method_missing is only called when a method is truly missing. I think it would be more annoying if .NET were to choose the opposite default.

JC
JC

Maybe the method should have been named TryGetMissingMember instead hence avoiding any confusion about it's functionality.

Jon
Jon

Agree with Michael. This is the behavior I would expect.

Nick Parker

Seems fitting that it would infer the explicit assignment first, then fall through to an implicit when unavailable.

Omri

I believe the confusion comes from prior experience with Dynamic Proxies. one should understand that dynamic proxies and dynamic object are different. the behavior you are expecting is very reasonable in a dynamic proxy scenario. it is less reasonable in a dynamic object.

Darius Damalakas

Standard behaviour, if I remember correctly, Python does exactly the same, and that makes perfect sense

Chris Marisic

I think JC summed up this post, that the method is named very poorly.

That if the method was named TryGetMissingMember that the intent would be conveyed properly.

Stanislav Ageev

Darius is right, getattr in Python got exactly the same behavior which makes sense. I was missing this behavior a lot

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

  1. Paying the rent online - about one day from now

There are posts all the way to Aug 03, 2015

RECENT SERIES

  1. Production postmortem (5):
    29 Jul 2015 - The evil licensing code
  2. Career planning (6):
    24 Jul 2015 - The immortal choices aren't
  3. API Design (7):
    20 Jul 2015 - We’ll let the users sort it out
  4. What is new in RavenDB 3.5 (3):
    15 Jul 2015 - Exploring data in the dark
  5. The RavenDB Comic Strip (3):
    28 May 2015 - Part III – High availability & sleeping soundly
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats