Declaring class constructors in F# 2.0, also considering singletons

by Marc Sigrist 19. October 2010 23:53

In F#, class constructors can be declared in several different ways. To declare a non-static class, one usually defines a primary constructor, plus zero or more additional constructors. To declare a static class, one usually defines a module.

Using a Primary Constructor

In F#, it is possible to create a thread-safe singleton with just three lines of code:

/// A public thread-safe singleton class in F#,
/// using a private primary constructor.
type Singleton private() =
    static let instance = Singleton()
    static member Instance = instance
// This would be the equivalent code in C#:
public class Singleton{ 
    static readonly Singleton instance = new Singleton(); 
    Singleton() {} 
    public static Singleton Instance {get { return instance;}} 
}

In the above F# example, private() defines an empty primary constructor. Using a primary constructor is the recommended practice for non-static classes in F#. According to the F# 2.0 Language Specification, section 8.6.4., any additional constructors must call the primary constructor (either directly or indirectly), as in the following example:

Using a Primary Constructor and an Additional Constructor

/// A public Person class in F#,
/// using a public primary constructor
/// and an additional public constructor.
type Person(name: string, guid) =
    new(name, guid) = Person(name, Guid.Parse(guid))
    member x.Guid = guid
    member x.Name = name
// This would be the equivalent code in C#:
public class Person{
     readonly string name;
     readonly Guid guid;
 
     public Person(string name, Guid guid){
          this.name = name;
          this.guid = guid;
     }
 
     public Person(string name, string guid):
          this(name, Guid.Parse(guid)){
     }
 
     public Guid Guid {get {return guid;}}
     public string Name {get {return name;}}
}

Using Only "Additional" Constructors

It is also possible to define classes in F# with only "additional" constructors, but no primary constructor. However, the available syntax for the rest of the class is quite restricted. Primary constructors should only be avoided when there is a very compelling reason to do so, e.g., to simplify automatic code generation. The following, modified Singleton example shows some of the difficulties you may face when avoiding a primary constructor:

/// This type is intended for private use within Singleton2 only.
type private SyncRoot = private new() = {}
 
/// A singleton with no primary constructor.
type Singleton2 =
     // As we cannot use implicit ("let"-bound) fields, we have to
     // use explicit ("val"-bound) fields. However, explicit fields
     // who are static must also be default-initialized, mutable, and private.
     [<DefaultValue>]
     static val mutable private instance: Singleton2
 
     private new() = {}
 
     // As we cannot rely on the inherent thread safety of non-mutable
     // let-bound fields, we have to apply a lock.
static member Instance = lock typeof<SyncRoot> (fun() -> if Unchecked.compare Singleton2.instance Unchecked.defaultof<Singleton2> = 0
then Singleton2.instance <- Singleton2()) Singleton2.instance

Using no Constructor at all

What happens if you define a class in F# without using any constructors at all? As opposed to C#, F# will not generate a default public parameterless instance constructor for you in the background. Your F# class simply cannot be instantiated. Oddly enough, while the compiler forbids the declaration of static fields via let bindings in this scenario (whose usage would seem to make sense), it does not complain if you define instance properties/methods/val bindings (who are useless, because they can never be accessed). This leaves you with only static properties/methods/val fields, which is quite restrictive. Furthermore, even if you decide to define such a "type with only static accessibility", it will not appear as a "static class" to its users. For these reasons, it is best to never define classes without constructors in F#. If you need what in C# we call a static class, you better define a module in F#:

Declaring a Static Class

/// A module (static class) defined in F#. Type-level let bindings are public by default,
/// but can also be internal or private. This is opposed to type (non-static class)
/// definitions, where type-level let bindings are always inherently private.
module PersonFactory =
     let CreatePerson(name, guid: Guid) = new (name, guid)
// This would be the equivalent code in C#:
public static class PersonFactory{
     public static Person CreatePerson(string name, Guid guid){
         return new Person(name, guid);
     }
}

