C# functional language extensions and Erlang-like concurrency system
github.com
github.com
Its familiar Java/C like syntax, classic use of OOP, enterprise vibes will mean it'll be very familiar and easy for most to pick up. And as you go deeper, it'll introduce you to anonymous delegates, lambdas, true generics, higher order functions, true closures, list comprehensions, anonymous types, type inference, lazy evaluation and even a sprinkle of monads.
With the language extensions, you can get even further.
This is a great way to start learning about FP concepts without even knowing it and it'll make your switch to a more thorough FP language much easier, such as MLs, Lisps, Erlangs, and most proof languages.
This has absolutely nothing to do with functional programming.
> delegates, lambdas, list comprehensions, anonymous types
Syntactic sugar.
> higher-order functions, true closures
Java has them too. They're called “objects”.
> a sprinkle of monads
Every higher-order language with strict evaluation (which includes every object-oriented language) already has at least one monad, whose use is pervasive and inescapable.
So, unless you have user-definable monads, where is the improvement?
C# does have user-definable monads. There are many in this project (Option, Either, Try, TryOption, Task, Reader, Writer, State, Parser, ...)
Yes, you can.
Here's an example from version 2.0 of lang-ext (which is WIP and will be released soon) [1]:
[1] https://github.com/louthy/language-ext/blob/type-classes/Lan...
If you can't even postulate a theory (the monad signature and its equational laws), it doesn't make sense to talk about what models of the theory exist (concrete instances).
Example of extensions for ValueTuple<A,B,C> (there are extensions up to ValueTuple<A,B,C,D,E,F,G> and Tuple<A,B,C,D,E,F,G>)
https://github.com/louthy/language-ext/blob/type-classes/Lan...
It allows cool stuff like this:
var abc = ('a', 'b').Add('c'); // ('a', 'b', 'c')
var abcd = ('a', 'b').Add('c').Add('d'); // ('a', 'b', 'c', 'd')
var abcd5 = ('a', 'b').Add('c').Add('d').Add(5); // ('a', 'b', 'c', 'd', 5)
var sumA = (1, 2, 3).Sum<TInt, int>(); // 6
var sumB = (2, 4, 8).Product<TInt, int>(); // 64
var flag = ("one", "two", "three").Contains<TString, string>("one"); // true
var str = ("Hello", " ", "World").Concat<TString, string>(); // "Hello World"
var list = (List(1, 2, 3), List(4, 5, 6)).Concat<TLst<int>, Lst<int>>(); // [1,2,3,4,5,6]Or do you simply mean some leaner syntactic sugar for their on-the-fly instantiation?
Point a = b with {X = 0}
this will make using immutable record types in C# much less tedious. Will also implement other stuff like value equality override, etc. I wish this was in 7.0, this is a great way to do FP in C# when you can't use F#.Proposal link : https://github.com/dotnet/roslyn/blob/features/records/docs/...
Structs differ from classes in that they are guaranteed to be contiguously placed laid out in memory; they're also non nullable and can't be a part of the inheritance hierarchy (though they can implement interfaces, which have some perf tradeoffs).
Haven't done such "real-world" stuff (with a proper server side, client side, data side etc) in Haskell either --- yet. It's not immediately productivity-inducing at all. I think over the very long haul, prolonged intensive exposure makes many a developer of "mainstream/web/crud/mvp/etc extractions" a much more rigorous, precise, exacting practitioner, which will yield a hard-to-quantify, harder-to-capitalize-on, but still very real and more substantive/deeper/sustained "productivity boost". It also teaches one to think of more robust patterns of abstraction and generalization which can translate back into programming-in-other-languages.
Nothing more tangible than that to report. Also there's a lot of curious-researcher-type "playfulness" in the wider ecosystem that's very tricky to assess what this will actually buy the "let's get coding" "brogrammer" (such as I)!
One facet that makes it quite worthwhile is that the language/compiler/ecosystem has incredibly bright people contributing not just by devising yet another funky undecipherable combinator for saving 10 lines of code in once-a-decade scenarios, but in fact actual hardcore pedal-to-the-metal under-the-hood optimizations, code check/test/validation assistence tools, keeping it all somewhat performant in server/parallel/concurrent scenarios and so on.
That said, this looks like something I'd definitely use, or at least experiment with in C# if I was still doing work in the language - though for the actor bits I would probably lean on Orleans.
Author here. That is simply not correct. It has a full supervision hierarchy as well as a compositional strategy system for creating policies that handle failures. The strategies can also be scripted as part of the config, to detach the failure handling entirely from the actor itself.
I couldn't just jump ship and use F#, Haskell, or Erlang; so I decided to bring what I'd learned from those languages into C#, and create a library that will help me write better C# code.
My mission is to create a library that reduces the cognitive burden of writing C#. It isn't a functional manifesto for C#, it just looks like it because I've found that's the best way to achieve my goals.
The Process system (Erlang style actors) is there to deal with the 'edges' of functional code. It's not possible to be pure like in Haskell, and so you will have stateful code - with all the problems that come with it, i.e. shared memory, locks, mutability, etc. Actors allow a certain amount of control that you don't get from C# classes: Single-threaded and no-shared state. They can be distributed anywhere and the mechanism for interaction is the same. You can build in routing or proxying to do load-balancing, etc.
The thought of trying to fix up an old code base did not even cross my mind. Probably because that is what my nightmares are made of.
https://github.com/Hopac/Hopac
https://github.com/Hopac/Hopac/blob/master/Docs/Programming....
http://t0yv0.blogspot.com/2014/03/concurrent-ml-and-hopac.ht...
https://neoeinstein.github.io/blog/2016/04-08-hopac-getting-...
Erlang's message passing system is probably more important to the success of its concurrency model than the specifics of the scheduler. As proven perhaps by the success of Akka and other actor-based systems built on a different threading model.
Erlang's scheduler is preemptive. Erlang processes can be preempted by the scheduler in the middle of execution and moved to the back of the scheduler queue or to another scheduler thread. There is no requirement for a process itself to yield time back to the scheduler to make sure that other processes receive some execution time. This is one component of how it achieves "soft-realtime" semantics. Eight processes, on a system with 8 scheduler threads, running in a tight loop cannot cause all other processes in the Erlang VM to be blocked. Other processes will be given time.
The only thing that violates this guarantee is long-running or blocking code executing on the native side of the NIF boundary.
Akka, goroutines, Cloud Haskell, etc. are exactly the kinds of things I'm talking about when I say I don't understand the point of actor frameworks running in environments that can't preempt actor execution. You had better hope all your actor implementations are well-behaved or that the implementations you're going to import from someone else are all well behaved... otherwise you're going to lockup your scheduler's thread pool.
OS processes are preemptive, however process threads are not. I'm not sure what you are trying to say about Erlang's scheduler itself being cooperative. It is a preemptive scheduler.
> Erlang's message passing system is probably more important to the success of its concurrency model than the specifics of the scheduler.
I disagree, preemptive concurrency is a fundamental piece of BEAM's success. Preemption gives Erlang its fault tolerance and low latency guarantees. If by message passing you mean immutability, then perhaps they are of equal importance.
From what I know Erlang's scheduler preempts processes it executes. Can you explain what you mean by it being "cooperative". It precisely useful because it is not cooperative. And processes don't have to "yield to" the scheduler.
The Erlang VM can intercede into a running process, and also does this with some of it's BIFs implemented in C.
From what I know, they cannot, not at arbitrary places, and that's why the scheduler is a cooperative one.
From the Erlang docs on process priority.
The BEAM VM can kill, halt, or suspend a running process at anytime from outside the process. It does not need to wait around for the process to exceed its reduction count limit.
Some of this capability is even exposed to user-land applications. The exit/2 function builds on top of this capability when sending in th atom 'kill' as the second argument. As do the suspend_process/1, suspend_process/2, and resume_process/1 functions.
The reduction count system is just there as a kind of fair-scheduling determinism semantic. Exhausting reduction allocations is not the only way the VM has to interact with running processes.
> From the Erlang docs on process priority.
Well, apparently you're right. I must take back what I said about Erlang scheduler.
The system simply uses the TPL for scheduling (which is actually very good).
I'm currently working on V2 of this project to bring ad-hoc polymorphism to C# (almost type-classes), and splitting out the Core and Process (actors) libraries to separate repos.