Code is organised in namespaces (which hold types and modules) and modules (which hold values, functions, types and other modules). A module is compiled to a static .NET class; a namespace is a .NET namespace. How a file starts is on the file structure page.
Namespaces
namespace MyCompany.Shapes // may be spread over several files
type Circle = { Radius: float }
module Geometry =
let area (c: Circle) = System.Math.PI * c.Radius ** 2.0
namespace global // the top-level .NET namespace
A namespace cannot contain values or functions directly. Indentation is not significant in a namespace declaration. A nested namespace must be named in full (namespace A.B), or a new top-level namespace is created. namespace rec makes the whole group mutually recursive. global names the root, which also resolves clashes (global.System.String).
Modules
module MyApp.Utilities // a top-level module: the whole file
let double x = x * 2
module Strings = // a local module: indented
let shout (s: string) = s.ToUpper() + "!"
module Inner = // modules nest
let value = 42
[<RequireQualifiedAccess>]
module Colour =
let red = 1
let green = 2
[<AutoOpen>]
module Prelude =
let inline (|>!) x f = f x; x
module S = MyApp.Utilities.Strings // a module abbreviation
- A module holds
letvalues and functions, types, exceptions, other modules anddoactions. Values are initialised in order when the file is first used (see static initialisation). [<RequireQualifiedAccess>]: callers must writeColour.red, even afteropen(used for modules whose names would clash, likeListandOption).[<AutoOpen>]: the module’s contents are available where the enclosing namespace or module is opened. On an assembly ([<assembly: AutoOpen("Name")>]) it opens a namespace for everything that references the assembly.- A module with the same name as a type in the same namespace gets a
Modulesuffix in its .NET name automatically (F# 4.1); older code wrote[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]for that. module recmakes everything in the module mutually recursive;module M = A.B.Cgives a module another name.- The values of a module can be reached by their full path (
MyApp.Utilities.double) or afteropen.
Open
open System
open System.Collections.Generic
open type System.Math // F# 5: the static members of a type
open MyApp.Utilities
let d = Dictionary<string, int>()
let r = Sqrt 2.0 // from open type
open lasts to the end of the enclosing namespace, module or file; each goes on its own line.When two opened modules or namespaces define the same name, the later open wins, silently, so avoid opening List and Seq together. An open that is not needed gives an editor hint, not an error. open can only name a namespace, a module or (with type) a type that the project or a reference provides.
Access control
| Word | Visible to |
|---|---|
public (the default) | every caller |
internal | the same assembly |
private | the enclosing type or module |
The word goes in front of the name: let private helper x = …, type internal Cache = …, member private this.F() = …, module internal Util, type C private () = … (a private constructor). The default is public, except that let bindings inside a type are always private to it. inherit and interface declarations and abstract members have the accessibility of the type; a union case or record field is as accessible as its type. protected is not used in F#, although it is accepted when the types come from other .NET languages; F# 11 lets a derived member read a protected base field inside an ordinary closure.
A signature file is the other way to control access: only what the .fsi shows is visible outside the file (see file structure).
Not described
Known, not yet covered
- Reference: the exact accessibility of
privateon a type in a namespace (the documentation says “the enclosing type or module”; how that works for a type directly in a namespace was not checked), the name resolution order of opened modules,[<AutoOpen>]on assemblies in detail, the rules for module suffixes, and the details ofnamespace recandmodule rec(initialisation order of recursive values gives warnings). - Reference: the access-control, open and namespace pages were read; the modules page was read for its summary and recursive-module notes only. The examples were not compiled.
See also
- File structure – how a file starts and the compilation order
- Classes and objects – access on members