Inside F#

Brian's thoughts on F# and .NET

Using multiple F# source files, and a useful debugging technique

Posted by Brian on September 6, 2008

In some prior blog entries, I highlighted some features of the project system that enable you to use and organize multiple files as well as multiple projects within your solution.  In my next blog entries, I want to continue showing you some more features along these lines, but now with more of an eye towards pragmatics, including some advice on how to choose among different ways to organize your code.

Multiple files in F#, and the implicit module

Suppose I have a tiny F# source code file like this:

let AnyAsString x = 
    sprintf "%A" x

This is a surprisingly handy function (we’ll see why shortly) – it takes any F# value and returns a reasonably-formatted human-readable string version of that value.  (You can read more about the various F# printf functions and specifiers here.)  Suppose I want to call this function from a different source file further down in my project – how do I do it?  Just trying to call it directly doesn’t work; for example if I write

    AnyAsString [1;2;3]

in a different file, I get

The value or constructor ‘AnyAsString’ is not defined.

The reason is that, if you write code at the "top level" of a file without using a "namespace" or a "module" (and I’ll talk more about when/how to use namespaces and modules to organize your code in a future blog entry), then F# implicitly puts your code in a module whose name is the source code filename.  So if my AnyAsString function were defined in "Debug.fs", then to call it from another file I need to write

    Debug.AnyAsString [1;2;3]

Put another way, the original code I showed for that file is equivalent to

// Debug.fs
module Debug

let AnyAsString x = 
    sprintf "%A" x

only this version is less subtle (by virtue of being explicit about the module).

Debugging F# code – breakpoints, locals, and the immediate window

Consider this silly little program which I’ve defined in Program.fs:

// Program.fs
// demonstrate calling a function from another file
printfn "%s" (Debug.AnyAsString [1;2;3])  

type Suit =
    | Club
    | Diamond
    | Heart
    | Spade

type Rank =
    | Ace | Deuce | Trey | Four | Five 
    | Six | Seven | Eight | Nine | Ten
    | Jack | Queen | King
type Card = 
    | Card of Suit * Rank

let bullet = Card(Spade,Ace)
printfn "%A" bullet

let Guess(yourCard : Card) =
    if yourCard = bullet then
        printfn "I knew it, everyone always picks the ace of spades!"
        printfn "Not the spade ace?  You are very clever."

let myCard = Card(Diamond,Trey)
printfn "(mine is %A)" myCard

The program itself is not very interesting or meaningful, but that’s good, because I want to focus on the tooling.  Suppose I put a breakpoint on the first line of the Guess function (by clicking in the margin or pressing F9):


and run the program inside the debugger.  When I hit the breakpoint, in the Locals window (Debug > Windows > Locals), you’ll see the "yourCard" parameter (near the bottom):


but the value of the card (3 of diamonds) is not apparent from this view.  (EDIT, Jan 2010: note that the default debugger experience here has greatly improved, see this entry.)  Even expanding the "+" entry for this local variable will not help much.  However, thanks to our Debug.AnyAsString function, we can easily see the value using the Immediate window (Debug > Windows > Immediate).  In the Immediate window, I can type "Debug.AnyAsString(yourCard)" and it shows me the value (near the bottom right):


There are a number of improvements to the out-of-the-box F# debugging experience that we hope to make in future releases, but in the meantime, this is one alternative technique you can use to inspect the value of local variables inside the debugger.

AnyAsString is an example of a "utility function" that you may find useful in many of your F# programs.  Next time I’ll discuss various ways to organize and reuse small libraries of utility code across multiple projects and solutions.


One Response to “Using multiple F# source files, and a useful debugging technique”

  1. Art said

    Thanks Brian.
    This is needed; look forward to more…

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: