Hacker Read top | best | new | newcomments | leaders | about | bookmarklet login

Only thing is actually missing from C# now to be a "proper" functional language is a way to declare (and pass a function arguments) immutable objects.


sort by: page size:

It's possible to write functional C# code, as well.

Eh, C# is good for the environment it lives in, but it's not without it's cruft.

C#'s answer for all of its missing features seems to be a generic class. Don't have tuples? We'll give you Tuple<T>. Don't have inline functions? We'll give you Func<T>. It feels very tacked on (especially Func).


C# is filled to the brim with functional programming features. Much of the base class library is somewhat functional (although obviously not all or even most, given the age of the BCL and stability of the API).

C# continues its tradition of stealing the good stuff from other languages. I'm really impressed. Pattern matching and immutable objects? This is great!

The way current C# does accessors / properties is just about perfect, I wish more languages would adopt it.

C# developer here, with a long history of OCaml development (and I'm still using OCaml knowledge as a filter for recruiting C# developers).

First-class functions in C# are nice, nearly as good as those in OCaml. The main annoyance is the incompatibility between Action<> and Func<> (and, in general, the fact that C# uses void rather than unit).

--

Immutability: for every mutable class in our code base, there are three or four immutable classes, and `readonly` is likely the most frequent keyword. Among these, we have an entire hierarchy of dozens of classes that are entirely immutable (and make heavy use of immutable containers from Microsoft) because it's still the easiest way to implement a multi-reader, single-writer thread-safe data structure. You can survive without immutable-by-default, you can survive without OCaml's

    { record with  a = b ; c = d }
syntax, but it gets very, very annoying to work without

    {< self with a = b ; c = d >} 
in an object-oriented language.

Algebraic data-types: I'm mostly writing compilers (yes, in C#, don't ask), and instead of writing a simple

    | SetLineOp of param * param * index
I have to define a new class, three readonly fields, a constructor to set them, equality operators (R# helps, but still...), and five or six lines of visitor pattern boilerplate in order to get the "you missed a case" warning in pattern matching. This gets very annoying very quick, and there is no practical benefit to having all those classes here.

--

Type inference: C# does manage to be fairly clever, although not as clever as OCaml. I have seldom found it to be lacking in general use, aside from the ability to define local functions (var f = a => { ... } does not work, you have to spell out the type of f). There have been a handful of times when I was trying to do something very clever and found myself limited by the type system, and had to write annotations myself.

And one time, I had to reimplement GADTs with generics and reflection. It was painful, but it works.

However, with a few minor tweaks (e.g. an option type), I would rather have the C# type inference than the OCaml one. The reason is that, if I want to do something very clever, I will not find myself limited to code that I can actually prove to the OCaml compiler as correct: I have, time and time again, resorted to reflection and code generation to work around such situations. In other words C#'s Obj.magic is a lot more powerful (and safe, and expressive) than OCaml's.

A fairly good example is Eliom's way of expressing the parameters of a service. In C# you would write in a PageController class

    public Details Update(PageId id, UserId user, [PostBody] Details body) 
and have your web framework automatically bind this to POST /page/update/{id}?user={user} with the appropriate serialization for PageId and UserId. And writing such a framework is easy: a couple hundred lines of code, with run-time type safety.

In OCaml you have to understand the entire Eliom_parameter framework: https://ocsigen.org/eliom/4.2/api/server/Eliom_parameter Just think of the mental firepower needed to create that framework in the first place!


> Immutable data is also becoming a common pattern even in C# but it's tedious as hell to write.

I can simplify it for you:

    public class TestClass : Record<TestClass>
    {
        public readonly int X;
        public readonly string Y;
        public readonly Guid Z;

        public TestClass(int x, string y, Guid z)
        {
            X = x;
            Y = y;
            Z = z;
        }
    }
That is an immutable type that has structural equality and ordering, a strong GetHashCode() implementation, as well as a default ToString() which previews the members, and serialization and deserialization constructs. It's a feature I recently added to language-ext [1].

If you need `With` functionality, then add the following member:

    public TestClass With(int? X = null, string Y = null, Guid? Z = null) =>
        new TestClass(X ?? this.X, Y ?? this.Y, Z ?? this.Z);
Then you can use named parameters to do partial updates:

    value = value.With(X: 456, Y: "World");
Obviously it's still more boilerplate than F#, but C# is never going to have significantly less until we get proper record types and ADTs.

> Functional programming is also seeping in but again tons of boiler plate.

Do you have an example? It's something I've worked on quite heavily over the past few years, so I'm always looking for areas to try and improve the lot of C# devs trying to write functionally.

[1] https://github.com/louthy/language-ext/releases/tag/v2.1.0


I also feel like "Funcs" are a work around. What I like the most about C# is the fact that it keeps evolving and incorporating new paradigms (closures, lambdas, LINQ, etc)

I do, because many of our requirements are purely functional. E.g. Turn a bunch of database queries into a user-friendly report.

They're eager to use the latest enhancements to C# that come from the functional world (e.g. lambdas, await/async), but it's impossible to get them to give up their mutable variables and null pointers.


C# was first to introduce most mainstream functional concepts into C-like languages: generics, lambdas, LINQ etc.

Aye - but the annoying thing is that it was never necessary: with a few subtle changes to Linq it’s possible to have allocation-free closures by passing state via hidden parameters on the stack - but just like every language out there we’re now hobbled by decisions made 15 years in the past.

——

On a related note, it’s interesting just how unpopular so many new C# language features are (just by looking at the numbers of Thumbs-down reactions on the GitHub Issues/PRs - stuff like top-level Main. It feels like C#’s LDT wants to be like Swift, but without Swift’s willingness to ditch ill-conceived features after a few years… but I think C# would be well-served by taking an axe to some language-features by now - like keyword-Linq and CLS-compliance (honestly, do any ISAs today still lack hardware support for unsigned ints?)


when I think back to my C# days, it makes me wonder how I ever did without functions as first class objects and a slew of other really great things about JS.

C# has delegates, events, lambda function, properties and async function as language constructs. This is as "first class" as it gets. It also has LINQ.


I'm wondering why the C# team is so keen on pattern matching - I feel like multiple dispatch would suit the language more and accomplish much the same thing. But C# is a weird beast in some ways - a pure OO language that keeps introducing features to make writing getters and setters more and more convenient.

Maybe I just need to move on with the times. I still see a lot of value in OO, but it's clear it's not at all in vogue. I am glad that functional ideas - particularly immutable data, and anonymous functions - have come into the mainstream. But I don't feel the need to throw the baby out with the bath water.


C# is fundamentally OO, so while you can write some pretty functional code in C#, you can't get away without touching OO.

I actually think C# (and many OOP languages) gets around this fairly well, by having virtual and extension methods. Many types of functions can be added easily without needing to go back through every inheritor.

C does the same thing. I didn't know C# followed the functional train all the way to lazy evaluation of arguments. But given the fact that C# isn't purely functional, that seems like a bad design decision.

Yep. A long time ago I remember using C# delegates to pass methods into a standard error handling wrapper. It's part of the language, but this was before functional programming was part of most OO Devs toolkit. Everyone was completely confused by it.

Yeah this is one of the ways I think C# is clearly improvable is having a type system closer to TS.

That really cracks me up! I work in C# probably 80% of the year (python and shudder vbscript make up the remainder) and I use lambda statements, implicit typing, and anonymous functions almost every day. The Linq IEnumerable<> extensions are also pretty well indispensable for me. My biggest complaint with C# is the limitations imposed by the static typing system: anonymous functions can't be generic, so you're forced to either declare delegates or explicitly declare each of your anon signatures; and KeyValuePair<> and Tuple<> both force you into sometimes excruciatingly, comically long object declarations, eg

Tuple<string, IEnumerable<string>, IEnumerable<KeyValuePair<string, bool>>

I've come to a point where I can comfortably write functional code in the language (though I should stress that I don't write "pure" functional code; I don't fall into the camp that abhors side effects in all scenarios). Day to day, it really is a fine language to work in, notwithstanding a few warts. In all honesty though, I'd rather be working in Python or a LISP most of the time

next

Legal | privacy