strangelights.com

Main F# Site

Edit Edit
Print Print
Recent Changes Recent Changes
Subscriptions Subscriptions
Lost and Found Lost and Found
Find References Find References
Rename Rename
Search
List all versions List all versions
How To Build Records
.

Check out the formatting tips on the right for help formatting and making links.

Use the template below:

Summary

On the F# email list Alex Peake asked "Since records can contain fields that are functions, can these functions refer to other fields within that record?". This is an important topic, since it's closely related to other topics such as how to use records to build objects, and how to use lexical scoping to manage private state and private functionality when building these objects.

The usual way to build rich object-like records is to first use a series of private "let" and "let rec" constructions to build the constituent components, and then publish the results in a record expression. For example, here is a somewhat gratuitous record/object that caches the result of "s1.Length" (gratuitous because s1.Length works in constant time anyway):

 type MyWidget =
   { GetLength : unit -> int;
     Get : unit -> string;
     Update : string -> unit }


 let MakeWidget(s1:string) = 
   let state = ref (s1, s1.Length) in 
   let get() = fst(!state) in 
   let getLength() = snd(!state) in
   let update(s:string) = state := (s,s.Length)  in
   { GetLength = getLength;
     Get = get;
     Update = update }

Note that "private" fields and methods become local "let" bindings. Private state is often a shared mutable structure referenced by multiple closures (note you can define a supporting record MyPrivateWidgetState with mutable fields to hold the private state instead of using “ref” cells). If you adopt this style you will find yourself using more inner let-bindings (which takes some getting used to), and your types will have slimmer external interfaces.

If your methods are mutually referential you simply generalize this to use inner recursive bindings. For example, in this case the "Length" function is implemented using "Get"

 type Widget =
   { GetLength : unit -> int;
     Get : unit -> string;
     Update : string -> unit }


 let MakeWidget(s1:string) = 
   let state = ref(s1) in 
   let rec get() = !state 
   and     getLength() = (get()).Length
   and     update(s) = state := s  in
   { GetLength = getLength;
     Get = get;
     Update = update } 

Many people like this style, and it is an important technique to know, because it helps to learn how to write your code in a way that ensures that your initialization process is coherent (e.g. doesn’t result in null-pointer errors). However, if you do this very often it becomes a bit of a shame that you can’t simply write recursive object expressions. As a result we have recently been discussing supporting the following syntax:

 let MakeWidget(s1:string) = 
   let state = ref(s1) in 
   { member x.GetLength() = (x.Get()).Length;
     member x.Get() = !state;
     member x.Update(s) = state := s }

At the time of writing this is still under consideration and relates to the ongoing work to publish F# modules and values in a more .NET-like fashion, and to support more OO-like programming directly within F#.

Welcome to F Sharp Wiki, view the HomePage

This site supports the new NoFollow anti-spam initiative.

Recent Topics

Copyright 2005, Robert Pickering (Others where credited) | Terms of Use