Basics 20 - Namespaces and Modules
Both namespaces and modules are used for organizing the code in a hierarchical, logical way.
Namespaces
Namespaces can contain:
Nested namespaces
Modules
Types
Modules
Modules are compiled to static classes
in .NET. All values and functions which are part of a module are compiled to static
members.
Modules can contain:
Sub-modules
Types
Values
Functions
Examples
The Typical Case
This is the most common case, namespace and module are declared.
// Program.fs
// NsName
namespace NsName
// NsName.ModuleName
module ModuleName =
// NsName.ModuleName.main
[<EntryPoint>]
let main args = 0
No Namespace or Module Declaration
When no namespace or module is declared at the top, the file contents are assumed to be part of one module. Module name becomes filename (without .fs) with the first letter capitalized.
Please note, this provision is available only for the last file in the F# project. For all the other files, you need namespace + module declaration or module declaration at the top.
// someCode.fs
// SomeCode.x
let x args = 0
// SomeCode.y
let y args = 0
// SomeCode.Mod
module Mod =
// SomeCode.Mod.x
let x args = 0
// SomeCode.Mod.y
let y args = 0
Combining Namespace and Module Declaration
The syntax module <Namespace name>.<Module name>
is shorthand for combining namespace and module declaration. When using this syntax, there can be only one top-level module in the file. If you need multiple top-level modules in a file, declare the namespace and modules separately. Also notice no =
sign after module <Namespace name>.<Module name>
.
// Program.fs
// NsName.ModuleName
module NsName.ModuleName
// NsName.ModuleName.main
[<EntryPoint>]
let main args = 0
Multiple Top-Level Modules in a File
This is an example of having multiple top-level modules in one file.
// Program.fs
// NsName
namespace NsName
// NsName.Module1
module Module1 =
// NsName.Module1.add
let add x y = x + y
// NsName.Module2
module Module2 =
// NsName.Module2.main
[<EntryPoint>]
let main args = 0
Multiple Namespaces and Modules in a File
This is an example of having multiple namespaces and modules in one file.
// Program.fs
// NsName1
namespace NsName1
// NsName1.Module1
module Module1 =
// NsName1.Module1.add
let add x y = x + y
// NsName2
namespace NsName2
// NsName2.Module2
module Module2 =
// NsName2.Module2.main
[<EntryPoint>]
let main args = 0
Nested Namespaces
This is an example of nested namespaces.
// Program.fs
// NsName1
namespace NsName1
// NsName1.Module1
module Module1 =
// NsName1.Module1.add
let add x y = x + y
// NsName1.NsName2
namespace NsName1.NsName2
// NsName1.NsName2.Module2
module Module2 =
// NsName1.NsName2.Module2.main
[<EntryPoint>]
let main args = 0
Sub-Modules
This is an example of creating a sub-module.
// Program.fs
// NsName1
namespace NsName1
// NsName1.Module1
module Module1 =
// NsName1.Module1.add
let add x y = x + y
// NsName1.Module1.Module2
module Module2 =
// NsName1.Module1.Module2.main
[<EntryPoint>]
let main args = 0
Recurring Modules
The usage of the keyword rec
with module declaration allows all the members of the module to be mutually recursive. This is similar to a C# class body.
Won't work:
namespace NsName1
module Module1 =
let add x y = x + y
// Will not work as twoConstant isn't known
let add2 x = x + twoConstant
let twoConstant = 2
Will work:
namespace NsName1
module rec Module1 =
let add x y = x + y
// Will work
let add2 x = x + twoConstant
let twoConstant = 2
Opening Namespaces
The keyword open
is used to make the members of a namespace available at the file level.
This is without opening System
namespace.
namespace NsName1
module Module1 =
let addPi x = x + System.Math.PI
This is with opening System
namespace.
namespace NsName1
open System
module Module1 =
let addPi x = x + Math.PI
Opening Types
You can open types also with open type <type>
. This means all the static members of the given type are available at the file level.
namespace NsName1
open type System.Math
module Module1 =
let addPi x = x + PI
If you have reached so far, congratulations.
Keep reading!