65 comments

[ 3.3 ms ] story [ 145 ms ] thread
C# continues its tradition of stealing the good stuff from other languages. I'm really impressed. Pattern matching and immutable objects? This is great!
“Good artists borrow, great artists steal.”
It doesn't always steal, AFAIK is was the first language to introduce "async" and the compiler magic that goes with it, i.e. so you don't have to use callbacks everywhere.
Async/await started with F# and was added to C# later.
While booth F# and C# have the same aim, they have totaly unrelated implementation and are quite different beats. IMO the C# design wasnt derived from F#.
They are similar in that F# was the first .NET language to say, "what could language constructs for asynchrony look like?" and implement it.

They are fundamentally different models, though.

F# uses a "cold task" model where invoking an async function returns a specification of work, which you must then start. You can start this work in different ways so that you have control over the semantics of how it executes.

C# uses a "hot task" models, where invoking the async method returns a handle to background work that has already been "kicked off". This is actually an oversimplification, because the semantics of what is actually the asynchronous thing you're awaiting can differ. But the overall concept follows this pattern.

I think F# had similar syntax prior to C# with Async Workflows. But C#'s refinement of this syntax seems to have caught a lot more attention.

I can't wait to have Async + ValueTask in C# 7 to help reduce the penalty of Async a bit more.

Alice ML¹ had that in 2000², and the idea of promises/futures dates back to the 70s. async/await to flatten promise hierarchies is decidedly _not_ a new idea.

¹ http://www.ps.uni-saarland.de/alice/manual/futures.html

² Well, it used "spawn" instead of "await". The semantics are very similar though.

the semantic and working implementation of spawn/away are quite different from async/await. While they might be related, i think it's kinda of stretch to call them prior arts...
They're really not all that different. Both are implementations of concurrency based on data-flow synchronization. Alice ML is explicit about running concurrent promises (it has other types of promises as well) in “threads”, but they're lightweight userspace threads. C# AFAIK doesn't specify any particular execution model for await.
The innovation was to combine async/await to flatten promise hierarchies with asynchronous callback-based IO under the hood to implement those promises without using background threads.

That was the new idea that suddenly made those decades-old promises useful for the software industry, as it allowed both blocking-style code simplicity and callbacks-style IO scalability.

The ML link says “evaluates the expression exp in a new thread and returns immediately with a future of its result” which translates to “not scalable”.

Alice ML “threads” are more like Erlang threads than C# threads. They're lightweight userspace threads and you can have thousands of them. That's quite scalable.

Also, that's not a new idea. Blocking-style code with async I/O scaling was pioneered by Oz in 1991. (It did it a little bit differently from Alice ML.)

“They're lightweight userspace threads and you can have thousands of them.” — can I use 1000 lightweight userspace threads to run 1000 concurrent kernel-space IO operations on files or sockets, one thread each?
Yes, that's precisely the point.
MS implemented IOCP in Windows NT in 1994, then BSD implemented kqueue in 2000, then Linux implemented epoll in 2002 (they all functionally very similar).

That means outside Windows, asynchronous event-based IO was only possible after 2002 (that’s when the first version of libevent was released).

And yet you’re telling me the ML threads in 2000 were capable of high-performance async IO? You sure about that? In 2000, which kernel API you think that runtime used for IO?

Yes, and VMS had asynchronous system traps for I/O in 1977.² ³

And yes, of course? Erlang could do scalable async I/O in 1988.

Alice ML and Erlang both emulate async I/O by having a few OS level threads each switching between a large number of userspace/VM threads. They queue I/O operations then preempt VM threads when results are ready. For a while that was the only sane way around the clusterfuck that is async I/O on *nix. It still scales fine and I think there's rather little interest in converting either Alice ML or Erlang to libevent/libev/libuv.

¹ The initial Erlang VM was very slow, but the I/O model was there. BEAM was created in 1992 and was fast enough for Ericsson to use in production.

² NT and VMS were both designed by David Cutler, who is more or less the father of asynchronous I/O at the OS level.

³ Incidentally, if you think async I/O in 1977 was advanced, you should look at AS/400 or VOS sometime.

> It still scales fine

Only 1024 sockets per select because FD_SETSIZE constant? How’s that scales fine? You have 10k sockets = you need 10 native threads, with 10 native stacks, on a quad code machine each of them is guaranteed to be out of CPU cache when IO completes. Not fine, very inefficient.

> there's rather little interest in converting either Alice ML or Erlang to libevent/libev/libuv.

Well, Erlang developers don’t care about windows. And for BSD, Linux and Solaris they already support native event-based async IO for many years. They call the feature “kernel poll”.

> if you think async I/O in 1977 was advanced

I aware on some systems it was widely used. Just not on the mainstream *nix systems where that Alice ML ran in 2000.

BTW Windows got it thanks to Dave Cutler whom they poached from VMS. VMS, I hear, head and shoulders above everyone in concurrent I/O at that time. Concurrency story on the unix side has always been weaker in comparison. That's bit of a shame because the _logical_ virtual machine that C targeted, the PDP, had instruction level support for coroutines.

