Type extensions

Definition

Members of a type defined outside its main type block.

Each of these members is called augmentation or extension.

3 categories of extensions:

  • Intrinsic extension

  • Optional extension

  • Extension methods

Intrinsic extension

Declared in the same file and namespace as the type

Use case: Features available in both companion module and type β†’ E.g. List.length list function and list.Length member

How to implement it following top-down declarations?

1. Implement in type: Redirect module functions to type members β†’ More straightforward

2. Intrinsic extensions: β†’ Declare type "naked", Implement in module, Augment type after β†’ Favors FP style, Transparent for Interop

Example:

namespace Example

type Variant =
    | Num of int
    | Str of string

module Variant =
    let print v =
        match v with
        | Num n -> printf "Num %d" n
        | Str s -> printf "Str %s" s

// Add a member as an extension - see `with` required keyword
type Variant with
    member x.Print() = Variant.print x

Optional extension

Extension defined outside the type's module/namespace/assembly

Use cases:

  1. Types we can't modify, for instance coming from a library

  2. Keep types naked - e.g. Elmish MVU pattern

Compilation: into static methods β†’ Simplified version of the previous example:

Another example:

Limits

  • Must be declared in a module

  • Not compiled into the type, not visible to Reflection

  • Usage as pseudo-instance members only in Fβ™― β‰  in Cβ™―: as static methods

Type extension vs virtual methods

☝ Override virtual methods:

  • in the initial type declaration βœ…

  • not in a type extension β›”

Type extension vs type alias

Incompatible❗

πŸ’‘ Solution: use the real type name

☝ Corollary: Fβ™― tuples such as int * int cannot be augmented, but they can be extended using Cβ™―-style extension methods πŸ“

Type extension vs Generic type constraints

Extensions allowed on generic type except when constraints differ:

Solution: Cβ™―-style extension method πŸ“

Extension method (Cβ™―-style)

Static method:

  • Decorated with [<Extension>]

  • In Fβ™― < 8.0: Defined in a class decorated with [<Extension>]

  • Type of 1st argument = extended type (IEnumerable<'T> below)

Example:

Cβ™― equivalent:

☝ Note: The actual implementations of Sum() in LINQ are different, one per type: int, float... β†’ Source code

Tuples

An extension method can be added to any Fβ™― tuple:

Comparison

Feature
Type extension
Extension method

Methods

βœ… instance, βœ… static

βœ… instance, ❌ static

Properties

βœ… instance, βœ… static

❌ Not supported

Constructors

βœ… intrinsic, ❌ optional

❌ Not supported

Extend constraints

❌ Not supported

βœ… Support SRTP

Limits

Type extensions do not support (sub-typing) polymorphism:

  • Not in the virtual table

  • No virtual, abstract member

  • No override member (but overloads πŸ‘Œ)

Extensions vs Cβ™― partial class

Feature
Multi-files
Compiled into the type
Any type

Cβ™― partial class

βœ… Yes

βœ… Yes

Only partial class

Intrinsic extension

❌ No

βœ… Yes

βœ… Yes

Optional extension

βœ… Yes

❌ No

βœ… Yes

Last updated

Was this helpful?