• RSS
  • Facebook
  • Twitter

Nunc rutrum nunc in enim bibendum at pellentesque est pellentesque. Pellentesque sodales bibendum elit non pulvinar. Mauris fermentum lectus ac risus dapibus cursus eu non ipsum.

  • Example Title 1

    Replace this sample description with your own description. A free premium template by NewBloggerThemes.com.

  • Example Title 2

    Replace this sample description with your own description. A free premium template by NewBloggerThemes.com.

  • Example Title 3

    Replace this sample description with your own description. A free premium template by NewBloggerThemes.com.

    Friday, January 16, 2009

    Object Types

    Object oriented constructs in F# are compatible with the OO support in .NET CLR, which implies that F# supports single implementation inheritance (a class can have one base class), multiple interface inheritance (a class can implement several interfaces and an interface can inherit from multiple interfaces), subtyping (an inherited class can be casted to the base class type) and dynamic type tests (it is possible to test whether a value is a value of an inherited class casted to a base type). Finally, all object types share a common base class which is called obj in F# and is an alias to the CLR type System.Object.
    F# object types can have fields, constructors, methods and properties (a property is just a syntactic sugar for getter and setter methods). The following example introduces the F# syntax for object types:

    type MyCell(n:int) =
    let mutable data = n + 1
    do printf "Creating MyCell(%d)" n

    member x.Data
    with get() = data
    and set(v) = data <- v

    member x.Print() =
    printf "Data: %d" data
    override x.ToString() =
    sprintf "(Data: %d)" data

    static member FromInt(n) =
    MyCell(n)


    Type MyCell has a mutable field called data, a property called Data, an instance method Print, a static method FromInt and the type also contains one overridden method called ToString, which is inherited from the obj type and returns a string representation of the object. Finally, the type has an implicit constructor. Implicit constructors are syntactical feature which allows us to place the constructor code directly inside the type declaration and to write the constructor arguments as part of the type construct. In our example, the constructor initializes the mutable field and prints a string as a side effect. F# also supports explicit constructors that have similar syntax as other members, but these are needed rarely.
    In the previous example we implemented a concrete object type (a class), which means that it is possible to create an instance of the type and call its methods in the code. In the next example we will look at declaration of an interface (called abstract object type in F#). As you can see, it is similar to the declaration of a class:

    type AnyCell =
    abstract Value : int with get, set
    abstract Print : unit -> unit

    The interesting concept in the F# object oriented support is that it is not needed to explicitly specify whether the object type is abstract (interface), concrete (class) or partially implemented (class with abstract methods), because the F# complier infers this automatically depending on the members of the type. Abstract object types (interfaces) can be implemented by a concrete object type (class) or by an object expression, which will be discussed shortly. When implementing an interface in an object type we use the interface .. with construct and define the members required by the interface. Note that the indentation is significant in the lightweight F# syntax, meaning that the members implementing the interface type have to be indented further:

    type ImplementCell(n:int) =
    let mutable data = n + 1
    interface AnyCell with
    member x.Print() = printf "Data: %d" data
    member x.Value
    with get() = data
    and set(v) = data <- v

    The type casts supported by F# are upcast, used for casting an object to a base type or to an implemented interface type (written as o :> TargetType), downcast, used for casting back from a base type (written as o :?> TargetType), which throws an exception when the value isn’t a value of the specified type and finally, a dynamic type test (written as o :? TargetType), which tests whether a value can be casted to a specified type.


    Object expressions

    As already mentioned, abstract types can be also implemented by an object expression. This allows us to implement an abstract type without creating a concrete type and it is particularly useful when you need to return an implementation of a certain interface from afunction or build an implementation on the fly using functions already defined somewhere else in your program. The following example implements the AnyCell type:

    > let newCell n =
    let data = ref n
    { new AnyCell with
    member x.Print() = printf "Data: %d" (!data)
    member x.Value
    with get() = !data
    and set(v) = data:=v };;
    val newCell : int -> AnyCell

    In this code we created a function that takes an initial value as an argument and returns a cell holding this value. In this example we use one more type of mutable values available in F#, called reference cell, which are similar to a mutable values, but more flexible (the F# compiler doesn’t allow using an ordinary mutable value in this example). A mutable cell is created by a ref function taking an initial value. The value is accessed using a prefix ! operator and can be modified using := operator. When implementing the abstract type, we use a new ... with construct with members implementing the functionality required by the abstract type (an object expression can’t add any members). In this example we need a reference cell to hold the value, so the cell is declared in a function and captured in a closure, which means that it will exist until the returned object will be garbage collected.
    The .NET BCL is built in an object oriented way, so the ability to work with existing classes is essential for the interoperability. Many (in fact almost all) of the classes are also mutable, so the eager evaluation and the support for side-effects are two key features when working with any .NET library. The following example demonstrates working with the mutable generic ResizeArray type from the BCL (ResizeArray is an alias for a type System.Collections. Generic.List to avoid a confusion with the F# list type):

    > let list = new ResizeArray<_>()
    list.Add("hello")
    list.Add("world")
    Seq.to_list list;;
    val it : string list = ["hello"; "world"]

    As you can see, we used the underscore symbol when creating an instance of the generic type, because the type inference algorithm in F# can deduce the type argument from the code (in this example it infers that the type argument is string, because the Add method is called with a string as an argument). After creating an instance we used Add method to modify the list and add two new items. Finally, we used a Seq.to_list function to convert the collection to the F# list. As a fully compatible .NET language, F# also provides a way for declaring its own classes (called object types in F#), which are compiled into CLR classes or interfaces and therefore the types can be accessed from any other .NET language as well as used to extend classes written in other .NET languages. This is an important feature that allows accessing complex .NET libraries like Windows Forms or ASP.NET from F#.
    Similarly as ML and OCaml, F# adopts an eager evaluation mechanism, which means that a code written using sequencing operator is executed in the same order in which it is written and expressions given as an arguments to a function are evaluated before calling the function (this mechanism is used in most imperative languages including C#, Java or Python). This makes it semantically reasonable to support imperative programming features in a functional language. As already mentioned, the F# value bindings are by default immutable, so to make a variable mutable the mutable keyword has to be used. Additionally F# supports a few imperative language constructs (like for and while), which are expressions of type unit:


    > // Imperative factorial calculation
    let n = 10
    let mutable res = 1
    for n = 2 to n do
    res <- res * n
    // Return the result
    res;;
    val it : int = 3628800


    The use of the eager evaluation and the ability to use mutable values makes it very easy to interoperate with other .NET languages (that rely on the use of mutable state), which is an important aspect of the F# language. In addition it is also possible to use the mutable keyword for creating a record type with a mutable field.

    Arrays

    As mentioned earlier, another type of value that can be mutated is .NET array. Arrays can be either created using [| .. |] expressions (in the following example we use it together with a range expression, which initializes an array with a range) or using functions from the Array module, for example Array.create. Similarly to the mutable variables introduced in the previous section, the value of an array element can be modified using the <- operator:

    > let arr = [| 1 .. 10 |]
    val arr : array
    > for i = 0 to 9 do
    arr.[i] <- 11 - arr.[i]
    (...)
    > arr;;
    val it : array = [| 10; 9; 8; 7; 6; 5; 4; 3; 2; 1 |]
    The F# language doesn’t have a different notion of a statement and an expression, which means that every language construct is an expression with a known return type. If the construct performs only a side effect (for example printing to a screen or modifying a global mutable variable or a state of .NET object) and doesn’t return any value then the type of the construct is unit, which is a type with only one possible value (written as “()”). The semicolon symbol (;) is used for sequencing multiple expressions, but the first expression in the sequence should have a unit as a result type. The following example demonstrates how the if construct can be used as an expression in F# (though in the optional F# lightweight syntax, which makes whitespace significant and which we used in the rest of this overview, the semicolon symbol can be omitted):


    > let n = 1
    let res =
    if n = 1 then
    printfn "..n is one..";
    "one"
    else
    "something else";;
    ..n is one..
    val res : string = "one"

    When this code executes it calls the true branch of the if expression, which first calls a side-effecting function, which prints a string and then returns a string ("one") as the result. The result is then assigned to the res value.
    Unlike some languages that allow one variable name to appear only once in the entire function body (e.g. C#) or even treat all variables declared inside the body of a function as a variable with scope of the whole function (e.g. Visual Basic or JavaScript), the scope of F# values is determined by the let binding and it is allowed to hide a value by declaring a value with the same name. The following (slightly esoteric) example demonstrates this:


    > let n = 21
    let f =
    if n < n =" n"> print_int n)
    else
    let n = n / 2
    (fun () -> print_int n)
    let n = 0
    f ();;
    42
    val it : unit


    In this example, the value n declared inside a branch of the if expression is captured by a function created using the fun keyword, which is returned from the if expression and bound to the value named f. When the f is invoked it indeed uses the value from the scope where it was created, which is 42. In languages, where the variable named n would refer to a value stored globally, it would be rather problematic to write a code like this. Of course, writing a code similar to what I demonstrated in this example isn't a good idea, because it makes the code very difficult to read. There are however situations where hiding a value that is no longer needed in the code is practical.
    One of the most interesting aspects of working with functions in functional programming languages is the possibility to use function composition operator. This means that you can very simply build a function that takes an argument, invokes a first function with this argument and passes the result to a second function. For example, you can compose a function fst, which takes a tuple (containing two elements) and returns the first element in the tuple with a function uppercase, which takes a string and returns it in an uppercase:


    > (fst >> String.uppercase) ("Hello world", 123);;
    val it : string = "HELLO WORLD"
    > let data = [ ("Jim", 1); ("John", 2); ("Jane", 3) ];;
    val data : (string * int) list
    > data |> List.map (fst >> String.uppercase);;
    val it : string list = ["JIM"; "JOHN"; "JANE"]


    In the first command, we just compose the functions and call the returned function with a tuple as an argument, however the real advantage of this trick becomes more obvious in the third command, where we use the function composition operator (>>) to build a function that is given as an argument to a map function that we used earlier. The function composition allows us to build a function without explicitly using a lambda function (written using the fun keyword) and when this features are used reasonably it makes the code more compact and keeps it very readable.