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
Macro
.
Summary

(See Don Syme's description of building rich object-like records, below, which stimulated the following)

First this is very similar to some Lisp and Scheme work I have been doing, using structures.

There are two differences in this context, and here I am wondering if anything can be done in the F# world:

You are probably familiar, but just for quick reference -- if I say (in Scheme):

(define-struct attr (name domain...

I automatically get make-attr, attr-name, attr-domain etc.

In Lisp

(defstruct (attr (:constructor create-attr (name domain &key (dom-len nil) (caption (string-labelize name))...

Here I defined my constructor as create-attr, and get attr-name, attr-domain, etc. and also have defaulting to values or functions on fields

You are also probably aware of the work on Nemerle which gives us Macros and access to the compiler pipeline, and work on Boo which gives us access to the compiler pipeline -- both of which allow you to create your own versions of this. Fundamentally it just saves typing (of the keyboarding variety), but the code is more concise.

Are any of these interesting for F#?

Don Syme's description of building rich object-like records

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 }

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#.

Don

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