Phil Trelford's Array
POKE 36879, 255

C# Records & Pattern Matching Proposal

August 25, 2014 13:27 by phil

Following on from VB.Net’s new basic pattern matching support, the C# team has recently put forward a proposal for record types and pattern matching in C# which was posted in the Roslyn discussion area on CodePlex:

Pattern matching extensions for C# enable many of the benefits of algebraic data types and pattern matching from functional languages, but in a way that smoothly integrates with the feel of the underlying language. The basic features are: records, which are types whose semantic meaning is described by the shape of the data; and pattern matching, which is a new expression form that enables extremely concise multilevel decomposition of these data types. Elements of this approach are inspired by related features in the programming languages F# and Scala.

There has been a very active discussion on the forum ever since, particularly around syntax.

Background

Algebraic types and pattern matching have been a core language feature in functional-first languages like ML (early 70s), Miranda (mid 80s), Haskell (early 90s) and F# (mid 00s).

I like to think of records as part of a succession of data types in a language:

Name Example (F#) Description
Scalar
let width = 1.0
let height = 2.0
Single values
Tuple
// Tuple of float * float
let rect = (1.0, 2.0)
Multiple values
Record
type Rect = {Width:float; Height:float}
let rect = {Width=1.0; Height=2.0}
Multiple named fields
Sum type(single case)
type Rect = Rect of float * float
let rect = Rect(1.0,2.0)
Tagged tuple
Sum type(named fields)
type Rect = Rect of width:float*height:float
let rect = Rect(width=1.0,height=2.0)
Tagged tuple with named fields
Sum type(multi case)
type Shape=
   | Circle of radius:float
   | Rect of width:float * height:float
Union of tagged tuples

Note: in F# sum types are also often referred to as discriminated unions or union types, and in functional programming circles algebraic data types tend to refer to tuples, records and sum types.

Thus in the ML family of languages records are like tuples with named fields. That is, where you use a tuple you could equally use a record instead to add clarity, but at the cost of defining a type. C#’s anonymous types fit a similar lightweight data type space, but as there is no type definition their scope is limited (pun intended).

For the most part I find myself pattern matching over tuples and sum types in F# (or in Erlang simply using tuples where the first element is the tag to give a similar effect).

Sum Types

The combination of sum types and pattern matching is for me one of the most compelling features of functional programming languages.

Sum types allow complex data structures to be succinctly modelled in just a few lines of code, for example here’s a concise definition for a generic tree:

type 'a Tree =
    | Tip
    | Node of 'a * 'a Tree * 'a Tree

Using pattern matching the values in a tree can be easily summed:

let rec sumTree tree =
    match tree with
    | Tip -> 0
    | Node(value, left, right) ->
        value + sumTree(left) + sumTree(right)

The technique scales up easily to domain models, for example here’s a concise definition for a retail store:

/// For every product, we store code, name and price
type Product = Product of Code * Name * Price

/// Different options of payment
type TenderType = Cash | Card | Voucher

/// Represents scanned entries at checkout
type LineItem = 
  | Sale of Product * Quantity
  | Cancel of int
  | Tender of Amount * TenderType

Class Hierarchies versus Pattern Matching

In class-based programming languages like C# and Java, classes are the primary data type  where (frequently mutable) data and related methods are intertwined. Hierarchies of related types are typically described via inheritance. Inheritance makes it relatively easy to add new types, but adding new methods or behaviour usually requires visiting the entire hierarchy. That said the compiler can help here by emitting an error if a required method is not implemented.

Sum types also describe related types, but data is typically separated from functions, where functions employ pattern matching to handle separate cases. This pattern matching based approach makes it easier to add new functions, but adding a new case may require visiting all existing functions. Again the compiler helps here by emitting a warning if a case is not covered.

Another subtle advantage of using sum types is being able to see the behaviour for all cases in a single place, which can be helpful for readability. This may also help when attempting to separate concerns, for example if we want to add a method to print to a device to a hierarchy of classes in C# we could end up adding printer related dependencies to all related classes. With a sum type the printer functionality and related dependencies are more naturally encapsulated in a single module

In F# you have the choice of class-based inheritance or sum types and can choose in-situ. In practice most people appear to use sum types most of the time.

C# Case Classes

The C# proposal starts with a simple “record” type definition:

public record class Cartesian(double x: X, double y: Y);

Which is not too dissimilar to an F# record definition, i.e.:

type Cartesian = { X: double, Y: double }

However from there it then starts to differ quite radically. The C# proposal allows a “record” to inherit from another class, in effect allowing sum types to be defined, i.e:

abstract class Expr; 
record class X() : Expr; 
record class Const(double Value) : Expr; 
record class Add(Expr Left, Expr Right) : Expr; 
record class Mult(Expr Left, Expr Right) : Expr; 
record class Neg(Expr Value) : Expr;

which allows pattern matching to be performed using an extended switch case statement:

switch (e) 
{ 
  case X(): return Const(1); 
  case Const(*): return Const(0); 
  case Add(var Left, var Right): 
    return Add(Deriv(Left), Deriv(Right)); 
  case Mult(var Left, var Right): 
    return Add(Mult(Deriv(Left), Right), Mult(Left, Deriv(Right))); 
  case Neg(var Value): 
    return Neg(Deriv(Value)); 
}

This is very similar to Scala case classes, in fact change “record” to case, drop semicolons and voilà:

abstract class Term
case class Var(name: String) extends Term
case class Fun(arg: String, body: Term) extends Term
case class App(f: Term, v: Term) extends Term

To sum up, the proposed C# “record” classes appear to be case classes which support both single and multi case sum types.

Language Design

As someone who has to spend some of their time working in C# and who feels more productive having concise types and pattern matching in their toolbox, overall I welcome our new overlords this proposal.

From my years of experience using F#, I feel it would be nice to see a simple safety feature included, to what is in effect a sum type representation, so that sum types can be exhaustive. This would allow compile time checks to ensure that all cases have been covered in a switch/case statement, and a warning given otherwise.

Then again, I feel this is quite a radical departure from the style of implementation I’ve seen in C# codebases in the wild, to the point where it’s starting to look like an entirely different language… and so this may be a feature that if it does see the light of day is likely to get more exposure in C# shops working on greenfield projects.


Tags:
Categories: .Net | C# | F# | Scala | Haskell | Erlang
Actions: E-mail | Permalink | Comments (3) | Comment RSSRSS comment feed

Orleans

April 3, 2014 10:28 by phil

Microsoft’s Build 2014 conference is currently in full flow, one of the new products announced is Orleans, an Actor framework with a focus on Azure.

There’s an MSDN blog article with some details, apparently it was used on Halo 4.

Demis Bellot of ServiceStack fame, tweeted his reaction:

I retweeted, as it wasn’t far off my initial impression and the next thing I know my phone is going crazy with replies and opinions from the .Net community and Microsoft employees. From what I can make out the .Net peeps weren’t overly impressed, and the Microsoft peeps weren’t overly impressed that they weren’t overly impressed.

So what’s the deal.

Actors

Erlang has distributed actors via OTP, this is the technology behind WhatsApp, recently acquired for $19BN!

The JVM has the ever popular Akka which is based heavily on Erlang and OTP.

An industrial strength distributed actor model for .Net should be a good thing. In fact Microsoft are currently also working on another actor framework called ActorFX,

The .Net open source community have projects in the pipeline too including:

There’s also in-memory .Net actor implementations with F#’s MailboxProcessor and TPL Dataflow. Not to mention the departed Axum and Retlang projects.

Orleans

From what I can tell, Orleans appears to be focused on Azure, making use of it’s proprietary APIs, so there's probably still a big space for the community's open source projects to fill.

Like Demis I’m not a huge fan of WCF XML configuration and code generation. From the Orleans MSDN post, XML and code-gen seem to be front and centre.

You write an interface, derive from an interface, add attributes and then implement methods, which must return Task<T>. Then you do some XML configuration and Orleans does some code generation magic for hydration/dehydration of your objects (called grains).

Smells like teen spirit WCF, that is methods are king, although clearly I could be reading it wrong.

From my limited experience with actors in F# and Erlang, messages and message passing are king, with pattern matching baked into the languages to make things seamless.

Initial impressions are that Orleans is a long way from Erlang Kansas…

The Good Parts

Building a fault-tolerant enterprise distributed actor model for .Net is significant, and could keep people on the platform where they may have turned with Erik Meijer to the JVM, Scala and Akka otherwise.

Putting async front and centre is also significant as it simplifies the programming model.

C# 5’s async is based on F#’s asynchronous workflows, which was originally developed to support actors via the MailBoxProcessor.

Coroutines

Underneath, Erlang’s processes, F#’s async workflows and C#’s async/await are simply implementations of coroutines.

Coroutines are subroutines that allow multiple entry points for suspending and resuming execution at certain locations. They’ve been used in video games for as long as I can remember (which only goes back as far as the 80s).

Coroutines help make light work of implementing state machines and workflows.

Methods

In Erlang messages are typically described as named tuples (an atom is used as the name), and in F# discriminated unions are typically employed.

Orleans appears to use methods as the message type, where the method name is analogous to an Erlang atom name, or an F# union case name and the parameters are analogous to a tuple. So far so good.

Where they differ is that return values are first-class for methods, and return values feel more like an RPC approach. In fact this is the example given in the article:

public class HelloGrain : Orleans.GrainBase, IHello
{
  Task<string> IHello.SayHelloAsync(string greeting)
  {
    return Task.FromResult("You said: '" + greeting + "', I say: Hello!");
  }
}

Also current wisdom for C# async is to avoid async void... which is why I guess they’ve plumped for Task as the convention for methods with no return value.

Messages

.Net’s built-in binary serialization is bottom of the league for size and performance, hopefully alternative serialization libraries like Google Protocol Buffers will be supported.

Judge for yourself

But these are just my initial impressions, try out the samples and judge for yourself.


Tags:
Categories: .Net | C# | F# | Erlang | Scala | Architecture
Actions: E-mail | Permalink | Comments (2) | Comment RSSRSS comment feed

Walkie Scorchie

September 7, 2013 16:58 by phil

From the window at the office I’ve seen a series of futuristic buildings erected, first the Gherkin, then the Shard and now the Walkie Talkie:

London skyline 

The last one being recently been re-dubbed the Walkie Scorchie as it produces a supercharged solar ‘death ray’ that has burned holes in carpets, melted furniture and even the interior of a Jaguar parked nearby.

It feels almost reminiscent of the dystopian future portrayed in the cult film Idiocracy:

Idiocracy skyline

Though our current society is probably closer to the surveillance society of 1984 with the omnipresent Big Brother watching over you:

Big brother is watching you

The everyday software we work with is no less broken, or so Scott Hanselman concludes in everything's broken and nobody's upset.

Software is increasingly a world of broken windows where developers are more accustomed to working around issues than giving feedback, let alone tackling the root causes.

waiting for background operation to complete modal dialog 

Anyone else struggling with the cognitive dissonance of a modal dialog waiting for a background operation to complete?

XAML

I’ve been using XAML in it’s various guises off an on for over 5 years now. Over that time I’ve used WPF, Silverlight and Metro. It feels like little has changed in that time. It’s still probably the best thing out there for desktop app development but surely we could do better.

XML

I’m still stuck editing views in XML, the poor man’s DSL. I, like the developers I know rarely use the designer view. When we do it frequently hangs and we’re left manually killing XDescProc.exe from task manager.

Data Binding

Data binding is central to XAML. With it you can easily bind a collection to a data grid and get sorting and filtering for free. But binding comes with a high performance cost and it’s stringly typed nature means you’re left finding binding errors in the output window at runtime.

Dynamically binding a view to a model would make more sense to me if I could edit the view at runtime, but you can’t, it’s compiled in.

Value Converters

If I want to transform a model value bound to the view to a different form I have to create a class that implements the IValueConverter interface then reference it as a static resource in the resources section. It has all the elegance of C++ header files. Achieving the same thing in ASP.Net is much simpler, you can just write inline some code in the view or call a function.

INotifyPropertyChanged

There’s a plethora of libraries and frameworks dedicated to working around this design decision, from the MVVM frameworks with LINQ expressions to PostSharp and attributes. The C# 5 compiler’s CallerMemberName attribute has finally brought some sanity to the situation. But I know many developers, including myself, have wasted countless hours dealing with it and trying to think of ways of subverting it.

Just about every view model class ends up inheriting from some ViewModelBase or ObservableObject class so that it can implement INotifyPropertyChanged.

Inheritance

It is often said that object-oriented programming is well suited to graphical user interfaces. Perhaps, but I start to have doubts when I see WPF’s Button class with 9 layers of inheritance and over 160 members.

Visual Studio 2010 introduced improved intellisense with substring search on members to partially work around this, but honestly I’d prefer to see buttons be closer to having content and a clicked event than their current diaspora of responsibilities.

Null Reference Exceptions

By far the most common error I see in C# applications is Null Reference Exceptions. Hardly a day goes by where yet another null check is added to the codebase. This needs to be fixed at the language level, functional-first languages like Scala and F# show it’s possible.

HTML5 & JavaScript

HTML 5 and JavaScript are now being pushed as an alternate environment for desktop development. JavaScript has come a long way performance and libraries wise and I like the HTML 5 Canvas model. However I’m not yet convinced how well this scales to multi-window applications that need to interact between processes.

Windows 8

I get that Metro style interfaces are good for tablets and touch, but for multi-window desktop applications it feels like a non-starter.

 

I’ve seen traders use 9 displays simultaneously, running a multitude of different apps from execution platforms and news services to Excel, Outlook and instant messengers.

To me Windows 8 appears to be consumer orientated release. I’m hoping the next version will bring something for the larger customer base of business users.

Vendors

One person’s problem is another’s opportunity. Third party vendors like JetBrains are grasping the opportunity with both hands by patching flaws in Visual Studio and C# with tools like Resharper. They’re now starting to provide elastoplasts over XAML editing too. Jetbrains are not the only ones, Telerik and others are making hay selling themes and datagrids.

627 

To temporarily workaround performance issues caused by the cost of the mouse handler events in one these products we were forced to throttle the number of system mouse events bubbling through the system.

Duct tape is a good short term solution, but surely at some point we should consider building a stronger foundation.

Simplicity

I would not give a fig for the simplicity this side of complexity, but I would give my life for the simplicity on the other side of complexity. - Oliver Wendell Holmes, Jr.

XAML is huge and bloated, WPF 4.5 Unleashed is 864 pages long, yet XAML’s focus on data binding makes it feel like a one-trick pony.

I think a modern desktop UI environment needs to cover a diverse range of product scenarios. There should be a low-level core that can be easily accessed with code for high performance features all the way up to a designer view for tacking databases on to views, and it should all interoperate seamlessly.

Sections of the development community are striving to bring simplicity to our environments. Language designers like Rich Hickey (Clojure) and Don Syme (F#) are bringing us simplicity at the language level. I’d love to see these thought processes applied to UI environments too.

To tackle the root causes of problems some times you need to stop continuously patching over the cracks, step back and take time to look at the big picture. To create Clojure Rich Hickey practised Hammock driven development. I’d love to see more of this kind of thoughtful design and less Mortgage driven development.

Tackling the root causes of complexity and defects in our software is not an easy choice, it requires investment and changes to the way we do things. But not changing is a choice too.

They live out their lives in this virtual reality as they would have around the turn of the 20th and 21st centuries. The time period was chosen because it is supposedly the pinnacle of human civilization. – Agent Smith

Must Java like languages and XML be considered the pinnacle of software development for time immemorial?


Tags:
Categories: Architecture | WPF | Silverlight | WinRT | .Net | C# | JavaScript | Scala | F#
Actions: E-mail | Permalink | Comments (2) | Comment RSSRSS comment feed