Welcome to Atalasoft Community Sign in | Help

Applied F# Symposium Session 2

How to Define Consumable Classes

Fine Points

1. F# is Free, C# is Closed – members in F# are public by default, members in C# are private by default. When in doubt, spell it out.

2. F# wants you to use lots of little static functions. Our customers don’t – they want objects/controls. Follow the template

3. F# has multiple, sometimes conflicting syntaxes for defining things. Sorry.

4. Files in an F# project are not necessarily in alphabetical order; they are in parse/necessity/dependency order. Again, sorry.

Content

Best practice point – here’s how to build a class file

Gross Structure

<namespace declaration>

<open clauses>

<helper modules>

<open clauses>

<class definition(s)>

Example:

namespace Frobozz.lifeform

open System

open System.IO

module internal argutils =

let raiseOnNull s o =

if o = null then raise(ArgumentNullException(s)) else o

open argutils

type FilePath(s:string) =

let _pathStr = raiseOnNull "s" s

let _path = _pathStr.Split([| '/'; '\\' |])

member this.Path with get() = _path

Exercise

1. Define a class called Digit which constructs with a string, its name, and has a read-only property Name and overrides ToString to print its name

2. Define a class called Hand which constructs with an int, the number of digits, and has a property which is a list of Digit, initialized to the digits. Every hand with n digits has n-1 fingers and 1 thumb.

3. Show and tell for abstract life forms, then make your favorite non-mute animal

4. Show and tell for interfaces and mix-in classes

 
namespace Frobozz.lifeform   
open System
open System.IO
open System.Media
open System.Reflection  
module internal utils =
let raiseOnNull s o =
if o = null then raise(ArgumentNullException(s))
else o
let raiseOnNegative s n =
if sign n < 0 then raise(ArgumentOutOfRangeException(s))
else n  
open utils   
type Digit(name:string) =
let _name = raiseOnNull "name" name
member this.Name with get() = _name
override this.ToString() = this.Name  
module internal lifeHelpers =
let namedDigit (n:int) =
new Digit(String.Format("finger {0}", n))
let rec makeDigits n l =
if n = 0 then l
elif n = 1 then new Digit "thumb" :: l
else (namedDigit (n - 1)) :: (makeDigits (n - 1) l)
let makeDigits1 n =
if n > 0 then new Digit("thumb") :: [ for i in 1 .. (n-1) -> (namedDigit i) ]
else []  
open lifeHelpers   
type Hand(digitCount:int) =
let _digits = makeDigits digitCount []
member this.Digits with get() = _digits  
[<AbstractClass>]
type Lifeform() =
abstract member Vocalize : unit -> unit  
[<AbstractClass>]
type SoundLifeform() =
inherit Lifeform()
abstract member GetSoundStream : unit -> Stream
override this.Vocalize() =
let stm = this.GetSoundStream() |> raiseOnNull "GetSoundStream"
let player = new SoundPlayer(stm)
player.PlaySync()    
type FSharpDuck(assem : Assembly, resName:string) =
inherit SoundLifeform()
override this.GetSoundStream() =
assem.GetManifestResourceStream(resName)    
type IVocal =
abstract member Vocalize : unit -> unit  
type BetterLifeform() =
abstract member Metabolize : unit -> unit
default this.Metabolize() = Console.WriteLine("breathing.")
member this.CanSpeak with get() = (this :> obj) :? IVocal  
type Slug() =
inherit BetterLifeform()  
type BetterDuck() =
inherit BetterLifeform()
interface IVocal with
override this.Vocalize() = Console.WriteLine("quack.")
 
Published Friday, June 25, 2010 2:58 PM by Steve Hawley

Comments

No Comments
Anonymous comments are disabled