Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding the pipeline operator to C# #1309

Closed
asydneylover opened this issue Feb 5, 2018 · 19 comments
Closed

Adding the pipeline operator to C# #1309

asydneylover opened this issue Feb 5, 2018 · 19 comments

Comments

@asydneylover
Copy link

The Pipeline operator is going to add to Javascript, and I see it greatly enhances readability to multiple method invocation https://github.com/tc39/proposal-pipeline-operator
How abount adding it to C#?

@HaloFour
Copy link
Contributor

HaloFour commented Feb 5, 2018

#74 and #96 as well as probably a couple of others

@Neme12
Copy link

Neme12 commented Feb 5, 2018

We have extension methods for this.

@aluanhaddad
Copy link

It's worth noting that while the OCaml style syntax is equally out of place in JavaScript as in C#. The former is slightly more amenable to the pipeline operator because you can trivially define curried functions and also because free functions are more common.

@jeffrey-igaw
Copy link

The extension method is not a perfect match for the pipeline. We need.

@MaLiN2223
Copy link

@jeffrey-igaw Why do you think extension methods are no match for pipelines? I think they do fit good in C# syntax as a "substitute". I think we could do most of the things using extensions methods with some Func<T,TK> Could you provide an example?

@jeffrey-igaw
Copy link

jeffrey-igaw commented Feb 7, 2018

@MaLiN2223 Hi! I'm not good at English, but i fully agree with issue #74, we quite often use util classes in other library or project, when we want to call the methods with chaining, we write some extension class every each util.
If we use pipe operator, it is more readable, no additional codes, no performance degradation.

and if it is possible. it also has a good effect on local functions, delegates, Func, Action that use local variable on parent scope.

Entity Something()
{
    using(var context = SomeDbContext())
    {
        // this also change to private static method on this class
        // but if need more parameter( four and five more.. ), i like this way.
        function Task localFunction(Entity entity) {
            // some entity codes...
           context.UseThis(entity);
        }

        // if not pipe operator
        // return Updatable.StaticFuncOrAction(localFunction(LibraryUtil.Method(entity.SomeExtendMethod())))
        return entity.SomeExtendMethod()
            |> LibraryUtil.Method
            |> localFunction
            |> Updatable.StaticFuncOrAction
    }
}

In fact, i do not think the pipe operator is a huge deal, but i think it's definitely helpful when we're coding these little pieces. 😄

@aluanhaddad
Copy link

@jeffrey-igaw the pipeline operator wouldn't help with that at all. It doesn't make void functions return a value. I believe you're thinking of Method Cascades.

@jeffrey-igaw
Copy link

jeffrey-igaw commented Feb 7, 2018

@aluanhaddad Sorry i write wrong return type in this example, actually should return Entity or something. i want you to look this code as an example.

Yes, you're right this is just method cascades with no need additional extension methods(and i don't know FP as well, i don't want C# to be similar to more FP). more simply, Why should we add an extension method for just one call with performance degradation? wouldn't it be better if we could avoid it(even if it is small)?

and like tc39 proposal, if the pipeline operator is also able to use await, the code will be cleaner.

return somethings |> await AsyncMethod |> A |> B |> C;

// non pipe line operator
return C(B(A(await AsyncMethod(somethings)));

or with extensions

public static class SomethingsExtensions
{
    public static AA A(this TypeA  typeA) { ... }
    public static AB B(this TypeB  typeB) { ... }
    public static AC C(this TypeC  typeC) { ... }
}

// ..and

return (await AsyncMethod(somethings)).A().B().C();

Can you explain why you don't need it if possible with examples?

@aluanhaddad
Copy link

aluanhaddad commented Feb 22, 2018

@jeffrey-igaw I follow you now.

Extension methods are statically dispatched so I wouldn't worry about performance but I do agree that it is verbose to define them.

Note that if you only have unary functions, you can already write generic extension methods that chain them together.

@ufcpp
Copy link

ufcpp commented Feb 23, 2018

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System;

static class Delegates
{
    public static Action Static = StaticMethod;
    static void StaticMethod() { }

    // faster than Static, but bit tricky
    public static Action CurriedDelegate = default(object).ExtensionsMethodWithDummyArg;
    static void ExtensionsMethodWithDummyArg(this object dummy) { }

    // I want this to be curried too, if the pipeline operator is introduced
    public static Action CurriedPipeline = default(object) |> StaticWithDummyArg;
    static void StaticWithDummyArg(object dummy) { }
}

/// <summary>
/// a result in my PC.
///           Method |     Mean |     Error |    StdDev |
/// ---------------- |---------:|----------:|----------:|
///           Static | 20.37 us | 0.0580 us | 0.0515 us |
///  CurriedDelegate | 15.26 us | 0.0530 us | 0.0496 us | // faster
/// </summary>
public class InvokeBenchmark
{
    const int N = 10000;
    [Benchmark] public void Static() => Invoke(Delegates.Static);
    [Benchmark] public void CurriedDelegate() => Invoke(Delegates.CurriedDelegate);

    private static void Invoke(Action action)
    {
        for (int i = 0; i < N; i++) action();
    }
}

class Program
{
    static void Main() => BenchmarkRunner.Run<InvokeBenchmark>();
}

@samuelludwig
Copy link

Has there been any significant deliberation on this suggestion as time has gone on? I adore the pipe operator in Elixir and would love to have it in C# as well.

@CyrusNajmabadi
Copy link
Member

@samuelludwig No. If/when such things happen, the issues are updated accordingly. Thanks! :)

@GratianPlume
Copy link

GratianPlume commented Mar 26, 2020

We have extension methods for this.

extension method can't handle this case:

void Foo(int x, class1 y, class2 z) {
    x |> y.Add |> z.handle;
}

@hez2010
Copy link

hez2010 commented Mar 26, 2020

Extension methods can only be used when the method itself being declared as an extension method. However, pipeline operator allows non-extension methods to be piped.

@1g0r
Copy link

1g0r commented Sep 13, 2020

We have extension methods for this.

With Extension methods you are forced to write additional classes methods and so forth

@YairHalberstadt
Copy link
Contributor

Closing as duplicate of #74 and #96

@winstonpuckett
Copy link

Sad this is closed 😭

@theunrepentantgeek
Copy link

@winstonpuckett it's closed because it's a duplicate of two existing issues, not because the idea has been rejected.

@winstonpuckett
Copy link

@winstonpuckett it's closed because it's a duplicate of two existing issues, not because the idea has been rejected.

Oh, lol. Thank you. This was my first time responding to a github issue. Now I know to check the bottom for the comment on why it was closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests