F# Add multiple constructor overloads that call the base class constructor

89 Views Asked by At

I'm trying to create a dictionary with structural equality in F# and I want to pass through several dictionary constructor overloads.

In C# this would look like

class StructuralDictionary<Key, Value> : Dictionary<Key, Value> where Key : IEquatable<Key>
{
    public StructuralDictionary() : base() { }
    public StructuralDictionary(IDictionary<Key, Value> dict) : base(dict) { }
    public StructuralDictionary(IEqualityComparer<Key> keyComparer) : base(keyComparer) { }
}

The F# docs have section demonstrating this usecase, but I can't get it to compile

type StructuralDictionary<'key, 'value when 'key:equality> =

    new (dictionary:IDictionary<'key,'value>) = { inherit Dictionary<'key,'value>(dictionary) }
    new () = { inherit Dictionary<'key, 'value> () }
2

There are 2 best solutions below

0
farlee2121 On BEST ANSWER

Ah. I was missing a inherit at the top

type StructuralDictionary<'key, 'value when 'key:equality> =
    inherit Dictionary<'key, 'value> // <--- This has to be here

    new (dictionary:IDictionary<'key,'value>) = { inherit Dictionary<'key,'value>(dictionary) }
    new () = { inherit Dictionary<'key, 'value> () }

I got a bit confused because I started with a primary constructor like

type StructuralDictionary<'key, 'value when 'key:equality> () =
    inherit Dictionary<'key, 'value> ()

    new (dictionary:IDictionary<'key,'value>) = { inherit Dictionary<'key,'value>(dictionary) }

But that doesn't work. So I tried to move the primary constructor down, but also moved the inheritance declaration so it still didn't compile.

It turns out to overload constructors you must have inherits at the top of the type declaration but you must not specify a primary constructor at the top.

2
Tomas Petricek On

If you want to use the implicit constructor syntax, all other constructors will have to call the implicit constructor (and, indirectly, will end up calling the same constructor of the base class).

In your example, you could define an implicit constructor that takes IDictionary as the argument and call it with an empty dictionary from the other constructor:

type StructuralDictionary<'TKey, 'TValue when 'TKey:equality>
    (dictionary:IDictionary<'TKey, 'TValue>) =
  inherit Dictionary<'TKey, 'TValue>(dictionary)
  new () = StructuralDictionary(dict [])

This may have some small overhead in contrast to just calling the base constructor without arguments (you are allocating an empty dictionary), but it lets you use all the other convenient features of implicit constructors, so it is probably worth it.

Related Questions in F#