BTW you don't really need kernel support for concurrency although it helps a great deal if you have. One way to do it would be to compile coroutines to an eventloop runtime and break read and writes into smaller concurrent chunks.

(comment deleted)
AFAIK, linq didnt exist anywhere else
IMO, C# is the language that best hits the sweet spot of evolution pace: not so slow that it becomes stagnant and outdated, but not so fast that people feel adrift and confused. C# 6 may not have had any show-stopper features like Linq or async/await, but the syntactic sugar all aimed at immutable/functional styles have let me clean up my code tremendously, and it looks like 7 is going to be more of that. Looking forward to it very much.

Edit: I stand by my statement even though I guess pattern matching and immutable types will have to wait for C# 8. The Python-esque tuples allowing for multiple return values without out params or Tuple<> is enough to keep me happy :)

I'd say they added a dash of Erlang to C# with the tuples and pattern matching.
This is a two-way street.

For example, many languages (Python, JavaScript, Scala, C++) already “stole” async-await stuff from C#.

As long as they don’t break IP or patent laws, I don’t see any problems with that.

definitly not. Python was late too the game yes, but I guess all the others had it way before C# (since 2012)

https://en.wikipedia.org/wiki/Futures_and_promises

The only one that "stole" it was maybe Swift.

Async-await isn’t just futures or promises.

It’s compile-time + runtime mechanism that builds those promises from the code that looks like blocking calls (i.e. easy to read, write and debug), but uses asynchronous IO under the hood (i.e. scalable).

BTW, have you read the article you linked? Because among other things, it currently says the following:

Several mainstream languages now have language support for futures and promises, most notably popularized by the async and await constructions in .NET 4.5 largely inspired by the asynchronous workflows of F#, which dates to 2007. This has subsequently been adopted by other languages, notably Dart (2014), Python (2015), Hack (HHVM), and drafts of ECMAScript 7 (JavaScript), Scala, and C++.

Since I haven't see many new Windows apps the recent years, who is actively developing new apps in C# and if yes, what kind of apps, which platforms, etc.? Is it mainly games?
Lots of games use C# because the popular Unity engine uses Mono as a runtime for user code.

Anecdotally I have some friends writing business software at various BigCo companies that use C#.

Edit: it's perhaps worth mentioning that there is some more nuance to the Unity situation with their IL2CPP tech. Bottom line: engine users are writing C#.

Our web stack is in C#
.NET has won the war over the desktop in what concerns native applications for Windows on the big corporations.

On all enterprise customers that we work with, think DAX, if the application is to run native on the desktop, which is usually means Windows workstations, the software stack tends to be .NET with some C++ here and there.

Sun never managed to understand the desktop and Oracle even less.

So unless the customer has requirements for portable desktop applications, the solution is .NET.

Totally clear that mainstream desktop is Windows, native and .NET but the question again and since there are rarely new apps on Windows: who is actively developing new desktop apps in C#, .NET on Windows which are not games?
A lot of financial institutions use .NET for in-house desktop apps.
>who is actively developing new desktop apps in C#, .NET on Windows which are not games?

Almost everybody doing in-house enterprise desktop apps (and those are a heck of a lot) and tons of people doing desktop Windows apps that don't need to be C++ (e.g. not Photoshop, Office and co).

Again, those are in the tens or hundreds of thousands. Check any Windows app review site or repo for examples.

We write a lot of desktop apps in-house.

It is _massively_ faster to write a quick UI in .Net than it is to write one in HTML.

(comment deleted)
How come there are rarely new apps on Windows?

I have been doing WPF development in the last two years for enterprise customers.

Also as a Windows user, there are plenty of applications to choose from.

Ticketmaster, bet365, MoonPig, Sky TV, LateRooms.
I just made one today. Took me about two hours to make a simple app for reviewing ~GB sized slides from digital microscope. I haven't written any in the past 5 years, though. I'm still blown away by how much more efficient I'm with Windows Forms compared to anything on the web.
There is a lot of code being written outside of your bubble. I don't mean that in a negative way; we all have our own bubble, but you have to appreciate that what you're into does not represent the industry as a whole.
I don't know about Windows or Windows Phone apps, but I know that C# is quite popular for developing web applications and services, although it's mainly so among non-silicon-valley companies.

C# and .NET used to be tied to Windows and IIS, Microsoft's web server, but recent developments are making it possible to create self-hosted applications and services written in C# that run in Linux. The self-hosting functionality is fairly mature by now, but the Microsoft implementation of cross platform C#/.NET is very early in its development.

It'll be interesting to see if Linux becomes a popular environment for developing and hosting .NET applications.I predict that it will be used, but it won't overtake the widely-used open-source alternatives such as Ruby, Python, and Node.js.

It's very easy to use C# to develop Windows services. I've written a few Windows services with C#, and it was pretty simple.

There's a huge amount of server-side enterprise software - Sharepoint stuff, things like that.
Some startups use it for their stack. BizSpark + C#/.NET + Azure is a really attractive stack for the aspiring startup, IMO.
I am doing healthcare development in C# - CQMs (clinical quality measures), CCDA generation and parsing, HL7 processing, patient portals, doctor portals, ePrescribing, direct messaging, lots of REST APIs as client and server, the list goes on and on. C# is an excellent fit for all of this and lets us develop powerful applications quickly. The web sites are IIS and most of the applications are distributed as Windows Services.

