Function as Object

Topics: C# Language Design
Sep 2, 2014 at 12:14 PM
What we have:
class A 
{
    public Int32 Prop { get; set; }
    public virtual void Foo(){...}
}


var a = new A();
a.Foo( );
Action aAction = a.Foo;
What I suppose to have:
Action<A> sStatic = a.Foo.StaticDelegate;
Action<A> sStatic2 = A.Foo;

Action<Int32> aPropSetter = a.Prop&.Setter;
Func<Int32> aPropGetter = a.Prop&.Getter;

Action<A, Int32> aStaticPropSetter = a.Prop&.StaticSetter;
Func<A, Int32> aStaticPropGetter = a.Prop&.StaticGetter;

aStaticPropSetter = A.Prop&.Setter;
aStaticPropGetter = A.Prop&.Getter;

MethodInfo mi1 = a.Foo.GetMethodInfo( );
MethodInfo mi2 = A.Foo.GetMethodInfo( );

class B : A
{
     public override void Foo(){...}
}

A a = new B( );

...

if( a.Foo.StaticDelegate == A.Foo )
{
    ...
}
else if ( a.Foo.StaticDelegate == B.Foo )
{
   ...
}
Sep 2, 2014 at 11:27 PM
I don't understand what you're trying to propose here.

Would you care to elaborate a bit more on that?

Why are delegates not working for you?
Sep 3, 2014 at 2:25 PM
Edited Sep 3, 2014 at 2:29 PM
Getting the property accessor into a delegate is indeed pretty hard right now compared to plain methods. However I prefer the following syntax:
Action<Int32> aPropSetter = new Action<Int32>(a.set_Prop);
The compiler already knows what get_Prop and set_Prop is, just refuses you to use it. It would be a smaller change to enable this when a method group is expected compared to introducing new syntax.

The GetMethodInfo proposal seems semantically equivalent to the infamous infoof operator. Don't hold your breath.
Sep 3, 2014 at 9:16 PM
BachratyGergely wrote:
Getting the property accessor into a delegate is indeed pretty hard right now compared to plain methods. However I prefer the following syntax:
Action<Int32> aPropSetter = new Action<Int32>(a.set_Prop);
The compiler already knows what get_Prop and set_Prop is, just refuses you to use it. It would be a smaller change to enable this when a method group is expected compared to introducing new syntax.

The GetMethodInfo proposal seems semantically equivalent to the infamous infoof operator. Don't hold your breath.
Got it!

On way would be for the compiler to match property P of type T with Func<T> if it has a getter and Action<T> if it has a setter. And, now that we are at it, extend that to indexers too.

The problem with this is accessibility scoping. You can get a delegate to a private/internal/protected property and throw it out in the public world. Should that be encouraged and made easier to do?
Sep 4, 2014 at 8:35 AM
Since we're stuck with strongly typed delegates I think it would be more consistent to explicitly specify the delegate type. Especially for indexers where the accessors are overloaded (e.g. this[int index] and this[string name]).

I'm not sure about the new Action<Int32>(a.Prop) syntax because with methods you can write
Action<Int32> adelegate = obj.SomeMethod;
obj.EventHandler += obj.SomeMethod;
stuff.Where(obj.SomePredicate).Select(obj.SomeProjection);
without specifying the delegate type on the right hand side (still explicit on the left side) which begs for
Action<Int32> aPropSetter = obj.SomeProp;
obj.EventHandler += obj.SomeProp;
But this is ambiguous: is this the property accessor delegate or the value of the property? If the accessor is explicitly specified there is no ambiguity, and it works exactly like methods. Though get_Stuff doesn't feel very C#ish.
Sep 4, 2014 at 11:44 AM
For Properties I Propose get reference operator &

so
Action<Int32> aPropSetter = obj.SomeProp;
obj.EventHandler += obj.SomeProp;
become
Action<Int32> aPropSetter = obj.SomeProp&; //Get Property Delegate
obj.EventHandler += obj.SomeProp&; //Get Property Delegate

obj.EventHandler += obj.SomeProp; //Use Property return value
Sep 4, 2014 at 11:40 PM
PauloMorgado wrote:
The problem with this is accessibility scoping. You can get a delegate to a private/internal/protected property and throw it out in the public world. Should that be encouraged and made easier to do?
Why not? Many, if not most, classes contain references to things which must not be exposed to the outside world, but pass those references to methods which are trusted not to persist nor expose them, even though the Framework contains no mechanism to restrict the ways in which a method can expose or persist a reference to which it receives. If method foo(Func<int>) can be trusted not to use a delegate it receives in a fashion contrary to its caller's expectations, then passing a property getter to foo wouldn't be "throwing it out to the outside world".
Sep 5, 2014 at 6:40 AM
Not sure if that is a good idea. For private methods you have to fall back to reflection, that makes it pretty explicit that you're in the danger zone.
Sep 5, 2014 at 9:49 AM
BachratyGergely wrote:
Not sure if that is a good idea. For private methods you have to fall back to reflection, that makes it pretty explicit that you're in the danger zone.
There's no need for a class to use reflection to create delegates to its own private methods.
Sep 5, 2014 at 10:33 AM
Edited Sep 5, 2014 at 10:34 AM
Are we talking about the same thing?
class SomeClass
{
    public SomeProp { get; private set; }
}
public void SomeOtherMethod(SomeClass obj)
{
    var aPropGetter = new Func<Int32>(obj.SomeProp&);     // OK
    var aPropSetter = new Action<Int32>(obj.SomeProp&);   // Compile error
}
SomeProp is visible in scope however the setter is not, so the second line should be disallowed. But if you want to expose a private member from inside by all means do so. That's an implementation detail and practically unverifiable anyway.
Sep 5, 2014 at 10:53 AM
Edited Sep 5, 2014 at 10:54 AM
You right.
class SomeClass
{
    public SomeProp { get; private set; }

    public void SomeOtherMethod()
    {
        var aPropGetter = new Func<Int32>(SomeProp&);     // OK
        var aPropSetter = new Action<Int32>(SomeProp&);   // OK
    }
}
Sep 5, 2014 at 1:31 PM
JesInc28 wrote:
You right.
class SomeClass
{
    public SomeProp { get; private set; }

    public void SomeOtherMethod()
    {
        var aPropGetter = new Func<Int32>(SomeProp&);     // OK
        var aPropSetter = new Action<Int32>(SomeProp&);   // OK
    }
}
Or you could do this, now:
Func<int> getter = () => SomeProp;
Action<int> setter = value => SomeProp = value;
Sep 5, 2014 at 4:55 PM
The problem with the lambda syntax is it creates an anonymous function that directly forwards the call to the setter, it might also create a closure over the instance variable. That's twice the GC overhead. It might be an option to make the compiler optimize this for the closure-free case, but would not be possible for the following:
var it1 = obj.SomeProp.SomeOtherProp&getter
var it2 = () => obj.SomeProp.SomeOtherProp;
var tmp = obj.SomeProp;
var it3 = () => tmp.SomeOtherProp;
Which is also different semantically: the first would get the accessor on construction, the second on every invocation. The value of SomeProp then might be different. it3 would be the equivalent form to it1.