InfoQ

InfoQ

News

My Bookmarks

Login or Register to enable bookmarks for unlimited time.

The content has been bookmarked!

There was an error bookmarking this content! Please retry.

Pattern Matching in .NET 4

Posted by Jonathan Allen on May 28, 2009

Sections
Development,
Architecture & Design
Topics
Language Design ,
.NET
Tags
F# ,
C# ,
Functional Programming ,
Visual Basic.NET

Case statements can be thought of as specialized version of the if/else syntax. There is nothing you couldn’t already do with them, and yet there are times when they seem much clearer. Consider this example in C# and VB.

double CaclRateByDate(DayOfWeek day)
  {
      if (day == DayOfWeek.Monday)
      {
          return .42;
      }
      else if (day == DayOfWeek.Tuesday)
      {
          return .67;
      }
      else if (day == DayOfWeek.Wednesday)
      {
          return .56;
      }
      else if (day == DayOfWeek.Thursday)
      {
          return .34;
      }
      else if (day == DayOfWeek.Friday)
      {
          return .78;
      }
      else if (day == DayOfWeek.Saturday)
      {
          return .92;
      }
      else if (day == DayOfWeek.Sunday)
      {
          return .18;
      }
      throw new ArgumentOutOfRangeException("Unexpected enum value");
  }
Function CaclRateByDate(ByVal day As DayOfWeek) As Double
    If day = Monday Then
        Return 0.42
    ElseIf day = Tuesday Then
        Return 0.67
    ElseIf day = Wednesday Then
        Return 0.56
    ElseIf day = Thursday Then
        Return 0.34
    ElseIf day = Friday Then
        Return 0.78
    ElseIf day = Saturday Then
        Return 0.92
    ElseIf day = Sunday Then
        Return 0.18
    Else
        Throw New ArgumentOutOfRangeException("Unexpected enum value")
    End If
End Function

