Home

Classes Fundamentals

 

Fundamentals of Classes

 

Introduction

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 characteristics as the tag number, the make, the model, the year, etc.

To create a class, start with the following formula:

type Name =

Introduction to the Members of a Class

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

type Name =
    Member1
    Member2
    . . .
    Member_n

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

type Name =
    class
	Member1
	Member2
	. . .
	Member_n
    end

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

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

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

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

This is followed 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.Color = string
    member this.Doors = 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.Color = string
	member this.Doors = int
    end

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() =
    member this.Color = string
    member this.Doors = int

let car = new Vehicle()

car.Make

If the class has more members, you can access them in the same way.

Introduction to the Methods of a Class

Besides the ability to be described, an object can perform actions. An action of an object is performed by a member function called a method. Like a property, a member function, called a method of a class, is created in the body of the class.

The fundamental formula to create a method is:

member [ this | method-name(parameter) = body

As mentioned for the members of a class, you start with the member keyword. This is followed by either the this keyword or a name (an identifier) of your choice. This is followed by a period and the name of the method. The name of a method starts in uppercase. The name is followed by the parentheses of a normal function. Here is an example:

type Creator() =
    member this.Create() . . .

Introduction to the Properties of a Class

In our introduction, we saw that a class is a list of characteristics that describe an object. A characteristic of an object is actually called a property.

The fundamental formula to create a property is:

member val property-name = constructor-parameter

You start with the member val expression. This is followed by a name for the property. To complete the creation of the property, assign a parameter from the constructor to it. Here is an example:

type Vehicle(manufacturer) =
    member val Make = manufacturer

After doing this, you can then access the property outside the class. Here is an example:

type Vehicle(manufacturer) =
    member val Make = manufacturer

let car = new Vehicle("Toyota")

car.Make

Of course, you can access the property inside the class. To do this, precede it with this.. Here is an example:

open System
open System.Windows.Forms

type Creator(title) =
    member val Title = title
    member this.Create() =
        let exercise = new Form()
        exercise.Text <- this.Title

        Application.Run exercise

let app = new Creator("Application Development Environment")

app.Create()

Letting Class Members Bind

One of the primary characteristics of a class is to take care of its internal assignments. 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 (or member followed by an identifier of your choice) 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.

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.

     
 

A Class as a Data Type

 

Introduction

A class is primarily a data type. As such, it shares all of the characteristics of variables of primitive types. For example, you can create various objects using one let keyword. Here is an example:

open System
open System.Windows.Forms

type Employee = {
    EmployeeNumber : string
    FirstName      : string
    LastName       : string
    HourlySalary   : float }

type EmployeePayroll(hSalary, tWorked) =
    let sal = ref hSalary
    let tme = ref tWorked
    let overtimeSalary = !sal * 1.50

    member this.HourlySalary with get() = !sal and set(value) = sal := value
    member this.TimeWorked   with get() = !tme and set(value) = tme := value
    member this.RegularTime  with get() = if !tme <= 40.00 then !tme else 40.00
    member this.Overtime     with get() = if !tme <= 40.00 then 0.00 else !tme - 40.00
    member this.RegularPay   with get() = if !tme <= 40.00 then !sal * !tme else !sal * this.Overtime
    member this.OvertimePay  with get() = if !tme <= 40.00 then 0.00 else (!tme - 40.00) * !sal * 1.50
    member this.GrossSalary  with get() = this.RegularPay + this.OvertimePay

let empl80223840 = { EmployeeNumber = "8022-3840"; FirstName = "Mark";  LastName = "Plant";  HourlySalary = 24.55 }
let empl58402497 = { EmployeeNumber = "5840-2497"; FirstName = "Carol"; LastName = "Mylans"; HourlySalary = 16.25 }
let empl20817008 = { EmployeeNumber = "2081-7008"; FirstName = "Maria"; LastName = "Pappas"; HourlySalary = 22.75 }

// Creating various objects with one declaration
let payroll58402497, payroll20817008, payroll80223840 = new EmployeePayroll(empl58402497.HourlySalary, 36.50),
                                                        new EmployeePayroll(empl20817008.HourlySalary, 42.50),
                                                        new EmployeePayroll(empl80223840.HourlySalary, 38.00)

let payrollSummary = new Form(Width = 375, Height = 135, Text = "Payroll Summary")

let lbxPayrollSummary = new ListBox(Left = 12, Top = 12, Width = 340, Height = 88)

lbxPayrollSummary.Items.Add("Hourly\tTime\tRegular\tOvertime\tRegular\tOvertime\tGross") |> ignore
lbxPayrollSummary.Items.Add("Salary\tWorked\tTime\tTime\tPay\tPay\tPay") |> ignore
lbxPayrollSummary.Items.Add(sprintf "%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" payroll80223840.HourlySalary payroll80223840.TimeWorked payroll80223840.RegularTime payroll80223840.Overtime payroll80223840.RegularPay payroll80223840.OvertimePay payroll80223840.GrossSalary) |> ignore
lbxPayrollSummary.Items.Add(sprintf "%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" payroll20817008.HourlySalary payroll20817008.TimeWorked payroll20817008.RegularTime payroll20817008.Overtime payroll20817008.RegularPay payroll20817008.OvertimePay payroll20817008.GrossSalary) |> ignore
lbxPayrollSummary.Items.Add(sprintf "%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" payroll58402497.HourlySalary payroll58402497.TimeWorked payroll58402497.RegularTime payroll58402497.Overtime payroll58402497.RegularPay payroll58402497.OvertimePay payroll58402497.GrossSalary) |> ignore

payrollSummary.Controls.Add lbxPayrollSummary

do Application.Run payrollSummary

This would produce:

A Class as a Data Type

Mutable Objects

Since classes are normal types, they support mutability, reference cells, and the ability to use the Ref record. Here are examples:

open System
open System.Windows.Forms

type Employee = {
    EmployeeNumber : string
    FirstName      : string
    LastName       : string
    HourlySalary   : float }

type EmployeePayroll(hSalary, tWorked) =
    let sal = ref hSalary
    let tme = ref tWorked
    let overtimeSalary = !sal * 1.50

    member this.HourlySalary with get() = !sal and set(value) = sal := value
    member this.TimeWorked   with get() = !tme and set(value) = tme := value
    member this.RegularTime  with get() = if !tme <= 40.00 then !tme else 40.00
    member this.Overtime     with get() = if !tme <= 40.00 then 0.00 else !tme - 40.00
    member this.RegularPay   with get() = if !tme <= 40.00 then !sal * !tme else !sal * this.Overtime
    member this.OvertimePay  with get() = if !tme <= 40.00 then 0.00 else (!tme - 40.00) * !sal * 1.50
    member this.GrossSalary  with get() = this.RegularPay + this.OvertimePay

let empl80223840 = { EmployeeNumber = "8022-3840"; FirstName = "Mark";      LastName = "Plant";    HourlySalary = 24.55 }
let empl58402497 = { EmployeeNumber = "5840-2497"; FirstName = "Carol";     LastName = "Mylans";   HourlySalary = 16.25 }
let empl20817008 = { EmployeeNumber = "2081-7008"; FirstName = "Maria";     LastName = "Pappas";   HourlySalary = 22.75 }
let empl70428150 = { EmployeeNumber = "7042-8150"; FirstName = "Frank";     LastName = "Cranston"; HourlySalary = 35.44 }
let empl42958475 = { EmployeeNumber = "4295-8475"; FirstName = "Alexander"; LastName = "Fays";     HourlySalary = 22.75 }

// Creating various objects with one declaration
let payroll58402497, payroll20817008, payroll80223840, payroll70428150 = new EmployeePayroll(empl58402497.HourlySalary, 36.50),
                                                                         new EmployeePayroll(empl20817008.HourlySalary, 42.50),
                                                                         new EmployeePayroll(empl80223840.HourlySalary, 38.00),
                                                                         new EmployeePayroll(empl70428150.HourlySalary, 44.00)

let payrollSummary = new Form(Width = 460, Height = 230, Text = "Payroll Summary")

let lbxPayrollSummary = new ListBox(Left = 12, Top = 12, Width = 430, Height = 180)

lbxPayrollSummary.Items.Add("Employee\tHourly\tTime\tRegular\tOvertime\tRegular\tOvertime\tGross") |> ignore
lbxPayrollSummary.Items.Add("Number\t\tSalary\tWorked\tTime\tTime\tPay\tPay\tPay") |> ignore
lbxPayrollSummary.Items.Add(sprintf "%s\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" empl80223840.EmployeeNumber payroll80223840.HourlySalary payroll80223840.TimeWorked payroll80223840.RegularTime payroll80223840.Overtime payroll80223840.RegularPay payroll80223840.OvertimePay payroll80223840.GrossSalary) |> ignore
lbxPayrollSummary.Items.Add(sprintf "%s\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" empl20817008.EmployeeNumber payroll20817008.HourlySalary payroll20817008.TimeWorked payroll20817008.RegularTime payroll20817008.Overtime payroll20817008.RegularPay payroll20817008.OvertimePay payroll20817008.GrossSalary) |> ignore
lbxPayrollSummary.Items.Add(sprintf "%s\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" empl58402497.EmployeeNumber payroll58402497.HourlySalary payroll58402497.TimeWorked payroll58402497.RegularTime payroll58402497.Overtime payroll58402497.RegularPay payroll58402497.OvertimePay payroll58402497.GrossSalary) |> ignore

// Creating a Mutable Object
let mutable pay = new EmployeePayroll(empl20817008.HourlySalary, 46.00)
lbxPayrollSummary.Items.Add(sprintf "%s\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" empl20817008.EmployeeNumber pay.HourlySalary pay.TimeWorked pay.RegularTime pay.Overtime pay.RegularPay pay.OvertimePay pay.GrossSalary) |> ignore

// Creating a Mutable Object
pay <- new EmployeePayroll(empl80223840.HourlySalary, 38.50)
lbxPayrollSummary.Items.Add(sprintf "%s\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" empl80223840.EmployeeNumber pay.HourlySalary pay.TimeWorked pay.RegularTime pay.Overtime pay.RegularPay pay.OvertimePay pay.GrossSalary) |> ignore

// Using a Reference Cell
let payment = ref (new EmployeePayroll(payroll70428150.HourlySalary, 48.50))
lbxPayrollSummary.Items.Add(sprintf "%s\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" empl70428150.EmployeeNumber (!payment).HourlySalary (!payment).TimeWorked (!payment).RegularTime (!payment).Overtime (!payment).RegularPay (!payment).OvertimePay (!payment).GrossSalary) |> ignore

// Using a Reference Cell
payment := new EmployeePayroll(empl58402497.HourlySalary, 45.50)
lbxPayrollSummary.Items.Add(sprintf "%s\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" empl58402497.EmployeeNumber (!payment).HourlySalary (!payment).TimeWorked (!payment).RegularTime (!payment).Overtime (!payment).RegularPay (!payment).OvertimePay (!payment).GrossSalary) |> ignore

// Usig the Ref Record
let wages = ref (new EmployeePayroll(empl80223840.HourlySalary, 38.00))
lbxPayrollSummary.Items.Add(sprintf "%s\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" empl80223840.EmployeeNumber (!wages).HourlySalary (!wages).TimeWorked (!wages).RegularTime (!wages).Overtime (!wages).RegularPay (!wages).OvertimePay (!wages).GrossSalary) |> ignore

(:=) wages (new EmployeePayroll(empl70428150.HourlySalary, 43.00))
lbxPayrollSummary.Items.Add(sprintf "%s\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" empl70428150.EmployeeNumber (!wages).HourlySalary (!wages).TimeWorked (!wages).RegularTime (!wages).Overtime (!wages).RegularPay (!wages).OvertimePay (!wages).GrossSalary) |> ignore

(:=) wages (new EmployeePayroll(payroll58402497.HourlySalary, 42.00))
lbxPayrollSummary.Items.Add(sprintf "%s\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" empl58402497.EmployeeNumber ((!) wages).HourlySalary ((!) wages).TimeWorked ((!)wages).RegularTime ((!) wages).Overtime ((!) wages).RegularPay ((!)wages).OvertimePay ((!) wages).GrossSalary) |> ignore

(:=) wages (new EmployeePayroll(payroll20817008.HourlySalary, 42.00))
// Using the members of the Ref record
lbxPayrollSummary.Items.Add(sprintf "%s\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" empl20817008.EmployeeNumber wages.Value.HourlySalary wages.Value.TimeWorked wages.Value.RegularTime wages.contents.Overtime wages.contents.RegularPay wages.contents.OvertimePay wages.contents.GrossSalary) |> ignore

payrollSummary.Controls.Add lbxPayrollSummary

do Application.Run payrollSummary

This would produce:

Mutable Objects

The Nullity of an Object

An object is said to be null if it exists but it doesn't have a meaningful value. In other words, the object has been created but it has not been given useable values. To allow a class to suppport nullity on its declarations, the class must be marked with an attribute named AllowNullLiteral. Here is an example:

[<AllowNullLiteral>]
type EmployeePayroll(hSalary, tWorked, pDate) =
	. . .

To support null values, the F# language provides the null keyword. The primary way to create a null object is to declare a variable without initializing it with a known value. Instead, you can initialize it with null. Here is an example:

let payroll2081700807312015 : EmployeePayroll = null

As you know already, to be able to change the value of an object after it has been created, you should declare its variable as mutable. Here is an example:

let mutable payroll2081700807312015 : EmployeePayroll = null

payroll2081700807312015 <- new EmployeePayroll(empl20817008.HourlySalary, 42.50, "07/31/2015")

After doing this, you can use the variable as you see fit.

Classes and Conditional Statements

Like values of primitive types, objects of classes can be involved in conditional statements. You can use the = operator to find out whether an object is null, or you can use the <> operator to find whether an object is not null. Here is an example:

let mutable payroll8022384007312015 : EmployeePayroll = null

payroll8022384007312015 <- new EmployeePayroll(empl20817008.HourlySalary, 44.50, "07/31/2015")

if payroll8022384007312015 <> null then
    lbxPayrollSummary.Items.Add(sprintf "%s\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" empl80223840.EmployeeNumber payroll8022384007312015.HourlySalary payroll8022384007312015.TimeWorked payroll8022384007312015.RegularTime payroll8022384007312015.Overtime pay.RegularPay payroll8022384007312015.OvertimePay payroll8022384007312015.GrossSalary) |> ignore

A better alternative is to use a matching pattern where one of the options is null in which case the object is null. The other option would be the underscore wildcard which indicates that the object holds a value. Here is an example:

let mutable payroll8022384007312015 : EmployeePayroll = null

payroll8022384007312015 <- new EmployeePayroll(empl20817008.HourlySalary, 44.50, "07/31/2015")

match payroll8022384007312015 with
| null -> ()
| _ -> lbxPayrollSummary.Items.Add(sprintf "%s\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f\t%0.02f" empl80223840.EmployeeNumber payroll8022384007312015.HourlySalary payroll8022384007312015.TimeWorked payroll8022384007312015.RegularTime payroll8022384007312015.Overtime pay.RegularPay payroll8022384007312015.OvertimePay payroll8022384007312015.GrossSalary) |> ignore
   
   
 

Home Copyright © 2009, 2015 FunctionX Home