Inside F#

Brian's thoughts on F# and .NET

Archive for February, 2009

The basic syntax of F# – classes, interfaces, and members

Posted by Brian on February 13, 2009

This entry is part of "The Basic Syntax of F#" series:

Today’s blog entry covers the F# syntax for authoring classes, interfaces, and members.  Together with the previous blog entry, this probably covers the most common 90% or so of the language.  Again today I will intentionally err on the side of simplicity, at the expense of total accuracy.

Defining F# types

There are lots of ways to define new types and type names in F#, and most involve declarations with the "type" keyword.  Today I’ll focus on just classes and interfaces; in a future blog entry I’ll describe the syntax for the rest of the kinds of types (records, discriminated unions, enums, type abbreviations, units of measure, structs, delegates, exceptions, and modules).

Classes (sans interfaces or inheritance)

Here is an example skeleton class definition whose only purpose is to demonstrate most of the language syntax involved in defining classes:

type public (*1*) MyClass<‘a> public (*2*) (x, y) (*3*) as this (*4*) =
    static let PI = 3.14
    static do printfn "static constructor"
    let mutable z = x + y
    do  printfn "%s" (this.ToString()) (*5*)
        printfn "more constructor effects"        
    internal new (a) = MyClass(a,a)
    static member StaticProp = PI
    static member StaticMethod a = a + 1
    member internal self.Prop1 = x
    member self.Prop2 with get() = z
                      and set(a) = z <- a
    member self.Method(a,b) = x + y + z + a + b

I’ll discuss each part in turn; the commented numbers are to help call out specific bits in the prose that follows.

A class definition usually starts like this:

type SomeClass(constructor-args) = ...

but there are lots of optional bits that can go before the ‘=’ when defining a class.  Back in the main example,

type public (*1*) MyClass<‘a> public (*2*) (x, y) (*3*) as this (*4*) =

the ‘public’ before (*1*) is the accessibility of the class type itself; new types default to being public.  After the name of the class, if the class is generic, you specify the generic parameters in angle brackets (MyClass<‘a> is a class with one generic parameter; the generic parameter is unused in this example, it just demonstrates the syntax).  The next portion defines the so-called "implicit constructor" (whose meaning is described in more detail below).  The ‘public’ before (*2*) is the accessibility of the implicit constructor (public is the default) and the stuff inside parentheses before (*3*) are the arguments to the implicit constructor.  The "as this" before (*4*) is an optional way to name the current object (you can use any identifier you like, it is lexically scoped to all non-static portions of the class body); the only time you need it is when referring to "this" inside the implicit constructor body (such as on the line marked (*5*) in the main example).

The body of the class conceptually has two portions, ‘let’s and ‘do’s (which run as part of construction), and ‘member’s.  Both portions can have ‘static’ and instance (non-static) parts; non-static is the default.  Names bound by ‘let’s are lexically scoped in the class body (and thus are always "private" to the class).  The non-static ‘let’s and ‘do’s run as the body of the implicit constructor (.ctor), the static ‘let’s and ‘do’s comprise the type’s static constructor (.cctor).  In other words, this code

    static let PI = 3.14 
    static do printfn "static constructor"

runs when something first refers to the enclosing MyClass type, and this code

    let mutable z = x + y
    do  printfn "%s" (this.ToString()) (*5*) 
        printfn "more constructor effects"

runs whenever you create an instance of MyClass.  (As with other .NET languages, it is rare to define a static constructor.)

Members are the public interface to functionality in a class, and come in two main flavors: properties and methods.  Members without arguments are "getter" properties; members with arguments are methods.  From the example:

    static member StaticProp = PI 
    static member StaticMethod a = a + 1 
    member internal self.Prop1 = x 
    member self.Prop2 with get() = z 
                      and set(a) = z <-
    member self.Method(a,b) = x + y + z + a + b

Members can be static or not (non-static is the default).  Non-static (instance) members must declare a self-identifier.  Just as with the optional "as this" from the class declaration, you can use any identifier you like; the identifier is bound to the current object and scoped to the member’s body (in these examples I chose "self").  Members default to being public (though "Prop1" demonstrates that you can add an optional accessibility specifier).  If you want to define a property with a "setter" as well as a "getter", you can use the syntax as in "Prop2". 

