Fundamentals of Namespaces

Introduction

Like a module, a namespace is a technique of creating a section of code to isolate names that can be uniquely identified even if some of those names are used somewhere else in a program. There are various differences between modules and namespaces. To point out those differences, we will review the features we saw for modules.

Creating a Namespace

To create a namespace, in a document, type the namespace keyword.

The Name of a Namespace

After the namespace keyword, type a name. The name of a namespace follows the rules of names of classes. Here is an example:

namespace Geometry
    ...

We will come back to issues about the name of a namespace.

Unlike a module, the creation of a namespace doesn't include the = sign.

The Body of a Namespace

After the name of the namespace, press Enter. The section on the the next line after the creation of a namespace is the body of the namespace. As a result, the formula to create a namespace is:

namespace namespace-name
    body

The Contents of a Namespace

Introduction

We already know that the first line of an F# code can contain the creation of a module or anything else, such as a function or a variable. Here is an example:

printfn "Welcome to the wonderful world of F#!";

module Exercise =
    printfn "F# is a functional programming language!!!";

This would produce:

Welcome to the wonderful world of F#!
F# is a functional programming language!!!

Press any key to continue . . .

In a document that contains the creation of a namespace, that creation must be the first line of code. As a result, the following code will fail:

printfn "Welcome to the wonderful world of F#!";

namespace . . .

A module can contain just about anything, including variables, functions, and classes, etc. Here is an example:

module CarDealer =
    type Vehicle(tag : string, make : string, model : string, yr : int) =
        do
            printfn "Vehicle Information"
            printfn "-------------------"
            printfn "Tag #: %s" tag
            printfn "Make:  %s" make
            printfn "Model: %s" model
            printfn "Year:  %d\n" yr

    let suv = new Vehicle("183048", "Toyota", "Rav4", 2010)

This would produce:

Vehicle Information
-------------------
Tag #: 183048
Make:  Toyota
Model: Rav4
Year:  2010

Press any key to continue . . .

Unlike a module, a namespace cannot contain variable declaration or direct call to functions. As a result, the following code will produce an error:

namespace CarDealer
    type Vehicle(tag : string, make : string, model : string, yr : int) =
        do
            printfn "Vehicle Information"
            printfn "-------------------"
            printfn "Tag #: %s" tag
            printfn "Make:  %s" make
            printfn "Model: %s" model
            printfn "Year:  %d\n" yr

    let suv = new Vehicle("183048", "Toyota", "Rav4", 2010)

This means that a namespace is a good place to create and organize classes. In a document, you can create as many namespaces as you want. Unlike modules, the body of a namespace doesn't have to be indented. Here is an example of a document with two namespaces:

namespace CommercialBank
type Employee =
    class
    end

namespace VehicleDealership
type Employee =
    class
    end

type Customer =
    class
    end

type Vehicle =
    class
    end

Nesting in a Namespace

One namespace can be nested in another namespace. Because all namespaces are created from the left side of the document, to indecate that a namespace is nested, you must qualify its name by indicating what its parent namespace(s) is (are). Here is an example:

namespace Mathematics
namespace Mathematics.Algebra // The Algebra namespace is nested in the Mathematics namespace
namespace Mathematics.Algebra.Elementary // The Elementary namespace is nested in the Algebra namespace that itself is nested in the Mathematics namespace
namespace Mathematics.Algebra.Equations // The Equations namespace is nested in the Algebra namespace that itself is nested in the Mathematics namespace 
namespace Mathematics.Arithmetic // The Arithmetic namespace is nested in the Mathematics namespace

You can then add the members anyway you want. To start, remember that a namespace cannot contain declared variables and functions but it can contain enumerations and classes. Here are examples:

namespace Mathematics
type Topics =       // The Topics enumeration is defined, or is a member of, the Mathematics namespace
    | Quantity
    | Structure
    | Space
    | Other
