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 letandstatic dobindings 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:
π‘ 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:
Declared with the
abstractkeywordNo default implementation (with the
defaultkeyword) (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
publicby defaultcan be compiled using a backing field:
val mutable a: intβ public fieldval a: intβ internal fielda@+ propertya => 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>]variableInteraction 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 valExpose 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>]attributeOr
struct...endblock (more frequent)
Last updated
Was this helpful?