To define constructors overloads other than the implicit constructor, use a syntax like this:

    internal new (a) = MyClass(a,a) 

The accessibility specifier is optional (defaults to public, just like other members).  The "body" of the constructor must "call forward" to another constructor (eventually ending up with a call to the implicit constructor).  Pragmatically, this means your implicit constructor must initialize everything, and thus probably takes the most arguments of any constructor overload.

There are a number of features of members I am omitting for simplicity, including named and optional parameters, overloading, events, and fields.  You can read the language spec for more details on these features, or ask questions as a blog comment.

Interfaces

Defining and using interfaces in F# is very straightforward.  An interface is a type that only defines abstract members and/or inherits other interfaces.  Here are a couple examples:

type IFooable =
    abstract member Foo : int -> int

type IQuxable =
    abstract member Qux : unit -> string
    inherit IFooable

"IFooable" is an interface with a method "Foo" that takes an int and returns an int.  "IQuxable" is an interface that inherits "IFooable" and adds another method named "Qux".

To have a class implement an interface, just add an ‘interface…with’ declaration to the end of the class body for each interface you want to implement:

type FooQux() =
    member this.SomeMethod() = printfn "hi"
    interface IQuxable with
        member this.Foo x = x + 1
        member this.Qux() = "qux!"

Here "FooQux" is a class containing a method "SomeMethod" and implementing the "IQuxable" interface.

Note that in F#, when a class implements an interface, the interface implementation is always explicit, which means you need an explicit upcast to call interface methods.  For example

let fooQux = new FooQux()
fooQux.SomeMethod()
let x = (fooQux :> IFooable).Foo 42  // must upcast to call "Foo"

Abstract classes and "virtual" methods

Here is an example of an abstract class:

[<AbstractClass>]
type SomeBase() =
    member this.ConcreteMethod y = y + 1
    abstract member AbstractMethod : int -> int
    abstract member VirtualMethod : int -> int
    default this.VirtualMethod x = x + 1

An abstract class is like a (normal, concrete) class, except it contains some abstract (not implemented) members that a subclass must implement.  What would be a "virtual" method in C# is expressed as an ‘abstract’ method that has a ‘default’ implementation.  An abstract class type must be marked with the "AbstractClass" attribute.

Inheritance

With inheritance come three more F# keywords: ‘inherit’, ‘override’, and ‘base':

type SomeDerived() =
    inherit SomeBase()
    override this.AbstractMethod z = z + 1
    override this.VirtualMethod x =
        1 + base.VirtualMethod x
    member this.OtherMethod() = ()

The ‘inherit’ clause defines the base class of a class, and also calls the base constructor as part of the implicit constructor.  (That is, in this example the zero-argument implicit constructor of "SomeDerived" calls the zero-argument constructor of "SomeBase".)  Abstract members that have no implementation must be overridden by the derived class (or else the derived class can also be marked abstract).  Abstract methods with default implementations can be overridden; to call the inherited method, use the ‘base’ keyword.

Other miscellany

I have intentionally omitted many details to keep this blog entry reasonably short (but still cover all the major common bits of syntax).  Here are a few notable omissions:

  • You can enclose a class body between the tokens ‘class’ and ‘end’.  You can enclose an interface body between the tokens ‘interface’ and ‘end’.  F# normally infers the kind of type being defined, making these tokens unnecessary/redundant.
  • As usual, whitespace matters; though I showed most method/property bodies on a single line of code, more commonly you will have a newline after the ‘=’ and indent the body underneath the declaration, as with "VirtualMethod" in "SomeDerived".
  • I only talked about accessibility (e.g. ‘public’, ‘internal’) and properties (rather than methods) in the first section; you can hopefully extrapolate how to define e.g. an internal virtual property.

Posted in Uncategorized | 10 Comments »

The basic syntax of F# – keywords and constructs

Posted by Brian on February 8, 2009

This entry is part of "The Basic Syntax of F#" series:

I have written lots of blog entries about F#, but I haven’t yet described the basic syntax of the language!  So today I’ll try to remedy that, describing about a dozen keywords/syntactic-forms that you will most commonly encounter when reading F# code.  This blog entry won’t cover all the syntax, but it covers perhaps the most common 75% or so.  Today I will also intentionally err on the side of simplicity, at the expense of total accuracy.

