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♯.
Class constructors
Primary constructor
Non-static classes are generally followed by their primary constructor:
☝ 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
andstatic 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:
💡 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
abstract
keywordNo default implementation (with
default
keyword) (Otherwise the member is virtual)
Inheritance with 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 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
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 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>]
attributeOr
struct...end
block (more frequent)
Last updated
Was this helpful?