Home

Introduction to Classes

 

Fundamentals of Classes

 

Introduction to Classes

A class is the frame work used to describe an object. The frame uses a list where each item describes a particular aspect. For example, a class used to describe a car for the motor vehicle office would have such items as the tag number, the make, the model, the year, etc.

To create a class, start with the following formula:

type Name =

After the equal sign, create the list of characteristics, each as a member:

type Name =
    Member 1
    Member 2
    . . .
    Member n

There are various types of members and we will see what they are. As an option, you can include the list of members between class and end. This can be done as follows:

type Name =
    class
	Member 1
	Member 2
	. . .
	Member n
    end

Introduction to the Members of a Class

The most fundamental member of a class appears as regular variable. The fundamental formula to create a member is:

member [ this | self-identifier | class-name ].member-name = data-type

You start with the member keyword. This is followed by one of the following:

  • The this keyword
  • A selft-identifier: This can be any letter of the aalphabet or any word of your choice. If you decide to use a word, you can start in uppercase or lowercase followed by letters, digits, and/or underscores
  • The name of the class

This is followeed by a period and the name of the member. Although you can use lowercase, the name should start in uppercase. The name is followed by = and the desired data type. Here are examples of members:

type Vehicle =
    member this.TagNumber = string
    member this.Make = string
    member this.Model = string
    member this.Year = int

Remember that you can include the body of the class between class and end. The above example can be written as follows:

type Vehicle =
    class
	member this.TagNumber = string
	member this.Make = string
	member this.Model = string
	member this.Year = int
    end

Class Construction

 

Introduction

In our introduction, we mentioned that a class is a technique to lay a foundation for, or to describe, an object. To start such a foundation, you must use a special member function that holds the primary characteristics of the object. That special function is called a constructor.

To create a constructor, add the parentheses to the name of the class. Here is an example:

type Vehicle() =
    member this.TagNumber = string
    member this.Make = string
    member this.Model = string
    member this.Year = int

The Default Constructor of a Class

If you add the parentheses to the name of a class but leave those parentheses empty, the class ic said to have a primary constructor. That is one way to create a default constructor. An alternative is not to add empty parentheses to the class name but add a member function named new, add empty parentheses to it, and assign the name of the class with empty parentheses to it. Here is an example:

type Vehicle =
    member this.TagNumber = string
    member this.Make = string
    member this.Model = string
    member this.Year = int

    new() = Vehicle()

Details on Creating Constructors

Instead of just one parameter, you can create a constructor that has as many parameters as you want. If you want to use more than one parameter, separate them with commas in the parentheses of the name of the class. Here is an example:

type Vehicle(tag, make, model) =
    class
	. . . Members
    end

If you want, or to be more explicit, you can (should) specify the data types of the parameters. Here are examples:

type Vehicle(tag : string, make : string, model : string) =
    class
	. . . Members
    end

As an alternative, you can create a constructor using a new member function and assign to it the constructor created on the name of the class. There are rules you must follow:

  • If the name of the class has empty parentheses, this means that a default constructor is defined. You cannot create an additional default constructor. This means that you cannot add a new() member function that has empty parentheses
  • If at least one parameter is already passed to the name of the class, this means that the class doesn't have a default constructor anymore. You can then create a parameter-less new() constructor, which would now act as the default constructor. Here is an example:
    type Vehicle(tag : string, make : string, model : string) =
        . . .
        new() = Vehicle()
  • You can add as many new() constructors as you want as long as each has a different number of parameters (than the others), including the one created using the name of the class.

    To add a new constructor using the new() member function, pass the desired number of parameters to both that new() member function and the class name assigned to it. In the parentheses of that class name, you must pass the number of parameters greater than or equal to the number of parameters of the new() constructor:
    • If the assigned class name has the same number of parameters as the new() constructor, the compiler will assign the parameters based on their positions. Here is an example:
      type Vehicle(tag : string, make : string, model : string) =
      
          . . .
      
          new() = Vehicle()
      
          new(tag, make) = Vehicle(tag, make)
    • If the assigned class name has more parameters than the new() constructor, you must specify how the extra parameter(s) will get its (their) value(s). One way to take care of this is to assign a default value to each extra parameter (of course, there are other ways we will see). Here is an example:
type Vehicle(tag : string, make : string, model : string) =

    . . .
    new() = Vehicle()

    new(tag, make) = Vehicle(tag, make)

    new(tag : string, make : string, model : string, yr : int) = Vehicle(tag, make, model, yr = 1900)

Using a Class

A class is meant to handle assignments and/or perform actions. Therefore, a class must be able to get values from outside and make its members available to the outside world. The role of the constructor(s) is to take care of such interactions. For example, a class can get values and use (or transform) them internally. To introduce an outside value to the members of a class, you can take it from a parameter of a constructor of the class. You can then assign that parameter to the appropriate member of the class. Here is an example:

type Vehicle(tag : string) =
    member this.TagNumber = tag

In the same way, you can create a contructor that takes as many members as necessary, add as members as necessary to the class and assign the corresponding constructors parameters to the appropriate members. Here are examples:

type Vehicle(tag : string, make : string, model : string, yr : int) =
    member this.TagNumber = tag
    member this.Make = make
    member this.Model = model
    member this.Year = yr

Remember that you can create different constructors using the new member function with different numbers of parameters. Here are examples:

type Vehicle(tag : string, make : string, model : string, yr : int) =
    member this.TagNumber = tag
    member this.Make = make
    member this.Model = model
    member this.Year = yr
    new() = Vehicle()
    new(tag : string) = Vehicle(tag, "Unknown", "N/A", 1900)
    new(tag : string, yr : int) = Vehicle(tag, "Unknown", "N/A", yr)

Creating an Object

As mentioned already, a class provides only the description of an object. To actually create an object, you must declare a variable based on the class. This is done using the let operator, giving a name to the variable, and assigning a constructor of the class. You must call the appropriate constructor; that is, the constructor with the desired and appropriate number of parameters. Here is an example:

type Vehicle(tag : string, make : string, model : string, yr : int) =
    member this.TagNumber = tag
    member this.Make = make
    member this.Model = model
    member this.Year = yr
    new(tag : string) = Vehicle(tag, "Unknown", "N/A", 1900)
    new(tag : string, yr : int) = Vehicle(tag, "Unknown", "N/A", yr) 

let car = Vehicle("739248")

Optionally, you can precede the name of the ckass with the new operator. Here is an example:

let car = new Vehicle("739248")

If the class has different constructors, you can declare different variables assigning the right constructor to each variable. Here are examples:

type Vehicle(tag : string, make : string, model : string, yr : int) =
    member this.TagNumber = tag
    member this.Make = make
    member this.Model = model
    member this.Year = yr
    new(tag : string) = Vehicle(tag, "Unknown", "N/A", 1900)
    new(tag : string, yr : int) = Vehicle(tag, "Unknown", "N/A", yr) 

let car = new Vehicle("739248")

let small = new Vehicle("204958", 2005)
let suv = new Vehicle("297M660", "Honda", "Pilot", 2010)

Doing the Binding in a Class

F# provides a special mechanism to perform one or more actions when an object is created; that is, when a constructor is initially called to create an object. For example, that mechanism can be used to display the values of the object.

To perform one or more primary actions when an object is created, you start a section using the do keyword in the body of the class:

type Name =
    do Action(s)
	. . .

The action can be written just after do on the same line. Here is an example:

type Vehicle(tag : string, make : string, model : string, yr : int) =
    do printfn "Vehicle Information"

You can also create the action(s) on the next line. If you do, the code for the action(s) must be indented to the right of the do indentation. Here are examples:

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

As mentioned already, the do section is used to do some things when an object is accessed. This means that, after declaring a variable for the object, the code in the do section is immediately available. As a result,  you can use the action(s) in that section. In this case, the action displays the values of the object and you don't even have to do any special thing. Here is an example:

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

let suv = new Vehicle("929384", "Honda", "Accord", 2015)

This would produce:

Vehicle Information
Tag #: 929384
Make:  Honda
Model: Accord
Year:  2015

Press any key to continue . . .

Accessing the Members of a Class Outside the Class

To access the member of a class outside the class, type the name of the variable, followed by a period and the name of the member. Here is an example:

type Vehicle(tag : string) =
    member this.TagNumber = tag

let car = new Vehicle("739248")

printfn "Vehicle Information"
printfn "Tag #: %s" car.TagNumber

If the class has more members, you can access them in the same way. Here are examples:

type Vehicle(tag : string, make : string, model : string, yr : int) =
    member this.TagNumber = tag
    member this.Make = make
    member this.Model = model
    member this.Year = yr

let car = new Vehicle("927748", "Toyota", "Corolla", 2004)

printfn "Vehicle Information"
printfn "Tag #: %s" car.TagNumber
printfn "Make:  %s" car.Make
printfn "Model: %s" car.Model
printfn "Year:  %d" car.Year

Letting Class Members Bind

One of the primary characteristics of a class is to take care of its internal assignments (for example, a car must be able to move ahead or back without something outside directing it as to what to do). To handle such tasks, a class uses values to exchange among its members and its constructor(s). Because such values are not used outside the class, they are considered, and treated as, private. On the other hand, the class members that can be accessed outside the class are referred to as public.

To create a value that can be shared internally among the members of a class, you can declare a variable for it. Such a variable is declared using the let keyword. If you decide to add at least one let member in your class, you must create a primary constructor (which is done on the name of the class). Here is an example of a let member in a class:

type Owner() =
    let firstName = string

In the same way, you can create as many let members as you want.  Here are examples:

type Owner() =
    let firstName = string
    let lastName = string

Remember that a let variable is meant to be used internally inside the class. On the other hand, a member created as member this. can be accessed inside or outside the class. One of the ways you use private members is to internally define what they do.

Used internally, a let variable can get its value from a constructor of the class and possibly manipulate it. Here are examples of let variables getting initialized from parameters of a constructor:

type Owner(fn: string, ln : string) =
    let firstName = fn
    let lastName = ln

In a class, you can use a combination of let variables and variable members. If you do, the let variable(s) must come first. One way you can manipulate a (the) let variable(s) is to let a member variable use it (them). Here is an example where a member variable is used to combine the values of let variables:

type Owner(fn: string, ln : string) =
    let firstName = fn
    let lastName = ln
    member this.FullName = firstName + " " + lastName

As seen previously, to use an object, you can declare a variable for it, and then you can access the public members of the class. Here is an example:

type Owner(fn: string, ln : string) =
    let firstName = fn
    let lastName = ln
    member this.FullName = firstName + " " + lastName

let person = Owner("Ethan", "Hampone");
printfn "Vehicle Registration - Owner"
printfn "Owner Name: %s\n" person.FullName

This would produce:

Vehicle Registration - Owner
Owner Name: Ethan Hampone

Press any key to continue . . .

Remember that once you declare and initialise a let variable, its value cannot change. If you want a let variable whose value can change, declare it as mutable.

Introduction to the Methods of a Class

 

Overview

One of the most important aspects of a class is to perform actions. An action is performed using a  function created in the class. Such a function is called a member function or method.  The fundamental formula to create a method is:

