Book review: Programming F#

by Marc Sigrist 12. April 2010 00:33
Programming F# Title: Programming F#
Subtitle: A comprehensive guide for writing simple code to solve complex problems
Publisher: O'Reilly®
Author: Chris Smith
Date of appearance: October, 2009 (416 Pages)

The new version of Visual Studio is officially released today, April 12, 2010. It contains a new language called „F#“, designed by Don Syme of Microsoft Research Cambridge, UK. F# is a programming language that has capacities comparable to C#, but also offers the possibilities of a functional language. It is therefore a multiparadigm language; instead of “F#”, I think it could also have been called "M#".

Before discussing the book, let me mention how I came from C# to F#. I seriously started investigating F# after having written, maybe for the the 10,000th time or so, something like:

/// ...
/// <exception cref=“ArgumentNullException“>
/// <paramref name=“bar“> is <see langword=“null“>.
/// </exception>

void Foo(Bar bar) {if (bar == null) throw new ArgumentNullException("bar");}

Even if one uses helper methods, code snippets, or (in .NET 4.0) a preconditional code contract, writing the non-null enforcement logic still remains an annoyingly repetitive task. One day, I read in a blog comment: "If you want a language with reference types that cannot be null, take a look at F#". This sounded like Christmas to me. After some further research, I decided to take the time to learn this new language.

The book appeared only recently and is up-to-date with the current F# 2.0 release. It was written by Chris Smith, Software Design Engineer in Test at the F# team. It contains a densely written overview of the complete F# language. The writing follows a systematic path from the simple to the advanced. There is always a short introduction of a feature, followed by an extensive example, followed by further comments.

In the introductory chapter, we learn that white space matters: In order to create hierarchies of scope in code, one simply uses new lines and indentations, not curly braces and semicolons. Functions can easily be nested in other functions, which can be nested again in still other functions ad infinitum. Each subordinated function has its own narrow scope, which eliminates an important source of bad programming design. Oftentimes, parameter types do not have to be declared, because the compiler can infer them automatically. If so, one can also avoid writing parentheses () for the parameters. Taken together, these features make the F# language nicely self-documentary. Even without looking at the details, from the tense, clear-cut, indented shape of the code alone, one can quickly get a sense of the logical structure.

Conceptually, you could do the same already in C# 2.0 by nesting anonymous methods within each other. However, even in C# 3.0/4.0, nesting lambdas, the code soon becomes convoluted. As a consequence, in C#, one tends to implement functions without applying the appropriate level of local nesting, or even to declare private methods where anonymous methods would be more logical, thereby violating scope. Declaring private types nested in other private types is not really an alternative, because the declaration has to be outside the method, and it all takes so many lines of code that the whole construct will finally diffuse its own purpose to the reader. The way I see it, by offering the feature of function nesting, functional languages promote the object-oriented principle of encapsulation in a more sophisticated and fine-grained way than object-oriented languages themselves.

As one continues reading the first three chapters, the thinking adapts more and more to the fact that functions are just like other values. F# allows you (through partial function application) to transform functions into other functions with less parameters, and (through "currying" with pipes) to build chains of functions in a natural, intuitive way. Discriminated unions are another productivity-enhancing feature: Imagine enums in C#, but with nearly unlimited freedom in defining (and nesting, and sub nesting...) each enum member. Discriminated union members can be matched to other values via typed pattern matching, another fascinating feature, something like C# switch statements on steroids. Together, discriminated unions and pattern matching save many lines of code and of potential errors. They also make the code spontaneously conceivable-at-a-glance, without having to go back and forth through page after page in the code editor to understand the mapping logic.

Another interesting aspect of F# is the built-in special support of collection-like types. F# tuples internally rely on the .NET 4.0 Tuple type (an ordered collection of differently typed, nameless values). F# records are like C# 3.0 anonymous types, without the anonymity (a collection of differently typed, named values). F# lists are read-only singly linked lists of equal types. Of course, F# also has built-in support for arrays and sequences. The language contains specific operators and other constructs to make the declaration, initialization, and general handling of collection-like types as intuitive and natural as possible, allowing you to "write the code the way you think" and let the compiler do the work of implementing your expressed intentions. It is also possible to use the generic collections from the .NET Framework.

Chapter 4 deals with imperative programming in F#, i.e., programming that alters data that is already in memory. This subject is presented in its own separate chapter, because, by default, F# values can never be null and can never be mutated, even if they are of reference types. The chapter explains how you can digress from the default behavior, including how to deal with .NET Framework members that request or may return null.

Chapter 5 explains object-oriented programming in F#. The author starts with a brief explanation of what object orientation is and why it is useful. These remarks are probably directed at proponents of so-called "pure" functional languages (such as Haskell), who might be skeptical about, or not accustomed to, object orientation. However, the author also mentions some shortcomings of pure object orientation. Among other things, it forces the developer to formally implement certain design patterns, which, in functional languages, are implicitly there without needing special consideration.

Chapter 6 shows how to do classical .NET programming with F#, with some exciting extensions. For example, in F#, using object expressions, it is possible to create an "inline instance" of an interface type, without declaring a named, implementing type first. The chapter also explains how to declare and use standard .NET enumerations (instead of F# discriminated unions) and compares F# value types with F# records.