However, using modules in F# 2.0 has a certain disadvantage: Method overloading is not possible. If you need method overloading in a static class, there is no other way than declaring a non-static type with just a private parameterless constructor, or no constructor at all:

/// A class with overloaded members in F#.
type PersonFactory2 =
     static member CreatePerson(name, guid: Guid) = Person(name, guid)
     static member CreatePerson(name, guid: string) = Person(name, guid)
// This would be the equivalent code in C#:
public class PersonFactory2{
     public static Person CreatePerson(string name, Guid guid){
          return new Person(name, guid);
     }
 
     public static Person CreatePerson(string name, string guid){
          return new Person(name, guid);
     }
}

No Static Constructor Method in F#

There is no separate static constructor method in F#. In order to run "static constructor code" in F#, you first need to declare a primary constructor. A primary constructor is actually an instance constructor (it can have a non-public access modifier and can take arguments). However, if and only if a primary constructor exists, any type-level static let and do-bound code implicitly becomes "static constructor code".

/// Running "static constructor code" in F#.
type SomeType() =
     static let instanceCount = ref 0
     static do printfn "Type created at %A" DateTime.Now
     do printfn "Instance created at %A" DateTime.Now
     do incr instanceCount
     static member InstanceCount = !instanceCount
// This would be comparable code in C#:
public class SomeType{
     static SomeType(){
         Console.WriteLine(
              string.Format("Type created at {0:G}", DateTime.Now));
     }
 
     public SomeType(){
         Console.WriteLine(
              string.Format("Instance created at {0:G}", DateTime.Now));
         InstanceCount++;
     }
 
     public static int InstanceCount {get; private set;}
}

In this blog post, I have covered the basics of declaring F# constructor code for class types and modules. Much more could be said with regards to type construction in F#. For instance, I did not cover structures, records, object expressions, calling base class constructors, and the details of read-only fields versus mutable fields versus reference value fields. Further information can be found in the F# specification, F# Language Reference, F# documentation, or in one of the few outstanding books available, such as Programming F#.

Tags: , ,

F#

Yet another comment on the C# cast ( ) and „as“ operators…

by Marc Sigrist 21. February 2010 19:39

Time and again, the question comes up whether to prefer the cast ( ) or the „as“ operator in C# to perform conversions to reference types. According to the C# 3.0 language specification, the two operators behave differently in several respects:

C# Conversion Operator( )as
Name Cast operator as operator
C# 3.0 Specification section 7.6.6 7.9.11
Can convert to ValueType Yes No
Executes user-defined explicit conversions Yes No
Compile-time errors CS0030: Cannot convert type 'X' to 'Y'. CS0030: Cannot convert type 'X' to 'Y'.
CS0077: The as operator must be used with a reference type or nullable type ('Y' is a non-nullable value type).
Runtime behavior if not convertible Throws InvalidCastException: "Unable to cast object of type 'X' to type 'Y'." Returns null

Given the above comparison table, it follows that you must use the cast operator ( ) in the following cases:

  • to convert to a ValueType:
    object o = 137; var i = (int)o;
  • to convert via a user-defined explicit operator overload defined in the source type. Note that the overload may return anything whatsoever: The same instance, a new instance of the same type, a new instance of a completely non-related type, null, a value type or reference type...
    // Declared inside a class called Source:
    static explicit operator Target(Source s) {return new Target();}

By contrast, you must use the "as" operator in the following cases:

  • to be 100% sure that that the result points to the same instance, or null, but never anything else:
    var bar = foo as Bar;
  • to return null if a runtime conversion to the desired reference type is not possible, as in this construct:
    var bar = foo as Bar ?? new Bar();

Furthermore, the "as" operator is a bit more tolerant with generics at compile time than the cast operator. That’s because the as operator casts „directly“ to a type of the same inheritance line:

TDerived GetDerived<TBase, TDerived>(TBase b) where TDerived: class {
    // Produces compiler error CS0030: Cannot convert
    // type 'TBase' to 'TDerived'.

    // return (TDerived)b;

    // This compiles...
    return
b as TDerived;
}

In all other cases, from a technical point of view, you may freely choose between the cast and the "as" operator. Therefore, the „right“ decision depends on what you want to express most in the source code. If you use the "as" operator, you thereby clearly document that you are interested in a reference target type that points to the same instance, and nothing else whatsoever – i.e., you do not want some crazy custom explicit operator to produce any side effects! Moreover, as a matter of taste, the "as" operator makes your code less cryptic, because it uses no parentheses, whereas the cast ( ) operator looks like old-fashioned C code.

For these reasons, personally, I prefer the "as" operator over the cast ( ) operator. However, I have met other developers who almost religiously defend usage of the cast ( ) operator as a best practice, „because it immediately throws an InvalidCastException“ at runtime if necessary, while the "as" operator might only later produce a NullReferenceException. Yet, against this, it could be argued that the "as" operator is even more secure, because it does not allow you to compile if it’s a value type, and it will never produce side effects...

Some tools, such as JetBrains‘ ReSharper, warn you if you apply the "as" operator without checking for null with a null comparison within the same procedure, even if null is logically impossible; e.g., when you have defined a null-checking procedure in a separate external helper method. You can turn this off, but only on a per-user basis. Others who look at your code may still see the warning. You may also disable the warning by surrounding the „critical“ section with a specific ReSharper comment, but it’s annoying to have your code cluttered like this. Therefore, if your company uses ReSharper, this might be a pragmatic reason to prefer the cast ( ) operator over the "as" operator.

In my opinion, it would be better if the C# "as" operator did not return null, but throw an InvalidCastException if the direct cast is not possible. Nothing of importance would be lost by this – you can always check for null with the "is" operator - but a lot of misunderstandings and disagreements would be prevented. Interestingly, the VB.NET language has the DirectCast operator, which does exactly this. A similar behavior could be implemented in C# like this:

public static T As<T>(this object o) where T: class{
    if
(o == null) throw new NullReferenceException();
    if
(!(o is T)) throw new InvalidCastException();
    return
o as T;
}

Simulating multiple inheritance in C#

by Marc Sigrist 18. February 2010 23:15

It is possible to simulate multiple inheritance in C#, in a limited way, by applying extension methods to interfaces. An example is shown below. Note that this works only for method implementation inheritance, but not for properties or any other kinds of base members.

The C# team originally considered including extension properties in C# 4.0, but then dropped the feature. The reason apparently was that including extension properties would logically imply including indexed extension properties as well, which C#, by design, does not support. However, accessing (but not defining) indexed properties will be introduced in C# 4.0, in order to make it easier to work with COM interop. Another reason might be that extension properties in C# 4.0 would cause conceptual confusion with the already-existing feature of attached properties in WPF. Interestingly, F# does offer extension properties, but it cannot be used (yet?) as code-behind language for WPF XAML files.

You probably will not use this approach in order to „simulate multiple inheritance“ very often. However, the capacity to add extension methods to interfaces, as such, is a powerful feature. It allows to cleanly separate categories of standard behaviors from their owners.

 using System;

// This test shows how to simulate multiple inheritance in C#.

// Requires .Net Framework 3.5 as target framework.

namespace Test {

    interface IBase1 { }

 

    static class Base1Implementation {

        internal static void Base1Method(this IBase1 base1) {

            Console.WriteLine("Base1Method called.");

        }

    }

 

    interface IBase2 { }

 

    static class Base2Implementation {

        internal static void Base2Method(this IBase2 base2) {

            Console.WriteLine("Base2Method called.");

        }

    }

 

    class Derived: IBase1, IBase2 { }

 

    static class Program {

        static void Main() {

            var derived = new Derived();

            derived.Base1Method(); // Writes "Base1Method called."

            derived.Base2Method(); // Writes "Base2Method called."

        }

    }

}