member [ this | self-identifier | class-name ].method-name([parameter(s)) = body

The creation of a method starts with member. The role of the [ this | self-identifier | class-name ] section follows the decription we gave for member variables. That section is followed by a period and the name of the method. The name should start in uppercase. The name of the member function is folllowed by parentheses. If you need to pass arguments to the method, add them inside the parentheses. The parentheses are followed by = and the body of the method. The body is used to define what the method does. For example, you can use a method to display a sentence.  Here is an example:

type Vehicle =
    member this.Show() =
        printfn "Vehicle Information"

As seen previously, to access a method outside the class, declare a variable based on the class, using a let keyword, and initialize it using the name of the class. Here is an example:

type Vehicle(tag) =
    member this.TagNumber = tag

let car = Vehicle("204858");

When creating an object, you can also precede the name of the class with the new operator. Here is an example:

type Vehicle(tag) =
    member this.TagNumber = tag

let car = new Vehicle("204858");

One of the jobs a method can perform is to use another member of the class, such as to display the value of a member variable. Here is an example:

type Vehicle(tag) =
    member this.TagNumber = tag
    member this.Show() =
        printfn "Vehicle Information"
        printfn "Tag #: %s" this.TagNumber

let car = Vehicle("204858");

In the same way, you can create as many methods as you want and each can perform as many actions as necessary. Here is an example of a method that displays the values of the member variables of a class:

type Vehicle(tag : string, make : string, model : string, yr : int) =
    member this.TagNumber = tag
    member this.Make = make
    member this.Model = model
    member this.Year = yr
    member this.Show() =
        printfn "Vehicle Information"
        printfn "Tag #: %s" this.TagNumber
        printfn "Make:  %s" this.Make
        printfn "Model: %s" this.Model
        printfn "Year:  %d" this.Year

let car = Vehicle("204858", "Buick", "Verano", 2014);
car.Show();

Remember that you can use a combination of let binding and member variables. Here is an example:

type VehicleRegistration(fn: string, ln : string, tag : string, make : string, model : string, yr : int) =
    let firstName = fn
    let lastName = ln
    member this.FullName = firstName + " " + lastName
    member this.TagNumber = tag
    member this.Make = make
    member this.Model = model
    member this.Year = yr
    member this.Show() =
        printfn "Vehicle Information"
        printfn "Tag #: %s" this.TagNumber
        printfn "Make:  %s" this.Make
        printfn "Model: %s" this.Model
        printfn "Year:  %d\n" this.Year

let regist = VehicleRegistration("Ethan", "Hampone", "204858", "Buick", "Verano", 2014);
printfn "=- Vehicle Registration -="
printfn "Owner Name: %s" regist.FullName
regist.Show();

This would produce:

=- Vehicle Registration -=
Owner Name: Ethan Hampone
Vehicle Information
Tag #: 204858
Make:  Buick
Model: Verano
Year:  2014

Press any key to continue . . .

A Method With Parameters

To perform its operation(s), a method may require one or more values that would be supplied from outside the class. As done for functions, if you are passing just one parameter, write after the name of the method. Then, in the body of the method, use the parameter as you see fit. When calling the method outside the class, make sure you specify its object and pass the appropriate number and type(s) or argument(s). Here is an example:

type HotelRoom(number, roomType, rate) =
    member this.RoomNumber = number
    member this.RoomType = roomType
    member this.DailyRate = rate
    member this.CalculateInvoice days =
        float days * rate

let room = HotelRoom(104, "Bedroom", 95.50)
let days = 3
let total = room.CalculateInvoice days

printfn "Hotel Room"
printfn "-----------------------"
printfn "Room #:        %d" room.RoomNumber
printfn "Room Type:     %s" room.RoomType
printfn "Daily Rate:    %0.02f" room.DailyRate
printfn "Days:          %d" days
printfn "Total Invoice: %0.02f" total
printfn "-----------------------"

This would produce:

Hotel Room
-----------------------
Room #:        104
Room Type:     Bedroom
Daily Rate:    95.50
Days:          3
Total Invoice: 286.50
-----------------------
Press any key to continue . . .

If you want to indicate the type of the parameter, include it in parentheses with : and its type. Here is an example:

type HotelRoom(number, roomType, rate) =
    member this.RoomNumber = number
    member this.RoomType = roomType
    member this.DailyRate = rate
    member this.CalculateInvoice days =
        float days * rate

let room = HotelRoom(104, "Bedroom", 95.50)
let days = 3
let total = room.CalculateInvoice (days : int)

printfn "Hotel Room"
printfn "-----------------------"
printfn "Room #:        %d" room.RoomNumber
printfn "Room Type:     %s" room.RoomType
printfn "Daily Rate:    %0.02f" room.DailyRate
printfn "Days:          %d" days
printfn "Total Invoice: %0.02f" total
printfn "-----------------------"

A method can also take more than one parameter. As done for functions, make the list of parameters separated by empty spaces after the name of the method. Here is an example:

type HotelRoom(number, roomType, rate) =
    member this.RoomNumber = number
    member this.RoomType = roomType
    member this.DailyRate = rate
    member this.CalculateInvoice days phoneCharge discount =
        (float days * rate) + phoneCharge - (float days * rate * discount / 100.00)

let room = HotelRoom(104, "Bedroom", 95.50)
let days = 3
let phoneUse = 12.48
let total = room.CalculateInvoice 3 12.48 0.00

printfn "Hotel Room"
printfn "-----------------------"
printfn "Room #:        %d" room.RoomNumber
printfn "Room Type:     %s" room.RoomType
printfn "Daily Rate:    %0.02f" room.DailyRate
printfn "Days:          %d" days
printfn "Phone Charge:  %0.02f" phoneUse
printfn "Total Invoice: %0.02f" total
printfn "-----------------------"

This would produce:

Hotel Room
-----------------------
Room #:        104
Room Type:     Bedroom
Daily Rate:    95.50
Days:          3
Phone Charge:  12.48
Total Invoice: 298.98
-----------------------
Press any key to continue . . .

Named Arguments

When calling a method, you must provide the appropriate arguments in the order their parameters appear on the method. F# provides an alternative. When calling the method, you can specify the arguments in an order of your choice. To do that, when creating the method, include its parameters in the parentheses and separate with commas. Here is an example:

type HotelRoom() =
    member this.CalculateInvoice(days, phoneCharge, discountApplied, discountRate) =
        (float days * rate) + phoneCharge - (float days * rate * discount / 100.00)

When calling the method, instead of simply listing the values of its arguments, add some parentheses to the method call. In the parentheses, type the name of a parameter, followed by =, and followed by its value; separate them with commas. Here is an example:

type HotelRoom(number, roomType, rate) =
    member this.RoomNumber = number
    member this.RoomType = roomType
    member this.DailyRate = rate
    member this.CalculateInvoice(days, phoneCharge, discountApplied, discountRate) =
        if discountApplied = true then
            (float days * rate) + phoneCharge - (float days * rate * discountRate / 100.00)
        else
            (float days * rate) + phoneCharge

let room = HotelRoom(104, "Bedroom", 95.50)
let days = 3
let phoneUse = 12.48
let total = room.CalculateInvoice(discountApplied = true, days = 3, discountRate = 20.00, phoneCharge = 12.48)

printfn "Hotel Room"
printfn "-----------------------"
printfn "Room #:        %d" room.RoomNumber
printfn "Room Type:     %s" room.RoomType
printfn "Daily Rate:    %0.02f" room.DailyRate
printfn "Days:          %d" days
printfn "Phone Charge:  %0.02f" phoneUse
printfn "Total Invoice: %0.02f" total
printfn "-----------------------"

This would produce:

Hotel Room
-----------------------
Room #:        104
Room Type:     Bedroom
Daily Rate:    95.50
Days:          3
Phone Charge:  12.48
Total Invoice: 241.68
-----------------------
Press any key to continue . . .

If you decide to simply provide the arguments to the method without using the names of the parameters, you must still use the parentheses and provide the argumens in the order of their parameters.

You can use the same technique of named arguments in the parentheses of the constructor used to create an object when declaring such a variable. Here is an example:

type HotelRoom(number, roomType, rate) =
    member this.RoomNumber = number
    member this.RoomType = roomType
    member this.DailyRate = rate
    member this.CalculateInvoice(days, phoneCharge, discountRate) =
        (float days * rate) + phoneCharge - (float days * rate * discountRate / 100.00)

let room = HotelRoom(roomType = "Conference Room", rate = 98.80, number = 110)
let days = 1
let phoneUse = 0.00
let total = room.CalculateInvoice(days = 3, discountRate = 0.00, phoneCharge = 12.48)

printfn "Hotel Room"
printfn "-----------------------"
printfn "Room #:        %d" room.RoomNumber
printfn "Room Type:     %s" room.RoomType
printfn "Daily Rate:    %0.02f" room.DailyRate
printfn "Days:          %d" days
printfn "Phone Charge:  %0.02f" phoneUse
printfn "Total Invoice: %0.02f" total
printfn "-----------------------"

This would produce:

Hotel Room
-----------------------
Room #:        110
Room Type:     Conference Room
Daily Rate:    450.00
Days:          1
Phone Charge:  0.00
Total Invoice: 450.00
-----------------------
Press any key to continue . . .
 
   
 

Adding Uninitialized Members

 

Introduction

If you create a member variable using the let keyword, you must initiliaze that member variable. On the other hand, you can add a member variable that is not initialized. This is done using the val keyword. Here is an example:

type Customer =
    val FullName : string;

A val member brings a set of requirements to a class. Normally, to use a class, you must declare a variable from it, which is naturally done using the let keyword; but you must have a constructor for the class. You have many options.

Initializing Uninitialized Members

Remember that, if your class doesn't have a primary constructor, you can create one or more constructors using the new keyworkd. If you create a constructor that doesn't take a parameter, you must initialize the val member to its default value. For a natural number member, this would be 0. For a decimal number, this would be 0.00. For a Boolean variable, this would be true or false. For a string, this would be an empty string. Here is an example:

type Customer =
    val FullName : string;
    new() = { FullName = "" }

If you want to initialize the val variable, you must add a constructor that takes a parameter that corresponds to the val member. When initializing the val member variable, assign the parameter to it. Here is an example:

type Customer =
    val FullName : string;
    new() = { FullName = "" }
    new(name) = { FullName = name }

After doing this, you can access the val member outside the class after creating an object that using the constructor that takes a value for the val parameter. Here is an example:

type Customer =
    val FullName : string;
    new() = { FullName = "" }
    new(name) = { FullName = name }

let client = new Customer("Jessica Constance Bernstein");

printfn "Customer Name: %s\n" client.FullName;

This would produce:

Customer Name: Jessica Constance Bernstein

Press any key to continue . . .

In the same way, you can add as many val members as necessary. Remember to create a constructor that can be used to initialize the member(s) so it (they) can be accessed outside the class. Here are examples:

type Customer =
    val FullName : string;
    val PhoneNumber : string
    val EmailAddress : string
    new() = { FullName = ""; PhoneNumber = ""; EmailAddress = "" }
    new(name) = { FullName = name; PhoneNumber = ""; EmailAddress = "" }
    new(name, phone) = { FullName = name; PhoneNumber = phone; EmailAddress = "" }
    new(name, phone, email) = { FullName = name; PhoneNumber = phone; EmailAddress = email }

let client = new Customer("Jessica Constance Bernstein", "103-118-9274", "jcbern@email.net");

printfn "Customer Name: %s" client.FullName;
printfn "Phone Number:  %s" client.PhoneNumber;
printfn "Email Address: %s\n" client.EmailAddress;

Initializing With Default Values

An alternative to initialize a val member is to mark it as [<DefaultValue>]. The member must also be created as mutable and the class must have a primary key constructor. Here is an example:

type Customer() =
    [<DefaultValue>]
    val mutable FullName : string;

You should also create a method that can be called to initialize the val member. Such a method should take a parameter for the (or each) val member. In the body of the method, assign the parameter to the (or each) corresponding val member. Outside the class, access the method and pass a value for the (or each) parameter(s). Here is an example:

type Customer() =
    [<DefaultValue>]
    val mutable FullName : string;
    member this.Initializer(name : string) =
        this.FullName <- name;

let client = new Customer();
client.Initializer("Robert Zachary Cox");

printfn "Customer Name: %s\n" client.FullName;

This would produce:

Customer Name: Robert Zachary Cox

Press any key to continue . . .

In the same way, you can create as many val members as possible and include them in your method initializer.

Static Member Variables

 

Introduction

A variable declared from a class is also called an instance of the class. In the same way, you can declare various instances of the same class as necessary:

type Vehicle(tag : string, make : string, model : string, yr : int) =
    member this.TagNumber = tag
    member this.Make = make
    member this.Model = model
    member this.Year = yr

let sedan = new Vehicle("927748", "Toyota", "Corolla", 2004)
let suv = new Vehicle("297M660", "Honda", "Pilot", 2010)

Each one of these instances gives you access to the members of the class but each instance holds the particular values of the members of its instance. Consider the results of the following program:

type Vehicle(tag : string, make : string, model : string, yr : int) =
    member this.TagNumber = tag
    member this.Make = make
    member this.Model = model
    member this.Year = yr

let sedan = new Vehicle("927748", "Toyota", "Corolla", 2004)
let suv = new Vehicle("297M660", "Honda", "Pilot", 2010)

printfn "Vehicle Information"
printfn "-------------------------"
printfn "       Sedan\tSUV"
printfn "-------------------------"
printfn "Tag #: %s\t%s" sedan.TagNumber suv.TagNumber
printfn "Make:  %s\t%s" sedan.Make suv.Make
printfn "Model: %s\t%s" sedan.Model suv.Model
printfn "Year:  %d\t\t%d" sedan.Year suv.Year

This would produce:

Vehicle Information
-------------------------
       Sedan	SUV
-------------------------
Tag #: 927748	297M660
Make:  Toyota	Honda
Model: Corolla	Pilot
Year:  2004		2010

All of the variables and members of classes we have used so far are referred to as instance members because, in order to access them, you must have an instance of a type or of a class declared where you want to access them.

In your application, you can declare a variable and refer to it regardless of which instance of an object you are using. Such a variable is called static. A static member of a class is internally accessed as soon as the program starts running. Because a static member is not tied to a particular instance of a class, a static member cannot use the this keyword.

A Static Variable

To declare a member variable of a class as static, type the static keyword on the left of let. Here is an example:

type Book() =
    static let title = string

In the same way, you can declare as many static member variables as you want in a class. Remember that let members are always private, so there is no reason to apply an access level to a static member.

Remember that, as soon as a class is accessed, which happens when you declare a variable for the class, the static member(s) is(are) available. As a result, not only do you not have to declare a variable of the class to access its member variable(s), but also once an object is created, its member(s) is(are) readily available.

Still, in a class, you can access a static member variable as you would a non-static member. If you plan to change the value of the variable, you should first declare it using the mutable keyword. Here is an example:

type Book() =
    static let mutable title : string = ""
    
    do
        title <- "Psychology and Human Evolution"
        printfn "Title: %s" title

let bk = new Book();

Any method of the class can also access a static member. Here is an example:

type Book() =
    static let mutable title : string = ""
    
    member this.Initialize() =
        title <- "Psychology and Human Evolution"
        printfn "Title: %s" title
        
let bk = new Book();

bk.Initialize()

In the same way, you can declare a combination of static and non-static variables as you see fit. Here is an example:

type Book() =
    static let mutable title : string = ""
    let mutable copyrightYear : int = 0
    
    member this.Initialize() =
        title <- "Psychology and Human Evolution"
        copyrightYear <- 2010
        
        printfn "Title:          %s" title
        printfn "Copyright Year: %d" copyrightYear
        
let bk = new Book();

bk.Initialize()

Static Methods

 

Statically doing Something

We already know that the do keyword can be used to perform an operation in a class. The action(s) of the do section is(are) perform when you declare a variable for the class. If you want the action(s) to take place whether an object is formally created or not, precede the do keyword with static. The member variables accessed in the do section have to be static. Here is an example:

type Vehicle() =
    static let mutable tagNumber : string = ""
    static let mutable year : int = 1960
    
    static do
        tagNumber <- "929384" 
        year <- 2010
        
        printfn "Title: %s" tagNumber
        printfn "Year:  %d" year
        
let car = new Vehicle();

This would produce:

Title: 929384
Year:  2010

Of course, you can create different do and static do sections in your class. Here is an example:

type Vehicle() =
    static let mutable tagNumber : string = ""
    let mutable make : string = ""
    let mutable model : string = ""
    static let mutable year : int = 1960
    
    do
        make <-  "Honda"
        model <- "Accord"
        
        printfn "Make:  %s" make
        printfn "Model: %s" model
        
    static do
        tagNumber <- "929384" 
        year <- 2010
        
        printfn "Title: %s" tagNumber
        printfn "Year:  %d" year
        
let car = new Vehicle();

If you do this, the static do section would be accessed first. The above program would produce:

Title: 929384
Year:  2010
Make:  Honda
Model: Accord

A Static Method

Like a member variable, a method of a class can be defined as static. Such a method can access any member of the class but it depends on how the member was declared.

To create a static method, type the static keyword to the left of the member keyword. Remember that the method cannot use the this keyword. Here is an example:

type Book() =
    
    static member Initialize() = . . .

As mentioned already, the way a static method accesses a member variable depends on how the member was created. Static members are directly accessible in the body of a static method, with just the name of the static member. Here is an example:

type Book() =
    static let mutable title : string = ""
    
    static member Initialize() =
        title <- "Psychology and Human Evolution"

        printfn "Title: %s" title

Outside the class, to access a static member, don't declare a variable for the class. Simply use the name of the class and access the static method using the period operator. Here is an example:

type Book() =
    static let mutable title : string = ""
    
    static member Initialize() =
        title <- "Psychology and Human Evolution"

        printfn "Title:          %s" title 
       
let bk = new Book();

Book.Initialize()

Static Classes

Like a variable or a method, a class can be considered static. A static class is a class whose members are accessed without creating an instance of the class. Also, all members of a static class are created as static.

 
 
   
 

Previous Copyright © 2012-2015 FunctionX Next