Chapter 7 deals with applied functional programming. It introduces units of measure and explains the usage of active patterns. Active patterns allow using functions inside the pattern matching. The author points out the three kinds of active patterns: Single-case, partial-case, and multi-case, and how they can be nested. The chapter also shows how to use F# lists in recursions. I was amazed by the fact that the F# compiler automatically generates code that avoids a stack overflow when the recursion is implemented in the “tail-recursive” style. A variation of this is the “continuation passing style”, which prevents stack overflows even when two interdependent recursive functions are involved. The chapter goes on with examples with function currying and the forward pipe operator (for a list of F# operators, see here), followed by closures, memoizing, and lazy evaluation, which should be familiar to C# programmers.

Chapter 8 is about applied object-oriented programming in F#. Any arbitrary symbol may be defined as an operator. One can declare indexers, and also “slices”, which return a sub range of a collection via slice notation. In addition to the generic type constraints known from C#, F# offers type constraints for delegate, enumeration, comparison, and equality conditions. As far as events are concerned, using the F# Observable module, one can define, compose, transform, merge, and map events in various ways. Chapter 9 demonstrates how to use F# as a scripting language. Even in scripted usage, F# is always compiled first, and therefore is faster than regular scripting languages. The chapter also contains a few pages about Microsoft Office automation with F#.

Chapters 10 to 13 contain more advanced F# concepts, which, coming from a C# background, were something like a revelation to me. Using computation expression builders, one can redefine the behavior of keywords such as while, return, yield, try/finally, etc., to create custom background processing for asynchronous workflows. F# allows you to call asynchronous operations almost like synchronous ones. You do not need to apply the traditional Asynchronous Programming Model (APM) of the .NET Framework, which is not type safe, and depends on separate callback methods spread in the class. Fortunately, version 4.0 of the .NET Framework contains Parallel Extensions for .NET (PFX) and thread-safe concurrent collections, with some further optimizations, ready to be used by any .NET language. Chapter 12 deals with reflection and declarative programming in F#. Using F# code quotations, one can access not only the static type information (as in classical reflection), but also the compiler’s internally used abstract syntax tree (AST). This is conceptually similar to, but much more elaborate than, expression trees known from lambdas in C# 3.0.

I would like to recommend this book to experienced developers seriously interested in F#. Readers without a functional background had better not expect to understand everything immediately upon a superficial first reading. The content is quite condensed, and many concepts are new to object-oriented developers. However, once you open yourself up to new ways of thinking about code, chances are you will become truly enthusiastic about the power and intuitiveness of this elegant new language. 

Book review: Pro WPF in C# 2008

by Marc Sigrist 27. February 2010 17:55
Book image Title: Pro WPF in C# 2008
Subtitle: Windows Presentation Foundation with .NET 3.5, Second Edition
Publisher: Apress® Books for Professionals by Professionals™
Series: The Expert's Voice in .NET
Author: Matthew MacDonald
Date of appearance: February, 2008 (1040 Pages)

This book is a thorough examination of the WPF 3.5 technology – its architecture, what you can do with it, and how to do it. It is directed at professional C# developers.

The book is written in a systematic, comprehensible way. A chapter starts with a basic introduction and includes graphics of the respective WPF sub-class hierarchy. The chapter's subject is then steadily explored in more and more detail. For instance, at the beginning, there are five pages just on resolution independence. XAML is explained in-depth, starting with the four ways of loading and compiling: Code-only, code and uncompiled XAML, code and compiled XAML, and XAML only; this is followed by the specifics of the XAML grammar (markup extensions, attached properties, etc.). There are seven pages on non-rectangular windows and sixteen pages on playing sound on different OS versions. As the book goes on, the author really shines in describing complex subjects, such as 3-D drawing, in a logically understandable way. Towards the end, there is a tabular overview of features missing in WPF compared to Windows Forms, with recommendations on when to choose one over the other, or both of them together, and how to mix them best.

The volume also contains lots of small, but precious pieces of surplus information, such as: Properties of WPF controls can be set in any order, without causing any change in behavior; or: By using an overloaded version of DependencyObject.SetValue in code, you can attach a value for any dependency property, even if it is not defined as an attached property (which is not possible in XAML). In addition, the author mentions various quirks of WPF, and how to get around them, if possible. Example: When you restart an animation that is almost complete, and the animation had the current position as the starting point, the animation will appear to slow down. Another example: Windows Vista always requires permission elevation for a setup, even though, in the case of Click Once, this makes no sense. As a consequence, a Click Once WPF application, on Vista, cannot be installed under a regular user account; the user is forced to install it under an admin account - which defeats the purpose of using Click Once in the first place...

Developers are all-too-familiar with the Pareto principle: 80% of the tasks of a project can be solved „easily“ in 20% of the time, but solving the other 20% takes at least 80% of the time. If you want to use WPF in a productive way, I strongly recommend taking the time to study this book. Admittedly, at 1040 pages, this is quite some endeavor. However, you will be rewarded many times over, as you will be saved a lot of frustration and unexpected delays, when you already know from the beginning how to solve much of the other 20%.