Over and over again the developer is expected to write “ElseIf day =” or “else if (day ==” even though it doesn’t add any additional information. It is just noise that distracts from the important information, namely the day of the week and and the returned value.

 In both VB and C#, we can thin this quite a bit by using a case statement.

double CaclRateByDate2(DayOfWeek day)
{
    switch (day)
    {
        case DayOfWeek.Monday:
            return .42;
        case DayOfWeek.Tuesday:
            return .67;
        case DayOfWeek.Wednesday:
            return .56;
        case DayOfWeek.Thursday:
            return .34;
        case DayOfWeek.Friday:
            return .78;
        case DayOfWeek.Saturday:
            return .92;
        case DayOfWeek.Sunday:
            return .18;
        default:
            throw new ArgumentOutOfRangeException("Unexpected enum value");
    }
}
Function CalcRateByDate2(ByVal day As DayOfWeek) As Double
    Select Case day
        Case Monday
            Return 0.42
        Case Tuesday
            Return 0.67
        Case Wednesday
            Return 0.56
        Case Thursday
            Return 0.34
        Case Friday
            Return 0.78
        Case Saturday
            Return 0.92
        Case Sunday
            Return 0.18
        Case Else
            Throw New ArgumentOutOfRangeException("Unexpected enum value")
    End Select
End Function

But even with this, there is still a lot of code that just doesn’t need to be there. Why do you have to keep repeating the fact that you were returning a value? Wouldn’t it be nice if you could write something like this?

double CaclRateByDate2(DayOfWeek day)
{
    return switch (day)
    {
        DayOfWeek.Monday: .42;
        DayOfWeek.Tuesday: .67;
        DayOfWeek.Wednesday: .56;
        DayOfWeek.Thursday: .34;
        DayOfWeek.Friday: .78;
        DayOfWeek.Saturday: .92;
        DayOfWeek.Sunday: .18;
        default:
            throw new ArgumentOutOfRangeException("Unexpected enum value");
    }
}
Function CalcRateByDate2(ByVal day As DayOfWeek) As Double
    Return Select Case day
        Monday: 0.42
        Tuesday: 0.67
        Wednesday: 0.56
        Thursday: 0.34
        Friday: 0.78
        Saturday: 0.92
        Sunday: 0.18
        Case Else
            Throw New ArgumentOutOfRangeException("Unexpected enum value")
    End Select
End Function

When you eliminate the stuff you don’t actually care about, C# and VB look remarkably similar. All that is left is the pattern you looking for and the result that you want when that pattern is found. This is what is known as Pattern Matching.

 Well unfortunately we aren’t going to see something like this in C# 4 or VB 10. But there is a new language on the block that has support for pattern matching. Consider this F# example from Mathew Podwysocki. (Please note that in all these examples a function is being created.)

let calcRateByDay2 (day:System.DayOfWeek) = 
  match day with 
  | System.DayOfWeek.Monday -> 0.42 
  | System.DayOfWeek.Tuesday -> 0.67 
  | System.DayOfWeek.Wednesday -> 0.56 
  | System.DayOfWeek.Thursday -> 0.34 
  | System.DayOfWeek.Friday -> 0.78 
  | System.DayOfWeek.Saturday -> 0.92 
  | System.DayOfWeek.Sunday -> 0.18 
  | _ -> failwith "Unexpected enum value" 

In another example, Mathew shows how to multiple parameters can be checked at the same time. In this example, the underscore is used as a wild card.

let allowUrl url port =
  match (url, port) with
  | "http://www.microsoft.com/", 80 -> true
  | "http://example.com/", 8888 -> true
  | _, 80 -> true
  | _ -> false

Unfortunately F# doesn’t have a lock on concise syntax. If you need to do anything interesting with a value then you have to go back to specifying it by name or by a placeholder.

let calcRateByDay3 (day:System.DayOfWeek) = 
  match day with 
  | x when x >= System.DayOfWeek.Monday && x <= System.DayOfWeek.Friday -> 0.42
  | System.DayOfWeek.Saturday -> 0.92 
  | System.DayOfWeek.Sunday -> 0.18 
  | _ -> failwith "Unexpected enum value"

let calcRateByDay3 (day:System.DayOfWeek) = 
  match day with 
  | _ when day >= System.DayOfWeek.Monday && day <= System.DayOfWeek.Friday -> 0.42
  | System.DayOfWeek.Saturday -> 0.92 
  | System.DayOfWeek.Sunday -> 0.18 
  | _ -> failwith "Unexpected enum value"

By comparison, here is Visual Basic’s syntax for ranges within a case statement.

Function CaclRateByDate3(ByVal day As DayOfWeek) As Double
    Select Case day
        Case Monday To Friday : Return 0.42
        Case Saturday : Return 0.92
        Case Sunday : Return 0.18
        Case Else
            Throw New ArgumentOutOfRangeException("Unexpected enum value")
    End Select
End Function

As you can see, each language in on the .NET platform has certain syntactical strengths that could be applied to the other languages without changing the language’s core nature.

No comments

Watch Thread Reply

Educational Content

New-age Transactional Systems - Not Your Grandpa's OLTP

John Hugg discusses high volume transaction processing applications with high and low frequency profiles, and how VoltDB can be used for that purpose.

Cool Code

Kevlin Henney examines code samples to see what can be learned from them starting from the premise that one won’t write great code unless he knows how to read it.

Collaboration: At the Extremities of Extreme

Jason Ayers share the observations he made watching a team of developers collaborating in real time on the same code base, pushing XP, pair programming and continuous integration to their extremes.

Yesod Web Framework

Michael Snoyman presents Yesod, a web framework written in Haskell and containing a web server, templating, ORM, libraries (templating, gravatar, etc.).

Transactions without Transactions

Richard Kreuter and Kyle Banker on how to avoid classical RDBMS transactional systems by using compensation mechanisms, transactional messaging or transactional procedures.

Attila Szegedi on JVM and GC Performance Tuning at Twitter

Attila Szegedi talks about performance tuning Java and Scala programs at Twitter: how to approach GC problems, the importance of asynchronous I/O, when to use MySQL/Cassandra/Redis, and much more.

10 tips on how to prevent business value risk

One category of risk that project teams need to ensure they address is business value failure – delivering a product that fails to provide value for the business investor.

Interview: Software Systems Architecture: Working With Stakeholders Using Viewpoints and Perspectives

InfoQ spoke to the authors of Software Systems Architecture on a couple of new topics, the System Context viewpoint and Agile, which have been added to the second edition.