namespace Mathematics.Algebra // The Algebra namespace is nested in the Mathematics namespace
namespace Mathematics.Algebra.Elementary // The Elementary namespace is nested in the Algebra namespace that itself is nested in the Mathematics namespace
type Operator(o) = // The Operator class is a member of the Mathematics.Algebra.Elementary namespace
    class
    end
namespace Mathematics.Algebra.Equations // The Equations namespace is nested in the Algebra namespace that itself is nested in the Mathematics namespace
type Quadratic(a, b, c) = // The Quadratic class is defined, or is a member of, the Mathematics.Algebra.Equations namespace
    class
    end
namespace Mathematics.Arithmetic // The Arithmetic namespace is nested in the Mathematics namespace
type Number() = // The Number class is defined the Mathematics.Arithmetic namespace
    class
    end
type Addition(a, b) = // The Addition class is defined the Mathematics.Arithmetic namespace
    class
    end

Besides classes (and enumerations and some others), a namespace can contain modules. Here are examples:

namespace Mathematics
type Topics =       // The Topics enumeration is defined, or is a member of, the Mathematics namespace
    | Quantity
    | Structure
    | Space
    | Other
module Geometry =
    printfn "Geometry is the branch of mathematics that studies shapes, figures, and space."
    
    module Polygons =
        type Square() =
            member this.Describe() =
                printfn "A square is a quadrilateral with four equal sides and four equal angles of 90 degrees."
        type Triangle() =
            member this.Describe() =
                printfn "A triangle is a polygon that has three edges and three vertices."
    module Planes =
        type Circle(radius) =
            do
                printfn "A circle is a shape of all point that are at an equal distance from another point named the center."
        type Ellipse(largeRadius, smallRadius) =
            member this.Describe() =
                printfn "An ellipse is curved plane with two focal points."
module Trigonometry =
    type Triangle() =
        member this.Describe() =
            printfn "A triangle is a plane shape from three leveled points."

module Summary =
    printf "Triangular Polygon Definition: "
    let geo = Geometry.Polygons.Triangle()
    geo.Describe()
    printf "Trigonometric Triangle Definition: "
    let tri = Trigonometry.Triangle()
    tri.Describe()
namespace Mathematics.Algebra // The Algebra namespace is nested in the Mathematics namespace
namespace Mathematics.Algebra.Elementary // The Elementary namespace is nested in the Algebra namespace that itself is nested in the Mathematics namespace
    type Operator(o) = // The Operator class is a member of the Mathematics.Algebra.Elementary namespace
        class
        end
namespace Mathematics.Algebra.Equations // The Equations namespace is nested in the Algebra namespace that itself is nested in the Mathematics namespace
    type Quadratic(a, b, c) = // The Quadratic class is defined, or is a member of, the Mathematics.Algebra.Equations namespace
        class
        end
namespace Mathematics.Arithmetic // The Arithmetic namespace is nested in the Mathematics namespace
    type Number() = // The Number class is defined the Mathematics.Arithmetic namespace
        class
        end
    type Addition(a, b) = // The Addition class is defined the Mathematics.Arithmetic namespace
        class
        end

In fact, because a namespace cannot contain functions and variables, if you want to use them, you should (must) nest a module and create such code in that module.

To access a member of a namespace outside that namespace, you must fully qualify its name. Here are example:

module Geometry =
    printfn "Geometry is the branch of mathematics that studies shapes, figures, and space."
    
    module Polygons =
        type Square() =
            member this.Describe() =
                printfn "A square is a quadrilateral with four equal sides and four equal angles of 90 degrees."
        type Triangle() =
            member this.Describe() =
                printfn "A triangle is a polygon that has three edges and three vertices."
    module Planes =
        type Circle(radius) =
            do
                printfn "A circle is a shape of all point that are at an equal distance from another point named the center."
        type Ellipse(largeRadius, smallRadius) =
            member this.Describe() =
                printfn "An ellipse is curved plane with two focal points."
