Monday, February 2, 2009

F# – User Interface

F# can access .NET assemblies, so Windows Forms is the UI library for F#. The following code reads microsoft.com and displays the HTML code in a TextBox.

#light
open System.Windows.Forms
open System.IO
open System.Net

let form = new Form(Visible=false,Text="Hello F#")

let result = new TextBox(Multiline=true,Dock=DockStyle.Fill, Text="")
form.Controls.Add(result)

let getHtml (url: string) =
    let req = System.Net.WebRequest.Create(url)
    let resp = req.GetResponse()
    printfn "Connected"
    let stream = resp.GetResponseStream()
    let reader = new StreamReader(stream)
    let html = reader.ReadToEnd()
    printfn "Response read"
    resp.Close()
    html
    
printfn "Connecting..."
let microsoft = getHtml("http://www.microsoft.com")
result.Text <- microsoft

form.Visible <- true
Application.Run(form)
Connecting...
Connected
Response read

As you can see, Windows Forms knowledge is a requirement for F# UI development. Personally I don’t think UI elements should be developed in F#, C# has much better IDE designer support so far (F# don’t have designers).

F# – Sequential code

F# can handle sequential code. Expressions evaluated sequentially. Just the last result will be kept, other results will be dismissed to prevent side effects.

#light
let a = (2+3;5+7;4+4)
printfn "a= %d" a
let b = (a+2;a+5)
printfn "b= %d" b
a= 8
b= 13

It can be useful when we are doing complicated computations or initializations and we want to indicate the progress:

printf "Processing"
let c = (printf ".."; 2; printfn ".."; 3)
printfn "c= %d" c
Processing....
c= 3

F# – Typed tuples

F# is a typed language. I create 2 tuples containing site URLs and relevancies. I create a tuple from the tuples above. I execute a pattern matching on site1 tuple, splitting it up to a string and an integer variables. Finally I print the content of the url and relevance variable to the console.

#light
let site1 = ("www.microsoft.com",10)
let site2 = ("www.bbc.com",9)
let sites = (site1, site2)
let url,relevance = site1

printfn "site: %s" url
printfn "relevance: %d" relevance
site: www.microsoft.com
relevance: 10

Let’s test type safety:

let url = url +2

> let url = url + 2;;

  let url = url + 2;;
  ----------------^^

stdin(34,17): error FS0001: The type 'int' does not match the type 'string'.
>

This error message means that integer cannot be converted to string.

Tuples can be used effectively in functions:

let increase (a,b) =
    (a+1,b+1)

let printIncreased (a,b) =
    let (a,b) = increase (a,b)
    printfn "a: %d" a
    printfn "b: %d" b
    
printIncreased (5,6)
a: 6
b: 7

Finally a tuple with 4 elements:

let quad = ("Doe", "John", 23, "New York")
let last,first,age,location = quad
System.Console.WriteLine("Last name: {0}\nFirst name: {1}\nAge: {2}\nLocation: {3}", last, first, age, location)
Last name: Doe
First name: John
Age: 23
Location: New York

Sunday, February 1, 2009

F# - Hello World

A simple Hello World code in F#:

#light
let HelloWorld =
    printfn "Hello World"

HelloWorld

It is the IL code for the F# code above:

Code to execute in IL:

  1: .class private abstract auto ansi sealed beforefieldinit $Program
  2:     extends [mscorlib]System.Object
  3: {
  4:     .method public static void _main() cil managed
  5:     {
  6:         .entrypoint
  7:         .maxstack 3
  8:         L_0000: nop 
  9:         L_0001: ldstr "Hello World"
 10:         L_0006: newobj instance void [FSharp.Core]Microsoft.FSharp.Text.Format`5<class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>::.ctor(string)
 11:         L_000b: call !!0 [FSharp.Core]Microsoft.FSharp.Core.Pervasives::printfn<class [FSharp.Core]Microsoft.FSharp.Core.Unit>(class [FSharp.Core]Microsoft.FSharp.Text.Format`4<!!0, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>)
 12:         L_0010: stsfld class [FSharp.Core]Microsoft.FSharp.Core.Unit <StartupCode$ConsoleApplication1>.$Program::HelloWorld@19
 13:         L_0015: call class [FSharp.Core]Microsoft.FSharp.Core.Unit Program::get_HelloWorld()
 14:         L_001a: pop 
 15:         L_001b: ret 
 16:     }
 17: 
 18: 
 19:     .field assembly static class [FSharp.Core]Microsoft.FSharp.Core.Unit HelloWorld@19
 20: 
 21: }
 22: 
 23: 

