Hacker News new | ask | show | jobs
by throw868788 1588 days ago
I do think the pipe operator is very tied into the first-class currying support and HM type inference in F#. In C# I think it makes a lot less sense.

To be honest I think each language should play to their strengths and only "steal" things that benefit their current market of users and how they work. If it augments them that's fine. Otherwise you risk cluttering the language with too many ways to do things. If you want all these F# features you probably just want F# - its not too hard to call `dotnet new classlib -lang F#` these days and mix both in together in a solution.

Having worked in a few C++ shops, at least from my experience, it can result in a lot of useless debates and internal wars if you keep on adding different features from different paradigms into the language whilst trying to keep backwards compatibility.

My view is that if you want unions/non-nullability/data vs classes even if C# gives you the features, it feels more natural to code that way in F# due to the environment around the features and years of optimising that code path. It's just less noisy and less workaround'y. i.e. each language typically prioritizes enhancements and features based on what users in that language are having pain points on. In that sense F# is much further on the data/function paradigm than C# is - conversely when doing low level stuff C# is often in front having to cater for that for some time.

1 comments

The pipe operator can be replaced by a T.Pipe(Func<T, U>) generic extension function.

In fact, I've defined it and occasionally use it in F# when I'm working with extensive C# fluent APIs, because it looks nicer than breaking them up with a single |>.

I've defined it myself (when doing C# with functional heavy code but it feels clunky) but there's still edge cases where it isn't as nice especially with functions of multiple args, or functions passed in. Sure C# can do these things with more code, just like F# can jump into some unsafe code, but its nicer in F# IMO. The other thing is that the operator as above is probably allocation heavy especially when needing to complete a function inside the lambda whereas the pipe in F# the compiler just rewrites the code. In hot loops or highly repeated workflows this makes a difference.

C# Fluent API's aren't really piped things since they usually just mutate a variable underneath (hence the ignore often at the end of them in F#). I don't think fluent API's and piped functions are the same thing, and the pipe operator allows any function that matches the signature to be put in.