Explicit Fields: The val Keyword
The val
keyword is used to declare a location to store a value in a class or structure type, without initializing it. Storage locations declared in this manner are called explicit fields. Another use of the val
keyword is in conjunction with the member
keyword to declare an automatically implemented property. For more information on automatically implemented properties, see Properties.
Syntax
val [ mutable ] [ access-modifier ] field-name : type-name
Remarks
The usual way to define fields in a class or structure type is to use a let
binding. However, let
bindings must be initialized as part of the class constructor, which is not always possible, necessary, or desirable. You can use the val
keyword when you want a field that is uninitialized.
Explicit fields can be static or non-static. The access-modifier can be public
, private
, or internal
. By default, explicit fields are public. This differs from let
bindings in classes, which are always private.
The DefaultValue attribute is required on explicit fields in class types that have a primary constructor. This attribute specifies that the field is initialized to zero. The type of the field must support zero-initialization. A type supports zero-initialization if it is one of the following:
- A primitive type that has a zero value.
- A type that supports a null value, either as a normal value, as an abnormal value, or as a representation of a value. This includes classes, tuples, records, functions, interfaces, .NET reference types, the
unit
type, and discriminated union types. - A .NET value type.
- A structure whose fields all support a default zero value.
For example, an immutable field called someField
has a backing field in the .NET compiled representation with the name someField@
, and you access the stored value using a property named someField
.
For a mutable field, the .NET compiled representation is a .NET field.
Warning
The .NET Framework namespace System.ComponentModel
contains an attribute that has the same name. For information about this attribute, see DefaultValueAttribute.
The following code shows the use of explicit fields and, for comparison, a let
binding in a class that has a primary constructor. Note that the let
-bound field myInt1
is private. When the let
-bound field myInt1
is referenced from a member method, the self identifier this
is not required. But when you are referencing the explicit fields myInt2
and myString
, the self identifier is required.
type MyType() =
let mutable myInt1 = 10
[<DefaultValue>] val mutable myInt2 : int
[<DefaultValue>] val mutable myString : string
member this.SetValsAndPrint( i: int, str: string) =
myInt1 <- i
this.myInt2 <- i + 1
this.myString <- str
printfn "%d %d %s" myInt1 (this.myInt2) (this.myString)
let myObject = new MyType()
myObject.SetValsAndPrint(11, "abc")
// The following line is not allowed because let bindings are private.
// myObject.myInt1 <- 20
myObject.myInt2 <- 30
myObject.myString <- "def"
printfn "%d %s" (myObject.myInt2) (myObject.myString)
The output is as follows:
11 12 abc
30 def
The following code shows the use of explicit fields in a class that does not have a primary constructor. In this case, the DefaultValue
attribute is not required, but all the fields must be initialized in the constructors that are defined for the type.
type MyClass =
val a : int
val b : int
// The following version of the constructor is an error
// because b is not initialized.
// new (a0, b0) = { a = a0; }
// The following version is acceptable because all fields are initialized.
new(a0, b0) = { a = a0; b = b0; }
let myClassObj = new MyClass(35, 22)
printfn "%d %d" (myClassObj.a) (myClassObj.b)
The output is 35 22
.
The following code shows the use of explicit fields in a structure. Because a structure is a value type, it automatically has a parameterless constructor that sets the values of its fields to zero. Therefore, the DefaultValue
attribute is not required.
type MyStruct =
struct
val mutable myInt : int
val mutable myString : string
end
let mutable myStructObj = new MyStruct()
myStructObj.myInt <- 11
myStructObj.myString <- "xyz"
printfn "%d %s" (myStructObj.myInt) (myStructObj.myString)
The output is 11 xyz
.
Beware, if you are going to initialize your structure with mutable
fields without mutable
keyword, your assignments will work on a copy of the structure which will be discarded right after assignment. Therefore your structure won't change.
[<Struct>]
type Foo =
val mutable bar: string
member self.ChangeBar bar = self.bar <- bar
new (bar) = {bar = bar}
let foo = Foo "1"
foo.ChangeBar "2" //make implicit copy of Foo, changes the copy, discards the copy, foo remains unchanged
printfn "%s" foo.bar //prints 1
let mutable foo' = Foo "1"
foo'.ChangeBar "2" //changes foo'
printfn "%s" foo'.bar //prints 2
Explicit fields are not intended for routine use. In general, when possible you should use a let
binding in a class instead of an explicit field. Explicit fields are useful in certain interoperability scenarios, such as when you need to define a structure that will be used in a platform invoke call to a native API, or in COM interop scenarios. For more information, see External Functions. Another situation in which an explicit field might be necessary is when you are working with an F# code generator which emits classes without a primary constructor. Explicit fields are also useful for thread-static variables or similar constructs. For more information, see System.ThreadStaticAttribute
.
When the keywords member val
appear together in a type definition, it is a definition of an automatically implemented property. For more information, see Properties.