Class, Struct

Class

Class in Fβ™― ≑ class in Cβ™―

  • Object-oriented building block

  • Constructor of objects containing data of defined type and methods

  • Can be static too

Keyword: we use the type keyword to define a class, like any other type in Fβ™―.

type MyClass =
    // (static) let and do bindings...
    // Constructors...
    // Members...

Class constructors

Primary constructor

Non-static classes are generally followed by their primary constructor:

type CustomerName(firstName: string, lastName: string) =
    // Primary builder's body
    // Members...

☝ Note: The primary constructor parameters, here firstName and lastName, are visible throughout the class body.

Secondary constructor

Syntax for defining another constructor: new(argument-list) = constructor-body

☝ In constructor-body, there must be a call the primary constructor.

Constructor parameters

☝ Constructors accept only tuples. They can not be curried!

let bindings

We can use let bindings in the class definition to define variables (in fact, class fields, called implicit fields) and inner functions.

Syntax:

☝ Notes

  • Declared before the class members

  • Initial value mandatory

  • Private

  • Direct access: no need to qualify them with the self-identifier

Example:

do bindings

We can use do bindings in the class definition to trigger side-effects (like logging) during the construction of the object or of the type, before the members.

Syntax:

Static constructor

  • There are no explicit static constructors in Fβ™―.

  • We can use static let and static do bindings to perform "type initialization".

  • They will be executed the first time the type is used.

Example:

Singleton

You can define a Singleton class by making the primary constructor private:

Warning

πŸ’‘ Alternative: single-case union perfectly fits this use case with no overhead.

Empty class

To define a class without a body, use the verbose syntax class ... end:

Generic class

There is no automatic generalization on type β†’ Generic parameters need to be specified:

Instanciation

Call one of the constructors, with tuple arguments

☝️ Don't forget () if no arguments, otherwise you get a function!

In a let binding: new is optional and not recommended β†’ let v = Vector(1.0, 2.0) πŸ‘Œ β†’ let v = new Vector(1.0, 2.0) ❌

In a use binding: new mandatory β†’ use d = new Disposable()

Property initialization

Properties can be initialized with setters at instantiation πŸ‘

  • Specify them as named arguments in the call to the constructor

  • Place them after any constructor arguments

πŸ’‘ Equivalent in Cβ™―: new PersonName("John") { Last = "Paul" }

Abstract class

Annotated with [<AbstractClass>]

One of the members is abstract:

  1. Declared with the abstract keyword

  2. No default implementation (with the default keyword) (Otherwise the member is virtual)

Inheritance with the inherit keyword β†’ Followed by a call to the base class constructor

Example:

Fields

2 kind of field: implicit or explicit

Implicit fields

As we've already seen, let bindings implicitly define fields in the class...

Explicit fields

Syntax: val [ mutable ] [ access-modify ] field-name : type-name

  • No initial value

  • public by default

  • can be compiled using a backing field:

    • val mutable a: int β†’ public field

    • val a: int β†’ internal field a@ + property a => a@

Field vs property

Explicit field vs implicit field vs property

Explicit fields are not often used:

  • Only for classes and structures

  • Useful with native functions manipulating memory directly (Because fields order is preserved - see SharpLab)

  • Need a [<ThreadStatic>] variable

  • Interaction with Fβ™― class of code generated without primary constructor

Implicit fields / let bindings are quite common, to define intermediate variable during construction.

Other use cases match auto-implemented properties:

  • Expose a value β†’ member val

  • Expose a mutable "field" β†’ member val ... with get, set

Structures

Alternatives to classes, but with more limited inheritance and recursion features

Same syntax as for classes, but with the addition of:

  • [<Struct>] attribute

  • Or struct...end block (more frequent)

Last updated

Was this helpful?