|
How would this look in idiomatic F#? |
I’ve been watching the play for apps from the sidelines. Had I’d missed the
boat by not getting in early with the first wave of farting and beer swilling
apps for mobile? Was the development experience raw and retrograde, like back
to the ’90s before virtual machines with many build targets and #pragma
hell? Xamarin helps ease that cross-platform pain? With
the recent release of F# 3.0 came another open source drop of the compiler and
tools and a language binding for F# 3.0 has been added to Xamarin
Studio.
Beloved F# istas, how would you do this in idiomatic F# to be shorter, ex: the error handling: gist.github.com/lobrien/5250556
— Miguel de Icaza (@migueldeicaza) March 27, 2013
In response to this tweet, I set about converting the C# in that gist to F#, figuring it would be a good way to take the Xamarin tooling for a test drive. To get started, I created a new F# project in Visual Studio but changed the default references to the mono assemblies. After a transcription from C# to F#, the code changes I made were …
- Put the moving bits inside an auto-opening private module. This is something
like an anonymous namespace in C++, a place to put stuff that is local to the
source file but otherwise hidden. What was left to the class members was to
unwrap a
Choice<_, _>
, possibly fire an alert off and return anOption<_>
…
[<AutoOpen>]
module private __ =
let initializeSession f =
the real work gets done here
//
type VideoCapture(labelledView) =
inherit AVCaptureVideoDataOutputSampleBufferDelegate()
...
//member x.InitializeSession () =
match initializeSession x with
(s) -> Some(s)
| Choice1Of2(m) -> alert(m); None | Choice2Of2
- I stopped naming things I didn’t care about using underscore, the discard binding from pattern matches. Note that I cannot use a single underscore for the this binding of a method so I use two.
override __.FinishedLaunching(_, _) = ...
- Replaced nulls with options and choices.
- Dropped the use of new when constructing object except when the class implements IDisposable.
- Collected related fields into records going with immutability where possible.
From this ...
//type VideoCapture(imgView, label) =
inherit AVCaptureVideoDataOutputSampleBufferDelegate()
member val ImageView : UIImageView = null with get, set
member val InfoLabel : UILabel = null with get, set
To this ...
//type LabelledView = {Label : UILabel; View : UIImageView}
type VideoCapture(labelledView) =
inherit AVCaptureVideoDataOutputSampleBufferDelegate()
- Used pattern matching to deconstruct records.
match labelledView with
{Label = l; View = v} -> |
- Dropped the
Maybe-
prefix on methods that were returning null but were now returningOption<_>
. - I preferred to use
Ref<_>
for the few remaining mutations of fields. - Encoded the same information in fewer fields by seeing that recording was tied to the existence of the capture.
type VideoCaptureController(viewColor, title) =
inherit UIViewController()
from this ...
//member val recording =
false with get, set
member val videoCapture : VideoCapture =
new VideoCapture(cv.LabelledView) with get, set
to this ...
//let capture : Ref<VideoCapture option> = ref None
The complete solution and gist are up at github. I coded this blind, aiming only to get it compiling and don’t know if it runs.