Type and Module Extensions
Remarks#
In all cases when extending types and modules, the extending code must be added/loaded before the code that is to call it. It must also be made available to the calling code by opening/importing the relevant namespaces.
Adding new methods/properties to existing types
F# allows functions to be added as “members” to types when they are defined (for example, Record Types). However F# also allows new instance members to be added to existing types - even ones declared elsewhere and in other .net languages.
The following example adds a new instance method Duplicate
to all instances of String
.
type System.String with
member this.Duplicate times =
Array.init times (fun _ -> this)
Note: this
is an arbitrarily chosen variable name to use to refer to the instance of the type that is being extended - x
would work just as well, but would perhaps be less self-describing.
It can then be called in the following ways.
// F#-style call
let result1 = "Hi there!".Duplicate 3
// C#-style call
let result2 = "Hi there!".Duplicate(3)
// Both result in three "Hi there!" strings in an array
This functionality is very similar to Extension Methods in C#.
New properties can also be added to existing types in the same way. They will automatically become properties if the new member takes no arguments.
type System.String with
member this.WordCount =
' ' // Space character
|> Array.singleton
|> fun xs -> this.Split(xs, StringSplitOptions.RemoveEmptyEntries)
|> Array.length
let result = "This is an example".WordCount
// result is 4
Adding new static functions to existing types
F# allow existing types to be extended with new static functions.
type System.String with
static member EqualsCaseInsensitive (a, b) = String.Equals(a, b, StringComparison.OrdinalIgnoreCase)
This new function can be invoked like this:
let x = String.EqualsCaseInsensitive("abc", "aBc")
// result is True
This feature can mean that rather than having to create “utility” libraries of functions, they can be added to relevant existing types. This can be useful to create more F#-friendly versions of functions that allow features such as currying.
type System.String with
static member AreEqual comparer a b = System.String.Equals(a, b, comparer)
let caseInsensitiveEquals = String.AreEqual StringComparison.OrdinalIgnoreCase
let result = caseInsensitiveEquals "abc" "aBc"
// result is True
Adding new functions to existing modules and types using Modules
Modules can be used to add new functions to existing Modules and Types.
namespace FSharp.Collections
module List =
let pair item1 item2 = [ item1; item2 ]
The new function can then be called as if it was an original member of List.
open FSharp.Collections
module Testing =
let result = List.pair "a" "b"
// result is a list containing "a" and "b"