Phillip Trelford's Array

POKE 36879,255

Case for VB.Net vNext

Following up on the last Roslyn preview way back in 2012, this week saw the availability of a new preview with a more complete compiler along with a few new language features for C# and VB. A lot of inspiration for these features seems to have come from the F# language.

The C# interactive shell from 2012 appears to be missing, perhaps ScriptCS is expected to fill this space, or you could just use F# interactive which already exists in Visual Studio.

On the language features side, C# 6 gets primary constructors for classes, heavily inspired by F#, and using static which brings parity with Java and VB.Net.

For me VB.Net gets the most interesting new feature in the form of Select Case TypeOf. which provides the first steps towards pattern matching.

Shapes

Taking a hierarchy of shapes as an example:

Public MustInherit Class Shape
End Class

Public Class Rectangle
    Inherits Shape
    Public Property Width As Integer
    Public Property Height As Integer
End Class

Public Class Circle
    Inherits Shape
    Public Property Radius As Integer
End Class

Sub Main()
    Dim shape As Shape = New Rectangle With {.Width = 10, .Height = 10}
    Select Case shape
        Case r As Rectangle When r.Width = r.Height
            Console.WriteLine("Square of {0}", r.Width)
        Case r As Rectangle
            Console.WriteLine("Rectangle of {0},{1}", r.Width, r.Height)
        Case c As Circle
            Console.WriteLine("Circle of {0}", c.Radius)
    End Select
End Sub

The functionality is still quite limited and quite verbose in comparison to say F# or Scala, but I feel it’s definitely an interesting development for VB.Net.

For comparison here’s an equivalent F# version using discriminated unions:

type Shape =
    | Rectangle of width:int * height:int
    | Circle of radius:int

let shape = Rectangle(10,10)
match shape with
| Rectangle(w,h) when w=h -> printfn "Square %d" w
| Rectangle(w,h) -> printfn "Rectangle %d, %d" w h
| Circle(r) -> printfn "Circle %d" r

Eval

Pattern matching can be really useful when writing compilers, here’s a simple expression tree evaluator in F#:

type Expression =
   | Factor of value:int
   | Add of lhs:Expression * rhs:Expression

let rec eval e =
   match e with
   | Factor(x) -> x
   | Add(l,r) -> eval l + eval r

let onePlusOne = Add(Factor(1),Factor(1))

VB.Net vNext can approximate this, albeit in a rather more verbose way:

Public MustInherit Class Expression
End Class

Public Class Factor
    Inherits Expression
    Public Property Value As Integer
    Sub New(x As Integer)
        Value = x
    End Sub
End Class

Public Class Op
    Inherits Expression
    Public Property Lhs As Expression
    Public Property Rhs As Expression
End Class

Public Class Add
    Inherits Op
End Class

Function Eval(e As Expression) As Integer
    Select Case e
        Case x As Factor
            Return x.Value
        Case op As Add
            Return Eval(op.Lhs) + Eval(op.Rhs)
        Case Else
            Throw New InvalidOperationException
    End Select
End Function

Sub Main()
    Dim onePlusOne As Expression =
        New Add With {.Lhs = New Factor(1), .Rhs = New Factor(1)}
    Console.WriteLine(Eval(onePlusOne))
End Sub

Summary

It will be interesting to see how VB.Net vNext develops. I think first-class support for tuples could be an interesting next step for the language.

F# Eye for the VB Guy

Are you a VB developer curious about functional-first programming. F# is a statically typed language built into Visual Studio. It is a multi-paradigm language with both functional and object-oriented constructs.

F# has powerful type inference which reduces the amount of typing you need to do without reducing performance or correctness.

F# projects are easily referenced from VB and vice versa. Like VB, F# makes minimal use of curly braces, and for many operations the syntax will feel quite familiar.

Here’s my cut-out-and-keep guide to common operations in both languages:

Declaring values

VB.Net F#
' Fully qualified
Dim greeting As String = "Hello"
' Type inferred
Dim greeting = "Hello"
// Fully qualified 
let greeting : string = "Hello"
// Type inferred 
let greeting = "Hello"

 

Declaring functions

VB.Net F#
Sub Print(message As String)
  Console.WriteLine(message)
End Sub

Function Add _
  (a As Integer, b As Integer) _
  As Integer
  Return a + b
End Function
let print( message: string ) = 
  Console.WriteLine(message) 

// Return type is inferred
let add(a:int, b:int) = a + b

 

Loops

VB.Net F#
For i = 1 To 10
  Console.WriteLine("Hello")
Next

For Each c In "Hello"
  Console.WriteLine(c)
Next
for i = 1 to 10 do 
   Console.WriteLine("Hello") 


for c in "Hello" do 
  Console.WriteLine(c)

 

If/Then/Else

VB.Net F#
Dim ageGroup As String
If age < 18 Then
  ageGroup = "Junior"
Else
  ageGroup = "Senior"
End If
let ageGroup = 
  if age < 18 then  
    "Junior"
  else  
    "Senior"
 

 

Pattern Matching

VB.Net F#
' Score Scrabble letter
Select Case
c Case "A", "E", "I", "L", "N", _ "O", "R", "S", "T", "U" Return 1 Case "D", "G" Return 2 Case "B", "C", "M", "P" Return 3 Case "F", "H", "V", "W", "Y" Return 4 Case "K" Return 5 Case "J", "X" Return 8 Case "Q", "Z" Return 10 Case Else Throw New _
      InvalidOperationException()
  End Select
// Score scrabble letter
match letter with
| 'A' | 'E' | 'I' | 'L' | 'N' 
| 'O' | 'R' | 'S' | 'T' | 'U' -> 1
| 'D' | 'G' -> 2
| 'B' | 'C' | 'M' | 'P' -> 3
| 'F' | 'H' | 'V' | 'W' | 'Y' -> 4
| 'K' -> 5
| 'J' | 'X' -> 8
| 'Q' | 'Z' -> 10
| _ -> invalidOp ""

 

Try/Catch

VB.Net F#
Dim i As Integer = 5
Try
  Throw New ArgumentException()
Catch e As OverflowException _
      When i = 5
  Console.WriteLine("First handler")
Catch e As ArgumentException _
      When i = 4
  Console.WriteLine("Second handler")
Catch When i = 5
  Console.WriteLine("Third handler")
End Try
let i = 5
try
  raise (ArgumentException())
with
| :? OverflowException when i = 5 ->
  Console.WriteLine("First handler")
| :? ArgumentException when i = 4 ->
  Console.WriteLine("Second handler")
| _ when i = 5 ->
  Console.WriteLine("Third handler")

 

Modules

VB.Net F#
Module Math
  ' Raise to integer power
  Function Pown( _
    x As Double, y As Integer)
    Dim result = 1
    For i = 1 To y
      result = result * x
    Next
    Return result
  End Function
End Module
module Maths =
  // Raise to integer power
 let pown (x:float,y:int) =
   let mutable result = 1.0
   for i = 1 to y do
     result <- result * x
   result

 

Classes

VB.Net F#
' Immutable class
Public Class Person
  Private ReadOnly myName As String

  Public Sub New(name As String)
    myName = name
  End Sub

  ReadOnly Property Name() As String
    Get
      Return myName
    End Get
  End Property
End Class

' Inheritance
Public Class MyWindow _
  : Inherits Window
End Class
// Immutable class
type Person (name : string) = 
  member my.Name = name

// Inheritance
type MyWindow() =
   inherit Window()

 

Summary

Interested in learning more? Give F# a try in Visual Studio with the built-in F# Tutorial project or in your browser with http://tryfsharp.org