#light

Some F# files start with

#light

and this just explicitly enables the ‘lightweight syntax’ option.  I won’t talk about the alternative to the lightweight syntax; everyone always uses this option, and it became the default a while ago, which means you can safely remove the explicit "#light" declaration from the tops of your files.

Comments

There are two kinds of comments in F#, seen here:

// a one-line comment
(* a multi-line
   comment (* these can nest *)
 *)

"open" a namespace

The "open" keyword is used to open a namespace or module.

// must fully qualify the name System.Console
System.Console.WriteLine("Hello, world!")
// after opening the namespace, don’t need to
open System
Console.WriteLine("Hello, world!")

"let" defines functions and values

The ‘let’ keyword is used to define both functions and values.  Here are examples of using ‘let’ to define values:

let x = 42             // immutable, x is always 42
let mutable y = 0      // mutable, can re-assign y’s value with <- operator
let z : string = null  // ": string" is type annotation to declare type

You rarely need type annotations (F# is a type-inferred language), but the last example is one case where a type annotation might be necessary.  (Without the annotation, ‘z’ would be inferred to have type "obj" (System.Object); the annotation says we want ‘z’ to have type "string".)

Here are examples of using ‘let’ to define functions:

let F x = x + 1
let G x y = x + y
let G2 (x:float) (y:float) : float = x + y
let H(x,y) = x + y
let rec Kaboom x = Kaboom (x+1)

"F" is a one-argument function. "G" and "G2" take two curried arguments (the latter specifies type annotations for the argument types and the result types of the function, to demonstrate the syntax), whereas "H" takes tupled parameters; to find out more on tuples and currying, you definitely want to read this blog entry.  The ‘let rec’ keyword lets you define a recursive function.

The lightweight syntax makes whitespace/indentation significant, and indentation is the normal way to scope function bodies (and many other constructs).  Also, functions can be defined at any scope.  This code exemplifies all that:

let Area diameter = // define a function
    // everything indented under here is the body of "Area"
    let pi = 3.14   // define a value inside the function
    let Radius d =  // define another function inside here
        // this is the body of the "Radius" function
        d / 2.0
    let r = Radius diameter
    pi * r * r
// use the function
let answer = Area 5.0

Lambdas are "fun"

The "fun" keyword is used to define a lambda (anonymous function).  The syntax is "fun args -> body", and the precedence rules usually force you to enclose the whole thing in parentheses.  Here’s an example:

let nums = [1; 2; 3; 4; 5]
let odds = List.filter (fun x -> x%2 = 1) nums
printfn "odds = %A" odds // odds = [1; 3; 5]

In the example, note that ‘%’ is the modulus operator, used here to determine if a number ‘x’ is odd, and List.filter is a function that applies a predicate (a function returning a bool) to a list, and returns a new list containing only the elements for which the predicate is true.

Pipe data with |>

One built-in operator is used very commonly: pipe.  "x |> f" just means "f x".  Thus the previous example would be written more idiomatically as

let nums = [1; 2; 3; 4; 5]
let odds = nums |> List.filter (fun x -> x%2 = 1)
printfn "odds = %A" odds // odds = [1; 3; 5]

There is no real benefit to using the pipeline operator in this tiny example, but this operator is often used to "stream" data through a series of transformative functions.  See this blog entry for details.

Pattern-matching with "match"

Pattern matching is a very powerful language feature that can be used in a variety of contexts, but it is most commonly used in a "match" expression:

match expr with
| pat_1 -> body_1
...
| pat_n -> body_n

The expression is tested against each pattern, and the first one that matches causes the corresponding body to be evaluated.  The most common patterns you’ll see involve simple algebraic data types such as discriminated unions, especially matching on a "list" or an "option"; check out the first half of this blog entry for a description of discriminated unions and how to use pattern matching on them.  (I probably will eventually write at least two full blog entries on pattern matching, but the paragraph above and the linked blog entry are enough for you to ‘get by’ as you are trying to pick up the language.)

Conditionals and loops

F# has if-then-else, while loops, and for loops, though you use them less frequently than in other languages (typically you use pattern-matching and recursion instead).  And since F# is a functional language, these are all expressions that return values.

The syntax for if-then-else has the general form

if cond1 then 
    expr1
elif cond2 then 
    expr2
else 
    expr3

The ‘elif’ and ‘else’ parts are optional, and you can have as many ‘elif’ (else if) parts as you like.  All the exprn must have the same type, and this is the type of the resulting whole expression.  If the ‘else’ is omitted, the exprn must have type "unit" (which is akin to "void").

The syntax for while is

while cond do
    expr

and the whole while expression always returns "unit".  There is nothing like "break" or "continue" in F#.

There are a variety of for-loop syntactic forms, but the most common one is

for pat in expr do
    bodyexpr

Here, expr is something you can enumerate (e.g. an IEnumerable<T>, known in F# as a seq<‘a>), pat is any pattern (but most commonly just a new identifier name), and the bodyexpr runs for each element in the enumerated sequence.  So for example

for x in someArray do
    printfn "%d" x

prints all the integers in "someArray".  Like ‘while’ the whole ‘for’ expression returns "unit".

Constructing objects with "new"

You can use ‘new’ to construct objects just as in C#:

let x = new System.Uri("http://hello.world/&quot;)

though in F# the ‘new’ keyword is often optional.

Literals

There are lots of literal forms in the language, but the most common are shown here:

let b : bool = true                     // or false
let i : int = 42
let s : string = "hi"
let
x : float = 3.14                    // "3." same as "3.0"
let ai : int array = [| 1; 2; 3 |]      // "int array"=="array<int>"
let lf : float list = [ 1.1; 2.2; 3.3 ] // "float list"=="list<float>"

(None of the type annotations are necessary, but they aid my exposition.)  Boolean, integer, and string literals work just as you expect.  The "float" type corresponds to System.Double and is the type of numerical literals containing a decimal point.  Array literals are written with [|these brackets|] whereas list literals are written with [these brackets]; both have elements delimited by semicolons (or newlines).  These just demo the most common types; I’ll talk more about all the built-in F# types in a future blog entry.

Exception constructs

F# has constructs like "try-catch-finally" and "using" (IDisposable) from C#.  The basic syntaxes are

try
    expr
with
    | pat_i -> body_i    

try
    expr
finally
    cleanup

use ident = expr

You can read a little more about these in this blog entry.

What’s left?

This brief intro probably covers 95% of common syntactic forms of the language, apart from types (defining new types, classes, members, etc.; as well as describing less-common builtin types) and pervasives (builtin operators and functions), both of which I intend to cover in future blog entries.

Posted in Uncategorized | 6 Comments »

Where did Brian go?

Posted by Brian on February 5, 2009

After three or four months of blogging about once per week, all of a sudden I disappeared for more than 9 weeks.  What gives?

As you may have guessed, in addition to being away for the holidays, I’ve been busy working on integrating F# into Visual Studio 2010 (and at the same time, improving F# atop VS 2008, since we will continue to ship out-of-band releases of F# before VS 2010 ships).  It’s been good to be focused at work, but I’ve been feeling very guilty about not blogging, so I decided to post a ‘softball’ entry today, in the hopes of gaining some blog-momentum back.  What’s today’s topic?  Why it’s lambdacats of course!

Lambdacats are like LOLcats except that they use obscure functional programming humor.  (Thanks to Matt for pointing them out to me.)  A typical example that’s right up my alley is

catamorphism

which plays off the facts that catamorphisms are sometimes written using (|banana-clips|) syntax.  Trust me, it’s very funny.  :)

I have a number of ideas for future blog posts… it’s just about making the time to actually write them.  For example, a couple months ago, after seeing this site, I had to try my hand at a similar problem, yielding results like these

TriBri1 TriBri2

Those of you on StackOverflow may recognize that as my gravatar; indeed that’s what I was using for test cases to tweak my algorithm:

TriSO1 TriSO2

Fun!  So of course I want to blog about that (about 300 lines of F#).

I also would like to finish off this series describing the relationship between C# and F# code.

I’d also like to write about modules, namespaces, and programming at the F# top-level, to help answer questions like these.

What would you like to see?

Still alive,

Brian

Posted in Uncategorized | 4 Comments »

 
Follow

Get every new post delivered to your Inbox.

Join 30 other followers