This topic has not yet been rated - Rate this topic

Access Control (F#)

Access control refers to declaring which clients can use certain program elements, such as types, methods, and functions.

In F#, the access control specifiers public, internal, and private can be applied to modules, types, methods including constructors, value definitions, functions, properties, and explicit fields.

  • public indicates that the entity can be accessed by all callers.

  • internal indicates that the entity can be accessed only from the same assembly.

  • private indicates that the entity can be accessed only from the enclosing type or module.

Note Note

The access specifier protected is not used in F#, although it is acceptable if you are using types authored in languages that do support protected access. Therefore, if you override a protected method, your method remains accessible only within the class and its descendents.

In general, the specifier is put in front of the name of the entity, except when a mutable or inline specifier is used, which appear after the access control specifier.

If no access specifier is used, the default is public, except for let bindings in a type, which are always private to the type.

Signatures in F# provide another mechanism for controlling access to F# program elements. Signatures are not required for access control. For more information, see Signatures (F#).

Access control is subject to the following rules:

  • Inheritance declarations (that is, the use of inherit to specify a base class for a class), interface declarations (that is, specifying that a class implements an interface), and abstract members always have the same accessibility as the enclosing type. Therefore, an access control specifier cannot be used on these constructs.

  • Individual cases in a discriminated union cannot have their own access control modifiers separate from the union type.

  • Individual fields of a record type cannot have their own access control modifiers separate from the record type.

The following code illustrates the use of access control specifiers. There are two files in the project, Module1.fs and Module2.fs. Each file is implicitly a module. Therefore, there are two modules, Module1 and Module2. A private type and an internal type are defined in Module1. The private type cannot be accessed from Module2, but the internal type can.


// Module1.fs

module Module1

// This type is not usable outside of this file
type private MyPrivateType() =
   // x is private since this is an internal let binding
   let x = 5
   // X is private and does not appear in the QuickInfo window
   // when viewing this type in the Visual Studio editor
   member private this.X() = 10
   member this.Z() = x * 100

type internal MyInternalType() =
   let x = 5
   member private this.X() = 10
   member this.Z() = x * 100

// Top-level let bindings are public by default,
// so "private" and "internal" are needed here since a
// value cannot be more accessible than its type.
let private myPrivateObj = new MyPrivateType()
let internal myInternalObj = new MyInternalType()

// let bindings at the top level are public by default,
// so result1 and result2 are public.
let result1 = myPrivateObj.Z
let result2 = myInternalObj.Z


The following code tests the accessibility of the types created in Module1.fs.


// Module2.fs
module Module2

open Module1

// The following line is an error because private means
// that it cannot be accessed from another file or module
// let private myPrivateObj = new MyPrivateType()
let internal myInternalObj = new MyInternalType()

let result = myInternalObj.Z


Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
Private Access Within Namespace Declaration Groups

private indicates that the entity can be accessed only from the enclosing type or module or namespace declaration group.

Access Control for Records

The F# Language Reference does not mention access control for record fields. While it is not allowed to use access modifiers for individual record fields, it is allowed to use an access modifier for all fields together:

    type public Point = internal { x : float; y: float; z: float; }

Access Control for Discriminated Unions

The F# Language Reference does not mention access control for discriminated unions. While it is not allowed to use access modifiers for individual union cases, it is possible to use an access modifier for all union cases together:

type public Expression =
    internal
    | Number of int
    | Add of Expression * Expression
    | Multiply of Expression * Expression
    | Variable of string

Access Control for Constructors

The F# Language Reference does not mention access control for constructors. A constructor's access defaults to the access of its enclosing type. It can be modified using a constructor access specifier, even if the constructor is implicit:

// Access specifier on implicit constructor.
type internal MyType private() = class end

// Access specifier on explicit constructor.
type internal MyType2 = private new() = {}

// Example: A Singleton based on implicit construction.
type internal MySingleton private() =
static let instance = MySingleton()
static member Instance = instance