Properties (F#)

Properties are members that represent values associated with an object.

// Property that has both get and set defined.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
   with [accessibility-modifier] get() =
      get-function-body
   and [accessibility-modifier] set parameter =
      set-function-body

// Alternative syntax for a property that has get and set.
[ attributes-for-get ]
[ static ] member [accessibility-modifier-for-get] [self-identifier.]PropertyName =
      get-function-body
[ attributes-for-set ]
[ static ] member [accessibility-modifier-for-set] [self-identifier.]PropertyName
   with set parameter =
      set-function-body

// Property that has get only.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName =
      get-function-body

// Alternative syntax for property that has get only.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
   with get() =
      get-function-body

// Property that has set only.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
   with set parameter =
      set-function-body

Remarks

Properties represent the "has a" relationship in object-oriented programming, representing data that is associated with object instances or, for static properties, with the type.

You declare properties by using the member keyword, the self identifier value that represents the current instance, and the name of the property. This declarative syntax is followed by the syntax that specifies the get and set methods, also named accessors. The various forms of the syntax shown are used for read/write, read-only, and write-only properties. For read-only properties, you define only a get method; for write-only properties, define only a set method. Note that when a property has both get and set accessors, the alternative syntax enables you to specify attributes and accessibility modifiers that are different for each accessor, as is shown in the following code.

// A read-only property.
member this.MyReadOnlyProperty = myInternalValue
// A write-only property.
member this.MyWriteOnlyProperty with set (value) = myInternalValue <- value
// A read-write property.
member this.MyReadWriteProperty
    with get () = myInternalValue
    and set (value) = myInternalValue <- value

Private values that hold the data for properties are called backing stores. Unlike other languages, F# does not provide a mechanism for creating an implicit backing store for a property; you must define backing stores explicitly, typically by using a mutable let binding, as follows.

type MyClass(x : string) =
    let mutable myInternalValue = x
    member this.MyProperty
         with get() = myInternalValue
         and set(value) = myInternalValue <- value

For read/write properties, which have both a get and set method, the order of get and set can be reversed. Alternatively, you can provide the syntax shown for get only and the syntax shown for set only instead of using the combined syntax. Doing this makes it easier to comment out the individual get or set method, if that is something you might need to do. This alternative to using the combined syntax is shown in the following code.

member this.MyReadWriteProperty with get () = myInternalValue
member this.MyReadWriteProperty with set (value) = myInternalValue <- value

Properties can be members of classes, structures, discriminated unions, records, interfaces, and type extensions and can also be defined in object expressions.

Attributes can be applied to properties. To apply an attribute to a property, write the attribute on a separate line before the property. For more information, see Attributes (F#).

By default, properties are public. Accessibility modifiers can also be applied to properties. To apply an accessibility modifier, add it immediately before the name of the property if it is meant to apply to both the get and set methods; add it before the get and set keywords if different accessibility is required for each accessor. The accessibility-modifier can be one of the following: public, private, internal. For more information, see Access Control (F#).

Property implementations are executed each time a property is accessed.

Static and Instance Properties

Properties can be static or instance properties. Static properties can be invoked without an instance and are used for values associated with the type, not with individual objects. For static properties, omit the self identifier. The self identifier is required for instance properties.

The following static property definition is based on a scenario in which you have a static field myStaticValue that is the backing store for the property.

static member MyStaticProperty
    with get() = myStaticValue
    and set(value) = myStaticValue <- value

Properties can also be array-like, in which case they are called indexed properties. For more information, see Indexed Properties (F#).

Type Annotation for Properties

In many cases, the compiler has enough information to infer the type of a property from the type of the backing store, but you can set the type explicitly by adding a type annotation.

// To apply a type annotation to a property that does not have an explicit 
// get or set, apply the type annotation directly to the property.
member this.MyProperty1 : int = myInternalValue
// If there is a get or set, apply the type annotation to the get or set method.
member this.MyProperty2 with get() : int = myInternalValue

Using Property set Accessors

You can set properties that provide set accessors by using the <- operator.


// Assume that the constructor argument sets the initial value of the
// internal backing store.
let mutable myObject = new MyType(10)
myObject.MyProperty <- 20
printfn "%d" (myObject.MyProperty)

The output is 20.

Abstract Properties

Properties can be abstract. As with methods, abstract just means that there is a virtual dispatch associated with the property. Abstract properties can be truly abstract, that is, without a definition in the same class. The class that contains such a property is therefore an abstract class. Alternatively, abstract can just mean that a property is virtual, and in that case, a definition must be present in the same class. Note that abstract properties must not be private, and if one accessor is abstract, the other must also be abstract. For more information about abstract classes, see Abstract Classes (F#).

// Abstract property in abstract class.
// The property is an int type that has a get and
// set method
[<AbstractClass>]
type AbstractBase() =
   abstract Property1 : int with get, set

// Implementation of the abstract property
type Derived1() =
   inherit AbstractBase()
   let mutable value = 10 
   override this.Property1 with get() = value and set(v : int) = value <- v

// A type with a "virtual" property.
 type Base1() =
   let mutable value = 10
   abstract Property1 : int with get, set
   default this.Property1 with get() = value and set(v : int) = value <- v

// A derived type that overrides the virtual property
type Derived2() =
   inherit Base1()
   let mutable value2 = 11
   override this.Property1 with get() = value2 and set(v) = value2 <- v

See Also

Reference

Methods (F#)

Other Resources

Members (F#)