[Feature Request] Return the object a method is calling on #2642
Replies: 15 comments
-
This sounds like it belongs on the csharplang repo: |
Beta Was this translation helpful? Give feedback.
-
obj.#If(true, () => {
Console.WriteLine("Oops...");
}); it would treat it as a preprocessor directive. |
Beta Was this translation helpful? Give feedback.
-
Yes, |
Beta Was this translation helpful? Give feedback.
-
It would be easy to circumvent that, as prepocessor directives must not be preceded by any token (apart from whitespaces). |
Beta Was this translation helpful? Give feedback.
-
@Unknown6656 obj.
method1().
method2(); but this would fail: messageBuilder.
#warning("Missing constructor").
#line(15); |
Beta Was this translation helpful? Give feedback.
-
This can sort of be done with extensions: public static class ObjectExtensions
{
public static TOut Pipe<TIn, TOut>(this TIn obj, Func<TIn, TOut> pipe)
{
return pipe.Invoke(obj);
}
public static TIn Pipe<TIn>(this TIn obj, Action<TIn> pipe)
{
pipe.Invoke(obj);
return obj;
}
} Usage: list
.Pipe(l => l.AddRange(...))
.Pipe(l => l.Sort())
.Pipe(System.Console.WriteLine) |
Beta Was this translation helpful? Give feedback.
-
Finally, a reason to add the back-tick operator. |
Beta Was this translation helpful? Give feedback.
-
I don't agree with extension method like
|
Beta Was this translation helpful? Give feedback.
-
I use Pipe methods (and Map, Bind, Tee) all the time. I don't think the extra verbosity is a problem, as you can easily see the nature of the next item in the chain. If you have a method which returns a non-void, non-self result, you can either .Pipe to continue that into the chain, or .Tee to perform it and ignore the output, continuing with the original chaining object. If the chained method always returned the original chaining object, how would you get the result of any non-void methods? |
Beta Was this translation helpful? Give feedback.
-
I'll just call it with dot ( |
Beta Was this translation helpful? Give feedback.
-
I think that's too unintuitive, to be honest.
It would be too easy to lose track of which value you're dealing with.
```
int a = 5;
int b = a.Add(5)
#Multiply by(2)
.Subtract(5);
```
It's just not easy to read. Sorry.
…On Sat, 20 Jul 2019, 10:56 Maxim Dobroselsky, ***@***.***> wrote:
If the chained method always returned the original chaining object, how
would you get the result of any non-void methods?
I'll just call it with dot (.) and use returned value.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<https://github.com/dotnet/csharplang/issues/2642?email_source=notifications&email_token=ADIEDQPKUHNMINAWIH5ISRDQALOLJA5CNFSM4H7KDVY2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD2NK7UA#issuecomment-513454032>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADIEDQNPDGJL3EU2NFM5NXLQALOLJANCNFSM4H7KDVYQ>
.
|
Beta Was this translation helpful? Give feedback.
-
I see one problem with this solution that a self-returning calling syntax can address:
This way, you can think of a self-returning calling syntax as supplementary to Pipe syntax, not its replacement. |
Beta Was this translation helpful? Give feedback.
-
@tonygiang - this is why I mentioned other functional-like methods, such as Tee: public static class ObjectExtensions
{
public static TIn Tee<TIn>(this TIn obj, Action<TIn> tee)
{
tee.Invoke(obj);
return obj;
}
public static TIn Tee<TIn, TIgnore>(this TIn obj, Func<TIn, TIgnore> tee)
{
tee.Invoke(obj);
return obj;
}
} |
Beta Was this translation helpful? Give feedback.
-
@tonygiang - that way, you can use Pipe to carry forward the result of the function, and Tee to carry the original value. Your code is instantly more obvious as to which version you want. |
Beta Was this translation helpful? Give feedback.
-
kotlin implements this in Standard.kt. And out of those 5 extension methods, we can port 2 of them into C#: public static T Also<T>(this T obj, Action<T> setupAction)
{
setupAction.Invoke(obj);
return obj;
}
public static R Let<T, R>(this T obj, Func<T, R> selector)
{
return selector.Invoke(obj);
} Usage: // Also:
var grid = new Grid
{
Children =
{
new Button
{
Text = "Click me"
}.Also(btn => Grid.SetRow(btn, 1))
}
};
// Let:
var button = new Button
{
Text = string.Join(", ", names).Let(txt =>
{
if (txt.Length > 40)
return txt[0..40] + "...";
else
return txt;
})
} Both extension methods are equally useful and I don't think it's practical to limit our options to only one of them. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Let's see an example:
I suggest to introduce a syntax to return the object a method is calling on. For example,
#
preceding a method. To illustrate what I'm talking about, let's see how the code above will be rewritten with this new syntax:So although
AddRange
isvoid
method it will returnlist
, the object the method has been called on. This approach can be applied to create chains like this:This feature is not limited to
void
methods only. If#
is used with methods that return some value, the value will be ignored and the object a method has been called on will be returned.This feature allows to create automatic fluent APIs. There will be no need to implement builders with ugly
return this;
at the end of methods. Fluent API will be a part of language and will be available out of the box.Beta Was this translation helpful? Give feedback.
All reactions