module Trigonometry =
    type Triangle() =
        member this.Describe() =
            printfn "A triangle is a plane shape from three leveled points."

module Summary =
    printf "Triangular Polygon Definition: "
    let geo = Geometry.Polygons.Triangle()
    geo.Describe()
    printf "Trigonometric Triangle Definition: "
    let tri = Trigonometry.Triangle()
    tri.Describe()

This would produce:

Geometry is the branch of mathematics that studies shapes, figures, and space.
Triangular Polygon Definition: A triangle is a polygon that has three edges and three vertices.
Trigonometric Triangle Definition: A triangle is a plane shape from three leveled points.

Press any key to continue . . .

Referring to Members of a Namespace

Outside a namespace, to refer to (one of) its member(s), you must fully qualify the name of that member from its parent(s). From the above example, to access the Quadratic class, you start from the most top namespace followed by each child namespace. This would be:

Mathematics.Algebra.Equations.Quadratic

Here is an example of using a class that is a member of a namespace:

namespace Mathematics
namespace Mathematics.Algebra
namespace Mathematics.Algebra.Equations
type Quadratic(a, b, c) =
    let mutable x = ""
    let mutable y = ""
    let mutable z = ""
    do
        if a < -1 then
            x <- (string a) + "x^2"
        elif a = -1 then
            x <- "-x^2"
        elif a = 0 then
            x <- ""
        elif a = 1 then
            x <- "x^2"
        elif a > 1 then
            x <- (string a) + "x^2"
        else
            x <- (string a) + "x^2"
    
        if b < -1 then
            y <- "- " + (string (-1 * b)) + "x"
        elif b = -1 then
            y <- "- x"
        elif b = 0 then
            y <- ""
        elif b = 1 then
            y <- "+ x"
        elif b > 1 then
            y <- "+ " + (string b) + "x"
        else
            y <- "+ " + (string b) + "x"

        if c < -1 then
            z <- "- " + (string (-1 * c))
        elif c = -1 then
            z <- "- " + (string (-1 * c))
        elif c = 0 then
            z <- ""
        else
            z <- "+ " + (string (c))

    member this.Equation with get() : string = (x + " " + y + " " + z + " = 0")

namespace ElementaryAlgebra

module Exercise =
    let quad = Mathematics.Algebra.Equations.Quadratic(5, 1, -1) // (1, -3, 1) // (5, -3, 3) //(1, 2, -2);
    printfn "Equation: %s" quad.Equation

This would produce:

quation: 5x^2 + x - 1 = 0
ress any key to continue . . .

The Name of a Namespace . . . Again

As seen so far, when accessing a namespace, you use its whole ancestry. In fact, when creating a namespace, you can specify a lineage that you anticipate would be essential. Here is an example:

namespace Chemistry.Compounds.Reactions
    type Atom(a) =
        class
        end

After creating a namespace like this, you can access its members using the whole qualified name. Here is an example:

namespace Chemistry.Compounds.Reactions
    type Atom(a) =
        class
        end

namespace Studies
module Research =
    let t = Chemistry.Compounds.Reactions.Atom("O")

Based on this, you can specify a name of a namespace that includes various parts even if those parts don't exist. To resume, the name of a namespace can be in one word or it can include various parts separated by periods.

If you had created a name of a namespace and made it in different parts, if you want, somewhere else in the file, you can create namespaces that include some parts that were used in the original name. Here is an example:

namespace Chemistry.Compounds.Reactions
    type Atom(a) =
        class
        end

namespace Chemistry.Compounds
    type Substance(element1, element2) =
        class
        end

namespace Studies
module Research =
    let t = Chemistry.Compounds.Reactions.Atom("O")
    let c = Chemistry.Compounds.Substance("hydrogen", "helium")

Previous Copyright © 2014-2024, FunctionX Monday 14 February 2022 Next