The typical model for most of our applications is we have three components - background agent, UI, and database. The UI handles configuration, user management, controls starting and stopping of processes, and also handles incoming API calls. The background agent is usually a windows service and the database is usually SQL Server.

Our products are used by hospitals as installable products and also by software vendors as libraries and bolt-on applications.

> CQMs...CCDA generation and parsing...

My condolences.

To be honest though I love working on CQMs. Of all the projects I've worked on in my career this is by far my favorite. Like CCDAs I could care less for the QRDA aspect but neither of those are my focus.
I do. No, not games. Recently CAD/CAM, previously GIS and other desktop software.

BTW, here's the third-party C# Windows app I use most often: https://windows.github.com/

Skyrim, Minecraft, GTA5, Witcher3
I'm curious how array slicing is any different from ArraySegment<T>, which is very old.
ArraySegment<T> is just a array reference with range delimiters. Slice/Span gives you a low overhead, type safe window into a block of memory that can be reinterpreted without allocating new memory. It's implementation involves some IL level pointer hacks to keep it fast.

Joe Duffy's first implmentation of it is here: https://github.com/joeduffy/slice.net

The more recent work for CoreFX is here: https://github.com/dotnet/corefxlab/tree/master/src/System.S...

So instead of improving the implementation of ArraySegment they just add yet another way of doing it?

This is of course expected for languages which keep piling up stuff but still disappointing.

Because of backwards compatibility.
How is that impacted by a faster implementation technique?

Are you arguing that some people rely on ArraySegment being slow?

No, it isn't compatible with any of the existing APIs that accept array or strings.

So making it compatible would probably require breaking its semantics.

I think Span really goes way beyond what ArraySegment was intended to do. ArraySegment was just a way of wrapping the very common 3 parameters (Array, offset, length) used in almost any buffer copy operation into a single object.

Span/slice was a much more ambitious type that not only provided fast array segment like access, but also introduced a way to provide typed views into byte[] without the cost of casting or copying memory.

Span<T> is low level enough that they considered calling it Array<T> but decided against it to avoid even more confusion.

If you want to see an example of a API failure it is with System.Tuple<>. That type is effectively being deprecated when ValueTuple comes into the BCL with proper compiler support.

The feature below amazing, I wonder how Visual studio will display it, I like it when above Properties it adds the ref count across the Solution:

      3 references
      public int Damage { get; }
      4 references
      public int Durability { get; }



  public class Sword(int Damage, int Durability);
  
This single line will result in a fully functional class:

  public class Sword : IEquatable<Sword>
  {
      public int Damage { get; }
      public int Durability { get; }
   
      public Sword(int Damage, int Durability)
      {
          this.Damage = Damage;
          this.Durability = Durability;
      }
   
      public bool Equals(Sword other)
      {
          return Equals(Damage, other.Damage) && Equals(Durability, other.Durability);
      }
   
      public override bool Equals(object other)
      {
          return (other as Sword)?.Equals(this) == true;
      }
   
      public override int GetHashCode()
      {
          return (Damage.GetHashCode() * 17 + Durability.GetHashCode())
              .GetValueOrDefault();
      }
   
      public static void operator is(Sword self, out int Damage, out int Durability)
      {
          Damage = self.Damage;
          Durability = self.Durability;
      }
   
      public Sword With(int Damage = this.Damage, int Durability = this.Durability) => 
          new Sword(Damage, Durability);
  }
No biggie, but I do miss rotate, partition, nth_element from STL. Its just that when I came to C# i came with an expectation that it would have all of STL covered and more.
C# is basically becoming Scala
Minus the type system that is itself Turing complete.

In all seriousness, the culture behind C# is way too conservative for it to ever to become like Scala. They add features, but they're nowhere near as bold and daring as the Scala team. As a language, Scala's is both incredibly impressive and terrifying from an Abstraction Astronaut's perspective. Even F# is very conservative compared to Scala.

I had a lot of hope for some wilder C# changes with the .Net core change. But i see a lot of hold back from established codebases. I almost wish we could fork the language to target the Java-esque crowd and the Go/Swift/Scala crowd.
Yes, C# really prefers adding two dozen special cases and language features instead of providing one generic way of achieving something like in Scala. :-(
Object orientation and pattern matching is not an obvious mix. A lot of OO is about dependency inversion, which is more or less the exact opposite of what pattern matching gives you. It can be a powerful tool in the right hands but could also lead to absolute horror. Sometimes it feels like Mads and co. are too focused on making C# functional-like and in the process encourages a lot of foot-shooting.
"Sometimes it feels like Mads and co. are too focused on making C# functional-like and in the process encourages a lot of foot-shooting"

I agree. When they added dynamic and functional concepts, I though: great, a dynamic/statically typed imperative/functional oo language. Too many different ways to do things, makes it harder to understand code written in a different style. Basically the opposite of python's "pythonic way" idiomatic style.

I do love functional programming, which is why I am trying to move to f#. People at work are open to the idea!!