The same code in C#:

  1: internal static class $Program
  2: {
  3:     // Fields
  4:     internal static Unit HelloWorld@19;
  5: 
  6:     // Methods
  7:     public static void _main()
  8:     {
  9:         HelloWorld@19 = Pervasives.printfn<Unit>(new Format<Unit, TextWriter, Unit, Unit, Unit>("Hello World"));
 10:         Program.get_HelloWorld();
 11:     }
 12: }
 13: 
 14: 

Something similar in C#:

  1: class Program
  2: {
  3:     static void Main(string[] args)
  4:     {
  5:         Console.WriteLine("Hello World");
  6:     }
  7: }

It is the IL code for the C# code above:

  1: .class private auto ansi beforefieldinit Program
  2:     extends [mscorlib]System.Object
  3: {
  4:     .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
  5:     {
  6:         .maxstack 8
  7:         L_0000: ldarg.0 
  8:         L_0001: call instance void [mscorlib]System.Object::.ctor()
  9:         L_0006: ret 
 10:     }
 11: 
 12:     .method private hidebysig static void Main(string[] args) cil managed
 13:     {
 14:         .entrypoint
 15:         .maxstack 8
 16:         L_0000: nop 
 17:         L_0001: ldstr "Hello World"
 18:         L_0006: call void [mscorlib]System.Console::WriteLine(string)
 19:         L_000b: nop 
 20:         L_000c: ret 
 21:     }
 22: 
 23: }
 24: 
 25: 

Early and Late Binding

There are numerous definitions for early and late binding. Some are technical, some are theoretical. I will try to define it from both viewpoints.

Variables and expressions can be assigned at compile time or at runtime. Compile time (declaration time) assignment is called:

  • early binding
  • static binding
  • static typing

An example for early binding:

  1: '  Create a variable to hold a new object.
  2: Dim FS As System.IO.FileStream
  3: ' Assign a new object to the variable.
  4: FS = New System.IO.FileStream("C:\tmp.txt", _
  5:     System.IO.FileMode.Open)

Runtime assignment is called dynamic binding or late binding, when the type of the variable or expression is determined by the current (application) conditions. An example for late binding:

  1: ' To use this example, you must have Microsoft Excel installed on your computer.
  2: ' Compile with Option Strict Off to allow late binding.
  3: Sub TestLateBinding()
  4:     Dim xlApp As Object
  5:     Dim xlBook As Object
  6:     Dim xlSheet As Object
  7:     xlApp = CreateObject("Excel.Application")
  8:     ' Late bind an instance of an Excel workbook.
  9:     xlBook = xlApp.Workbooks.Add
 10:     ' Late bind an instance of an Excel worksheet.
 11:     xlSheet = xlBook.Worksheets(1)
 12:     xlSheet.Activate()
 13:     ' Show the application.
 14:     xlSheet.Application.Visible = True
 15:     ' Place some text in the second row of the sheet.
 16:     xlSheet.Cells(2, 2) = "This is column B row 2"
 17: End Sub

Another example for late binding:

  1: Dim MyVariable As Object
  2: MyVariable = "About Visual Basic"
  3: Debug.WriteLine("The variable data type is: " & MyVariable.GetType.ToString)
  4: MyVariable = #6/30/2006#
  5: Debug.WriteLine("The variable data type is: " & MyVariable.GetType.ToString)

The result for the code above:

The variable data type is: System.String
The variable data type is: System.DateTime

As you can see, the variable named MyVariable can represent a System.String and a System.Date in the code above.

Despite of the advantages of late binding, early binding is recommended:

  • Early binding code can be optimized better by the compiler, so it runs (much) faster
  • It is usually easier to read early binding code (known types, etc.)
  • Automatic code completion, Dynamic Help and other advanced IDE features are available only for early binding codes
  • Compiler can type 'compatibility' for early binding variables and expressions
  • Application constants are accessible (e.g. in MS Word)

Some advantages of late binding:

  • Version independence. E.g. in case of MS Word, programming against Word 97 and changing code libraries to Word 2000 can be smooth and automatic.
  • More references can mean more linking and bigger file size (in case of unmanaged code)

There are numerous methods in C# to use late binding. Most of them employs reflection and dynamic compilation. There will be late binding as a language feature from C# 4.0 specification. Late binding will be as simple as the following:

  1: dynamic d = GetDynamicObject();
  2: d.Foo();
Late binding will be achieved by the dynamic keyword.