Allow convenient object.Function() syntax for function parameters #1917
Replies: 40 comments
-
In other words you're asking for extension delegate types. Unlike extension methods, this doesn't really give a powerful new way to extend existing objects ala Linq. Instead it's a relatively minor bit of syntactic sugar which will only really be relevant locally to where the delegate is in scope. I could imagine that there would indeed be a very few cases where I would consider using it. But we have to consider every bit of syntactic sugar comes at a cost. People who've never seen this new syntax before will be confused by it. People will be trying to work out where this method comes from for example, or what If it is added, it will have to be supported till the end of time, and no more powerful features could be added if their syntax conflicts with this. As such I see this as too little gain, for too much downside, to be worth doing. |
Beta Was this translation helpful? Give feedback.
-
I would never want a delegate parameter to be made to look like an instance member. Instance members indicate that they are an intrinsic part of the type, including extension methods. Method parameters do not qualify. |
Beta Was this translation helpful? Give feedback.
-
I am not sure exactly what you mean here. But I want to use existing delegate types without defining new ones.
True.
Right. But this is true for any new feature.
This is not a problem Today because the IDE can very easily help you get to the definition of the method (the function parameter in this case). Thinking about the 'this' syntax, I think that the other syntax I suggested (the 'ext' syntax) is better. It allows the feature to work on any delegate type and does not require the generic argument syntax to be modified.
I can't image another feature that would use the exact same syntax. |
Beta Was this translation helpful? Give feedback.
-
@jnm2 ,
Extension methods are hardly an intrinsic part of the object. For example, are Select, SelectMany, and Where intrinsic parts of |
Beta Was this translation helpful? Give feedback.
-
@ymassad The point of extension methods is to be able to give a type you don't own new intrinsic capabilities like Method parameters are not at all good candidates to extend the set of members on types within the method body. |
Beta Was this translation helpful? Give feedback.
-
@jnm2 , Ok. Then maybe I used the wrong name of the feature. It should be something like: convenient object.Function() syntax for function parameters. |
Beta Was this translation helpful? Give feedback.
-
I'm objecting to the
|
Beta Was this translation helpful? Give feedback.
-
What if extension local functions (#850) were allowed? With that, you could write: public static void DoSomething(
Customer customer,
Func<Customer, string> getCustomerDescription,
Func<Order, string> getOrderDescription)
{
string GetCustomerDescription(this Customer c) => getCustomerDescription(c);
string GetOrderDescription(this Order o) => getOrderDescription(o);
var desc1 = customer.GetCustomerDescription();
Order order = ...
var desc2 = order.GetOrderDescription();
...
} It's quite a lot of extra syntax compared with this proposal, but it's also more widely useful and builds on existing C# syntax ( |
Beta Was this translation helpful? Give feedback.
-
@svick , In your example, you still need to name the local functions GetCustomerDescription and GetOrderDescription instead of simply GetDescription. Also, as you noted, it requires more work. I agree with you regarding the 'this' syntax. I have suggested another syntax at the end of the original post. |
Beta Was this translation helpful? Give feedback.
-
@jnm2 , you have a point. I think that my proposal makes the member.Method() syntax have a different meaning than what it used to mean. Extension methods have changed the meaning a little bit (consider that two invocations with the exact same type and member name in different files can mean different things based on the 'using' declarations used). This proposal moves this a bit further. IDEs can help very much by highlighting the function parameter invocation in a different way. |
Beta Was this translation helpful? Give feedback.
-
Not everyone uses an IDE. Particularly with .NET Core, there's a considerable rise in folks using sophisticated text editors. IDE assistance can make language features easier to use - but language features shouldn't be dependent on IDE assistance to be understandable. |
Beta Was this translation helpful? Give feedback.
-
@theunrepentantgeek , what you say can be said about almost any C# feature. For example, if you see this:
What is With an IDE, things are better. Without an IDE, you can get to what you need to know but it requires more knowledge of the code you are reading and the language itself. |
Beta Was this translation helpful? Give feedback.
-
Maybe a property name, but no way would I use pascal casing for variables, fields or parameters. |
Beta Was this translation helpful? Give feedback.
-
If the codebase adheres to the norms of the wider C# ecosystem, it should be either a type name or a property. It's unlikely to be a variable, field or parameter. That said, I suspect you're missing my point @ymassad. Language features shouldn't require IDE support to be understood; they need to stand on their own. |
Beta Was this translation helpful? Give feedback.
-
@jnm2 , You can never know. Other developers work on the same project. What about this:
In summary, when you work with a language, you need to know the features. |
Beta Was this translation helpful? Give feedback.
-
It's an interesting proposal but I can't see it being of much benefit to anyone except those that follow this specific design pattern, which I can't imagine is remotely common. Pretty much all of the reasons for wanting the language change is due to adherence to a very strict and self-impose set of restrictions, which preclude a swath of existing language features. I also find it pretty weird that you want to follow functional idioms but that you want to do so with OOP syntax. |
Beta Was this translation helpful? Give feedback.
-
This is only because you didn't provide enough information in your post, in fact, you don't even mention the alternatives and the issues associated with them but to address the problem you can add an extension method named
|
Beta Was this translation helpful? Give feedback.
-
@ymassad I know that my suggestion is far from perfect but at least now I can see where this proposal might be useful. |
Beta Was this translation helpful? Give feedback.
-
You are right. I like how functions compose better than objects. But I see the object.Function() syntax very convenient in many cases. |
Beta Was this translation helpful? Give feedback.
-
@eyalsk ,
This is not the same as passing the delegates to the method. In my post, the two delegate parameters can have different values on each call to DoSomething. |
Beta Was this translation helpful? Give feedback.
-
@ymassad There's really hardly a difference between And while my solution involves more typing, it also has more benefits such as code reuse. Besides that, the fact that it's possible to get that result with other design patterns currently makes this feature much less important, espically when the problem isn't common at all. |
Beta Was this translation helpful? Give feedback.
-
@willard720 , There would be a difference if you have multiple functions, e.g.:
looks much better to me than:
|
Beta Was this translation helpful? Give feedback.
-
@ymassad There's already a feature proposed that would fix that and is widely approved of. I'm pretty sure it's already a champion, I just can't find it. The syntax will look something like this: TranslateToABC() |> ConvertToXYZ() |> GetAddress() |> message; and does the same thing. This is already a feature in other languages so it has a proper term. @HaloFour Do you which feature I'm talking about? I'm not sure if I got the order of the method calls right or not. Either way, it's very elegant and solves that problem. |
Beta Was this translation helpful? Give feedback.
-
#96? |
Beta Was this translation helpful? Give feedback.
-
@willard720, You appear to have the expression back to front. The forward pipe operator (see #74 and #96) would transform: TranslateXYZToABC(ConvertAddressToXYZ(GetMessageAddress(message))); into: message |> GetMessageAddress() |> ConvertAddressToXYZ() |> TranslateXYZToABC(); |
Beta Was this translation helpful? Give feedback.
-
With regard to the above, if I may indulge in a bit of cheeky self-promotion, a library I maintain, SuccincT, provides basic forward pipe operations via the message.Into(GetMessageAddress).Into(ConvertAddressToXYZ).Into(TranslateXYZToABC); It's not as elegant as having the operator, and obviously has the performance overheads associated with delegates, but some might like it 😀 |
Beta Was this translation helpful? Give feedback.
-
@DavidArno Pipe operators, that's what I was thinking of. And the extension methods syntax isn't bad either! Though isn't there gonna be a performance hit from sending the delegates? |
Beta Was this translation helpful? Give feedback.
-
@willard720, good point re performance. I updated my comment to admit that. |
Beta Was this translation helpful? Give feedback.
-
@willard720
You know there is. No worse than LINQ though, so it hardly seems worth worrying about. The rule about optimizing measured hot paths still applies. |
Beta Was this translation helpful? Give feedback.
-
@jnm2 I assumed it wouldn't be a massive performance. I made a similar thing once and it ended up being around 10x slower, so it was around 0.0001s, instead of 0.00001s to use it like a million times in a loop. So basically it isn't a big enough difference to worth mentioning and I assume a similar difference will be present here. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
It would be really nice to be able to invoke Func and Action parameters using the object.Function() syntax. Consider the following example:
'ext' stands for extension. I am not sure if this is the best keyword though.
The DoSomething method takes two Func parameters. The special thing about these parameters is the 'ext' keyword applied to them.
The body of the method uses GetDescription on the Customer object as if it were an instance method. The same thing is true for Order.
In the example, two parameters have the same name. C# would allow this because they have the 'ext' keyword.
Under the hood, the C# compiler could name these Customer_GetDescription and Order_GetDescription and have special attributes applied to the parameters (or the method?) that contain the "real" names.
I see two benefits:
We get to name the parameters GetDescription instead of GetCustomerDescription and GetOrderDescription.
We get better experience by typing 'customer.' and then have IntelliSense help us complete the method invocation. I see this as getting best of both the functional programming way of composition and the OOP way of thinking about the object (the customer and the order) when deciding what to do next.
UPDATE:
The value of this feature is more visible when you invoke multiple functions in a single expression like this:
TranslateXYZToABC(ConvertAddressToXYZ(GetMessageAddress(message)))
With the proposed feature, it will look like this:
message.GetAddress().ConvertToXYZ().TranslateToABC()
Which looks much better to me.
UPDATE: When adding this issue I used the following syntax first, then I decided to change it to the syntax presented before:
I think that the 'ext' syntax is much better because it allows us to use any delegate type and also because it does not require modifying the syntax for generic arguments.
Beta Was this translation helpful? Give feedback.
All reactions