Returning an Object from a Function

Introduction

A function can be made to return an object of a class type (in the body of the function, you can declare any variable(s) you want). Of course, you must know the class of the object you want to return. You can use an existing/built-in class or you can create your own. When defining the function, make sure its last statement indicates an object. Outside the function, you can call it, get its return value, and use it as you see fit, such as displaying the values of its properties and calling its methods. Here is an example where the last line of the function specifies that it is returning a variable that was declared locally:

type Employee() =
    let mutable emplNbr = ""
    let mutable fn = ""
    let mutable ln = ""
    let mutable sal  = 0.00
    member this.EmployeeNumber with get() = emplNbr and set(value) = emplNbr <- value
    member this.FirstName with get() = fn and set(value) = fn <- value
    member this.LastName with get() = ln and set(value) = ln <- value
    member this.HourlySalary with get() = sal and set(value) = sal <- value

let createEmployeeRecord() =
    let empl : Employee = Employee()
    empl.EmployeeNumber <- "2080-4813"
    empl.FirstName <- "James"
    empl.LastName <- "Alexanders"
    empl.HourlySalary <- 22.25
    empl

let empl = createEmployeeRecord()

printfn "Employee Payroll Summary"
printfn "----------------------------------------------------"
printfn "Employee #:    %s" empl.EmployeeNumber
printfn "Full Name:     %s %s" empl.FirstName empl.LastName
printfn "Hourly Salary: %0.02F" empl.HourlySalary
printfn "----------------------------------------------------"

This would produce:

Employee Payroll Summary
----------------------------------------------------
Employee #:    2080-4813
Full Name:     James Alexanders
Hourly Salary: 22.25
----------------------------------------------------
Press any key to continue . . .

Returning a New Object

Instead of declaring a local variable, if the class has one or more constructors, you can use it/them in the last line and pass the desired or appropriate arguments to indicate the return value. Here is an example:

type Employee(emplNbr, fname, lname, salary) =
    member val EmployeeNumber = emplNbr with get, set
    member val FirstName = fname with get, set
    member val LastName = lname with get, set
    member val HourlySalary = salary with get, set

let createEmployeeRecord() =
    let emplNbr = "2080-4813"
    let fn = "James"
    let ln = "Alexanders"
    let sal = 22.25
    new Employee(emplNbr, fn, ln, sal)

let empl = createEmployeeRecord()

printfn "Employee Payroll Summary"
printfn "----------------------------------------------------"
printfn "Employee #:    %s" empl.EmployeeNumber
printfn "Full Name:     %s %s" empl.FirstName empl.LastName
printfn "Hourly Salary: %0.02F" empl.HourlySalary
printfn "----------------------------------------------------"

Although F# is an inferred language, if you want to indicate the return type of a function, type : and the type before the = symbol. Here is example:

type Employee(emplNbr, fname, lname, salary) =
    member val EmployeeNumber = emplNbr with get, set
    member val FirstName = fname with get, set
    member val LastName = lname with get, set
    member val HourlySalary = salary with get, set

let createEmployeeRecord() : Employee =
    let emplNbr = "2080-4813"
    let fn = "James"
    let ln = "Alexanders"
    let sal = 22.25
    new Employee(emplNbr, fn, ln, sal)

let empl = createEmployeeRecord()

printfn "Employee Payroll Summary"
printfn "----------------------------------------------------"
printfn "Employee #:    %s" empl.EmployeeNumber
printfn "Full Name:     %s %s" empl.FirstName empl.LastName
printfn "Hourly Salary: %0.02F" empl.HourlySalary
printfn "----------------------------------------------------"

You can also pass additional parameters, such as those of primitive types, to the function and use them in the body of the function as you see fit. Here is an example:

type Employee(emplNbr, fname, lname, salary) =
    member val EmployeeNumber = emplNbr with get, set
    member val FirstName = fname with get, set
    member val LastName = lname with get, set
    member val HourlySalary = salary with get, set

let createEmployeeRecord nbr first last salary : Employee =
    new Employee(nbr, first, last, salary)

let empl = createEmployeeRecord "2080-4813" "James" "Alexanders" 22.25
    
printfn "Employee Payroll Summary"
printfn "----------------------------------------------------"
printfn "Employee #:    %s" empl.EmployeeNumber
printfn "Full Name:     %s %s" empl.FirstName empl.LastName
printfn "Hourly Salary: %0.02F" empl.HourlySalary
printfn "----------------------------------------------------"

An Object as Parameter

A function can be defined to take an object as parameter. In this case, when creating the function, you should specify the data type of the parameter. In the body of the function, use the parameter as you see fit. Here is an example:

type Employee(emplNbr, fname, lname, salary) =
    let mutable nbr = emplNbr
    let mutable fn  = fname
    let mutable ln  = lname
    let mutable sal  = salary
    member this.EmployeeNumber with get() = nbr and set(value) = nbr <- value
    member this.FirstName with get() = fn and set(value) = fn <- value
    member this.LastName with get() = ln and set(value) = ln <- value
    member this.HourlySalary with get() = sal and set(value) = sal <- value

let createEmployeeRecord() : Employee =
    Employee("2080-4813", "James", "Alexanders", 22.25)

let present (empl : Employee) =
    printfn "Employee Payroll Summary"
    printfn "----------------------------------------------------"
    printfn "Employee #:    %s" empl.EmployeeNumber
    printfn "Full Name:     %s %s" empl.FirstName empl.LastName
    printfn "Hourly Salary: %0.02F" empl.HourlySalary
    printfn "----------------------------------------------------"

let empl = createEmployeeRecord()
present empl

Besides the object from class, you can pass other parameters. Some can be based on primitive types. Here is an example:

type Employee(emplNbr, fname, lname, salary) =
    let mutable nbr = emplNbr
    let mutable fn  = fname
    let mutable ln  = lname
    let mutable sal  = salary
    member this.EmployeeNumber with get() = nbr and set(value) = nbr <- value
    member this.FirstName with get() = fn and set(value) = fn <- value
    member this.LastName with get() = ln and set(value) = ln <- value
    member this.HourlySalary with get() = sal and set(value) = sal <- value

let createEmployeeRecord() : Employee =
    Employee("2080-4813", "James", "Alexanders", 22.25)

let present (empl : Employee) mon tue wed thu fri =
    printfn "Employee Payroll Summary"
    printfn "----------------------------------------------------"
    printfn "Employee #:    %s" empl.EmployeeNumber
    printfn "Full Name:     %s %s" empl.FirstName empl.LastName
    printfn "Hourly Salary: %0.02F" empl.HourlySalary
    printfn "----------------------------------------------------"
    printfn "Pay Summary - Time Worked"
    printfn "Monday:    %0.02f" mon
    printfn "Tuesday:   %0.02f" tue
    printfn "Wednesday: %0.02f" wed
    printfn "Thursday:  %0.02f" thu
    printfn "Friday:    %0.02f" fri

let empl = createEmployeeRecord()
present empl 8.50 9.00 7.50 8.00 8.00

This would produce:

Employee Payroll Summary
----------------------------------------------------
Employee #:    2080-4813
Full Name:     James Alexanders
Hourly Salary: 22.25
----------------------------------------------------
Pay Summary - Time Worked
Monday:    8.50
Tuesday:   9.00
Wednesday: 7.50
Thursday:  8.00
Friday:    8.00
Press any key to continue . . .

You can also pass more than one object as parameter. The parameters can be of the same type or different types. Here is an example:

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4

type Employee(emplNbr, fname, lname, status, salary) =
    member val EmployeeNumber = emplNbr with get, set
    member val FirstName = fname with get, set
    member val LastName = lname with get, set
    member val Status = status with get, set
    member val HourlySalary = salary with get, set
    
    member this.Present() : unit =
        printfn "Employee Payroll Summary"
        printfn "----------------------------------------------------"
        printfn "Employee #:    %s" this.EmployeeNumber
        printfn "Full Name:     %s %s" this.FirstName this.LastName
        printfn "Status:        %A" this.Status
        printfn "Hourly Salary: %0.02F" this.HourlySalary
        printfn "----------------------------------------------------"

type Payroll() =
    let mutable emplNbr = ""
    let mutable mon  = 0.00
    let mutable tue  = 0.00
    let mutable wed  = 0.00
    let mutable thu  = 0.00
    let mutable fri  = 0.00
    member this.EmployeeNumber with get() = emplNbr and set(value) = emplNbr <- value
    member this.Monday    with get() = mon and set(value) = mon <- value
    member this.Tuesday   with get() = tue and set(value) = tue <- value
    member this.Wednesday with get() = wed and set(value) = wed <- value
    member this.Thursday  with get() = thu and set(value) = thu <- value
    member this.Friday    with get() = fri and set(value) = fri <- value

let validate (empl : Employee) (pay : Payroll) : bool =
    if empl.EmployeeNumber = pay.EmployeeNumber then
        true
    else
        false

let staff = Employee("7092-3094", "Rose", "Crittenden", EmploymentStatus.FullTime, 24.05)
let pay = Payroll()
pay.EmployeeNumber <- "2080-4813"
pay.Monday <- 22.25
pay.Tuesday <- 8.50
pay.Wednesday <- 9.50
pay.Thursday <- 8.00
pay.Friday <- 10.00

if validate staff pay = true then
    printfn "The payroll will be calculated"
else
    printfn "The information you provided for the employee and the payroll do not match"

You can also pass a combination of parameters of class types and primitive types. Here is an example:

 type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4

type Employee(emplNbr, fname, lname, status, salary) =
    member val EmployeeNumber = emplNbr with get, set
    member val FirstName = fname with get, set
    member val LastName = lname with get, set
    member val Status = status with get, set
    member val HourlySalary = salary with get, set
    
    member this.Present() : unit =
        printfn "Employee Payroll Summary"
        printfn "----------------------------------------------------"
        printfn "Employee #:    %s" this.EmployeeNumber
        printfn "Full Name:     %s %s" this.FirstName this.LastName
        printfn "Status:        %A" this.Status
        printfn "Hourly Salary: %0.02F" this.HourlySalary
        printfn "----------------------------------------------------"

type Payroll() =
    let mutable emplNbr = ""
    let mutable mon  = 0.00
    let mutable tue  = 0.00
    let mutable wed  = 0.00
    let mutable thu  = 0.00
    let mutable fri  = 0.00
    member this.EmployeeNumber with get() = emplNbr and set(value) = emplNbr <- value
    member this.Monday    with get() = mon and set(value) = mon <- value
    member this.Tuesday   with get() = tue and set(value) = tue <- value
    member this.Wednesday with get() = wed and set(value) = wed <- value
    member this.Thursday  with get() = thu and set(value) = thu <- value
    member this.Friday    with get() = fri and set(value) = fri <- value

let validate (empl : Employee) (pay : Payroll) salaryIsFixed : float =
    let mutable result = 0.00
    
    if empl.EmployeeNumber = pay.EmployeeNumber then
        if salaryIsFixed = true then
            result <- empl.HourlySalary * 40.00
        else
            result <- empl.HourlySalary * (pay.Monday + pay.Tuesday + pay.Wednesday + pay.Thursday + pay.Friday)
    else
        printfn "The information you provided for the employee and the payroll do not match"
    result
    
let staff = Employee("7092-3094", "Rose", "Crittenden", EmploymentStatus.FullTime, 24.05)
let pay = Payroll()
pay.EmployeeNumber <- "7092-3094"
pay.Monday <- 22.25
pay.Tuesday <- 8.50
pay.Wednesday <- 9.50
pay.Thursday <- 8.00
pay.Friday <- 10.00

printfn "Payroll Preparation"
printfn "------------------------"
printfn "Weekly Salary: %0.02f" (validate staff pay true)

This would produce:

Payroll Preparation
------------------------
Weekly Salary: 962.00
Press any key to continue . . .

Classes and Classes

A Property of a Class Type

As a class can be made a member variable of another class, it can also be created as a property. The formula is the exact same we have seen for properties of primitive types. Here are examples:

type Rectangle() =
    let mutable len = 0.00
    let mutable wd  = 0.00
    member this.Length with get() = len and set(value) = len <- value
    member this.Width with get() = wd and set(value) = wd <- value
    member this.Perimeter with get() = (len + wd) * 2.00
    member this.Area with get() = len * wd
    
type Circle() =
    let mutable radius = 0.00
    member me.Radius with get() = radius and set(value) = radius <- value
    member me.Diameter with get() = radius * 2.00
    member me.Circumference with get() = me.Diameter * 3.14156
    member me.Area with get() = radius * radius * 3.14156

type BasketballCourt() =
    let mutable external = new Rectangle()
    let mutable central  = new Circle()
    let mutable rar = 0.00
    let mutable rh = 0.00
    let mutable kw = 0.00
    let mutable ftld = 0.00
    let mutable b3pld = 0.00
    member sport.Court
    	with get() = external
    	and set(value) = external <- value
    member sport.Center
    	with get() = central
    	and set(value) = central <- value
    member sport.RestrictedArcRadius
    	with get() = rar
    	and set(value) = rar <- value
    member sport.RimHeight
    	with get() = rh
    	and set(value) = rh <- value
    member sport.KeyWidth
    	with get() = kw
    	and set(value) = kw <- value
    member sport.FreeThrowLineDistance
    	with get() = ftld
    	and set(value) = ftld <- value
    member sport.B3PointLineDistanceFromBasket
    	with get() = b3pld
    	and set(value) = b3pld <- value
   
let NBACourt = BasketballCourt()
let NBA = Rectangle()
NBA.Length <- 28.65
NBA.Width <- 15.24
NBACourt.Court <- NBA
NBACourt.RimHeight <- 3.05;
NBACourt.RestrictedArcRadius <- 1.22;
let courtCenter = Circle()
courtCenter.Radius <- 1.22;
NBACourt.Center <- courtCenter
NBACourt.B3PointLineDistanceFromBasket <- 1.22;
NBACourt.KeyWidth <- 4.88;
NBACourt.FreeThrowLineDistance <- 4.57;

printfn "Basketball Court"
printfn "_____________________________________________________"
printfn "Court Measures ______________________________________"
printfn "   Length:             %0.02f m" NBACourt.Court.Length
printfn "   Width:              %0.02f m" NBACourt.Court.Width
printfn "   Perimeter:          %0.02f m" NBACourt.Court.Perimeter
printfn "   Area:               %0.02f m" NBACourt.Court.Area
printfn "Central Circle Measures ____________________________"
printfn "   Radius:            %0.02f m" NBACourt.Center.Radius
printfn "   Diameter:          %0.02f m" NBACourt.Center.Diameter
printfn "   Circumference:     %0.02f m" NBACourt.Center.Circumference
printfn "   Area:              %0.02f m" NBACourt.Center.Area
printfn "____________________________________________________"
printfn "Restricted Arc Radius: %0.02f m" NBACourt.RestrictedArcRadius
printfn "3-Point Line Distance From Basket:  %0.02f m" NBACourt.B3PointLineDistanceFromBasket
printfn "Key Width (Shaded Lane or Restricted Area: %0.02f m" NBACourt.KeyWidth
printfn "Free-throw line distance from point on the floor directly below the backboard: %0.02f m" NBACourt.FreeThrowLineDistance
printfn "____________________________________________________"

This would produce:

Basketball Court
_____________________________________________________
Court Measures ______________________________________
   Length:             28.65 m
   Width:              15.24 m
   Perimeter:          87.78 m
   Area:               436.63 m
Central Circle Measures ____________________________
   Radius:            1.22 m
   Diameter:          2.44 m
   Circumference:     7.67 m
   Area:              4.68 m
____________________________________________________
Restricted Arc Radius: 1.22 m
3-Point Line Distance From Basket:  1.22 m
Key Width (Shaded Lane or Restricted Area: 4.88 m
Free-throw line distance from point on the floor directly below the backboard: 4
.57 m
____________________________________________________
Press any key to continue . . .

If the class that represents the property has an appropriate constructor, you can pass a parameter of that class to the constructor of your new class and use that argument in the property. Here are examples:

type Rectangle(length, width) =
    let mutable len = length
    let mutable wd  = width
    member this.Length with get() = length and set(value) = len <- value
    member this.Width with get() = width and set(value) = wd <- value
    member this.Perimeter with get() = (len + wd) * 2.00
    member this.Area with get() = len * wd
    
type Circle(radius) =
    let mutable rad = radius
    member me.Radius with get() = radius and set(value) = rad <- value
    member me.Diameter with get() = rad * 2.00
    member me.Circumference with get() = me.Diameter * 3.14156
    member me.Area with get() = rad * rad * 3.14156

type BasketballCourt(rect, circle) =
    let mutable external = rect
    let mutable central  = circle
    let mutable rar = 0.00
    let mutable rh = 0.00
    let mutable kw = 0.00
    let mutable ftld = 0.00
    let mutable b3pld = 0.00
    member sport.Court
    	with get() = external 
    	and set(value) = external <- value
    member sport.Center 
    	with get() = central 
    	and set(value) = central <- value
    member sport.RestrictedArcRadius 
    	with get() = rar 
    	and set(value) = rar <- value
    member sport.RimHeight 
    	with get() = rh 
    	and set(value) = rh <- value
    member sport.KeyWidth 
    	with get() = kw 
    	and set(value) = kw <- value
    member sport.FreeThrowLineDistance 
    	with get() = ftld 
    	and set(value) = ftld <- value
    member sport.B3PointLineDistanceFromBasket
    	twith get() = b3pld 
    	and set(value) = b3pld <- value
   
let NBACourt = BasketballCourt(Rectangle(28.65, 15.24), Circle(1.22))
NBACourt.RimHeight <- 3.05;
NBACourt.RestrictedArcRadius <- 1.22;
NBACourt.B3PointLineDistanceFromBasket <- 1.22;
NBACourt.KeyWidth <- 4.88;
NBACourt.FreeThrowLineDistance <- 4.57;

printfn "Basketball Court"
printfn "_____________________________________________________"
printfn "Court Measures ______________________________________"
printfn "   Length:             %0.02f m" NBACourt.Court.Length
printfn "   Width:              %0.02f m" NBACourt.Court.Width
printfn "   Perimeter:          %0.02f m" NBACourt.Court.Perimeter
printfn "   Area:               %0.02f m" NBACourt.Court.Area
printfn "Central Circle Measures ____________________________"
printfn "   Radius:             %0.02f m" NBACourt.Center.Radius
printfn "   Diameter:           %0.02f m" NBACourt.Center.Diameter
printfn "   Circumference:      %0.02f m" NBACourt.Center.Circumference
printfn "   Area:               %0.02f m" NBACourt.Center.Area
printfn "____________________________________________________"
printfn "Restricted Arc Radius: %0.02f m" NBACourt.RestrictedArcRadius
printfn "3-Point Line Distance From Basket:  %0.02f m" NBACourt.B3PointLineDistanceFromBasket
printfn "Key Width (Shaded Lane or Restricted Area: %0.02f m" NBACourt.KeyWidth
printfn "Free-throw line distance from point on the floor directly below the backboard: %0.02f m" NBACourt.FreeThrowLineDistance
printfn "____________________________________________________"

A Method that Returns an Object

A method of a class can be made to produce an object of a class type. Here is an example:

type TimePeriod =
    | LunchSpecial
    | RegularLunch
    | Dinner

type Meal(name, description, price) =
    let mutable n = name
    let mutable d = description
    let mutable p = price
    member this.Name with get() = n and set(value) = n <- value
    member this.Description with get() = d and set(value) = d <- value
    member this.UnitPrice with get() = p and set(value) = p <- value

type MealOrder(name : string, period : TimePeriod) =
    let getMeal() : Meal =
        if name = "LS01" then Meal("LS01", "Sweet and Sour Chicken", 5.95)
        elif name = "LS02" then Meal("LS02", "Mongolian Beef", 5.95)
        elif name = "LS03" then Meal("LS03", "Cashew Shrimp", 7.25)
        else Meal("", "", 0.00)
    
    member this.Present() =
        printfn "Customer Order"
        printfn "------------------------------------------"
        printfn "Time Period: %A" period
        printfn "Selection:   %s" (getMeal().Name)
        printfn "Price:       %0.02f" (getMeal().UnitPrice)
    
let order = MealOrder("LS01", TimePeriod.LunchSpecial)

order.Present()

This would produce:

Customer Order
------------------------------------------
Time Period: LunchSpecial
Selection:   LS01
Price:       5.95
Press any key to continue . . .

Passing an Object to a Method

Depending on its role, an object can be passed to a method of a class. Such an object can be used only in the body of the method. Here is an example:

type TimePeriod =
    | LunchSpecial
    | RegularLunch
    | Dinner

type Meal(name, description, price) =
    let mutable n = name
    let mutable d = description
    let mutable p = price
    member this.Name with get() = n and set(value) = n <- value
    member this.Description with get() = d and set(value) = d <- value
    member this.UnitPrice with get() = p and set(value) = p <- value

type MealOrder(name, period : TimePeriod, spicy) =    
    member this.PresentOrder(food : Meal) =
        if food.Name = name then
            printfn "Customer Order"
            printfn "------------------------------------------"
            printfn "Time Period: %A" period
            printfn "Selection:   %s" food.Name
            printfn "Spicy?       %A" spicy
            printfn "Price:       %0.02f" food.UnitPrice
        else
            printfn "Wrong Selection: The food name you provided is not valid."

let ls01 = Meal("LS01", "Sweet and Sour Chicken", 5.95)
let rl01 = Meal("RL01", "Sweet and Sour Chicken", 8.95)
let ls02 = Meal("LS02", "Mongolian Beef", 5.95)
let rl02 = Meal("RL02", "Mongolian Beef", 9.95)
let ls03 = Meal("LS03", "Cashew Shrimp", 7.25)
let unknown = Meal("", "", 0.00)
    
let order = MealOrder("RL02", TimePeriod.RegularLunch, true)

order.PresentOrder(rl02)

This would produce:

Customer Order
------------------------------------------
Time Period: RegularLunch
Selection:   RL02
Spicy?       true
Price:       9.95

In the same way, you can create a class whose constructor takes an object as parameter. That allows you to use the parameter object throughout the body of the class. Here is an example:

type TimePeriod =
    | LunchSpecial
    | RegularLunch
    | Dinner

type Meal(name, description, price) =
    let mutable n = name
    let mutable d = description
    let mutable p = price
    member this.Name with get() = n and set(value) = n <- value
    member this.Description with get() = d and set(value) = d <- value
    member this.UnitPrice with get() = p and set(value) = p <- value

type MealOrder(food : Meal, period : TimePeriod) 
    
    member this.PresentOrder() =
        printfn "Customer Order"
        printfn "------------------------------------------"
        printfn "Time Period: %A" period
        printfn "Selection:   %s" food.Name
        printfn "Price:       %0.02f" food.UnitPrice

let ls01 = Meal("LS01", "Sweet and Sour Chicken", 5.95)
let rl01 = Meal("RL01", "Sweet and Sour Chicken", 8.95)
let ls02 = Meal("LS02", "Mongolian Beef", 5.95)
let rl02 = Meal("RL02", "Mongolian Beef", 9.95)
let ls03 = Meal("LS03", "Cashew Shrimp", 7.25)
let unknown = Meal("", "", 0.00)
    
let order = MealOrder(rl02, TimePeriod.RegularLunch)

order.PresentOrder()

This would produce:

Customer Order
------------------------------------------
Time Period: RegularLunch
Selection:   RL02
Price:       9.95

Press any key to continue . . .

Passing an Interface to a Function or Method

An interface provides a list of members that some classes must implement. After creating such classes, you can create a function or method that gets the interface as a parameter. In the body of the function or method, through the parameter, you can access only the members of the interface. When calling the function or method that receives the interface, you must pass an object of a class that implements the interface. Here are examples:

type ICircular =
    abstract Diameter : unit -> double
    abstract Circumference : unit -> double
    abstract Area : unit -> double

type IQuadrilateralArea =
    abstract Area : double * double -> double

type Circle(radius : double) =
    member this.Radius : double = radius
    member this.Diameter() = (this :> ICircular).Diameter()
    member this.Circumference() = (this :> ICircular).Circumference()
    member this.Area()        = (this :> ICircular).Area()
    interface ICircular with
        member this.Diameter() = radius * 2.00
        member this.Circumference() = radius * 2.00 * 3.14156
        member this.Area() : double = radius * radius * 3.14156

type Sphere(radius : double) =
    member this.Radius : double = radius
    member this.Diameter() = (this :> ICircular).Diameter()
    member this.Circumference() = (this :> ICircular).Circumference()
    member this.Area()        = (this :> ICircular).Area()
    interface ICircular with
        member this.Diameter() = radius * 2.00
        member this.Circumference() = radius * 2.00 * 3.14156
        member this.Area() : double = radius * radius * 4.00 * 3.14156

type Cylinder(radius : double, height : double) =
    member this.Radius : double = radius
    member this.Height : double = height
    member this.Diameter() = (this :> ICircular).Diameter()
    member this.Circumference() = (this :> ICircular).Circumference()
    member this.BottomArea()   = (this :> ICircular).Area()
    interface ICircular with
        member this.Diameter() = radius * 2.00
        member this.Circumference() = radius * 2.00 * 3.14156
        member this.Area() : double = radius * radius * 3.14156
    interface IQuadrilateralArea with
        member this.Area(length : double, width : double) : double = length * width

let describe(round : ICircular) =
    printfn "Round Shape Characteristics";
    printfn "------------------------------";
    printfn "Diameter:      %f" (round.Diameter());
    printfn "Circumference: %f" (round.Circumference());
    printfn "Area:          %f" (round.Area());
    printfn "==============================";

let circle = Circle(46.8506)
let ball = Sphere(46.8506)
let cup = Cylinder(46.8506, 28.96)

describe circle
describe ball
describe cup

This would produce:

Round Shape Characteristics
------------------------------
Diameter:      93.701200
Circumference: 294.367942
Area:          6895.657349
==============================
Round Shape Characteristics
------------------------------
Diameter:      93.701200
Circumference: 294.367942
Area:          27582.629395
==============================
Round Shape Characteristics
------------------------------
Diameter:      93.701200
Circumference: 294.367942
Area:          6895.657349
==============================

Press any key to continue . . .

Because F# is top-down one directional language (somehow like C++ and Java but unlike C#), if you want to access the members of a class that implements the interface, you must declare its variable before defining the function or method that takes the interface as parameter. Here are examples:

type ICircular =
    abstract Diameter : unit -> double
    abstract Circumference : unit -> double
    abstract Area : unit -> double

type IQuadrilateralArea =
    abstract Area : double * double -> double

type Circle(radius : double) =
    member this.Radius : double = radius
    member this.Diameter() = (this :> ICircular).Diameter()
    member this.Circumference() = (this :> ICircular).Circumference()
    member this.Area()        = (this :> ICircular).Area()
    interface ICircular with
        member this.Diameter() = radius * 2.00
        member this.Circumference() = radius * 2.00 * 3.14156
        member this.Area() : double = radius * radius * 3.14156

type Sphere(radius : double) =
    member this.Radius : double = radius
    member this.Diameter() = (this :> ICircular).Diameter()
    member this.Circumference() = (this :> ICircular).Circumference()
    member this.Area()        = (this :> ICircular).Area()
    interface ICircular with
        member this.Diameter() = radius * 2.00
        member this.Circumference() = radius * 2.00 * 3.14156
        member this.Area() : double = radius * radius * 4.00 * 3.14156

type Cylinder(radius : double, height : double) =
    member this.Radius : double = radius
    member this.Height : double = height
    member this.Diameter() = (this :> ICircular).Diameter()
    member this.Circumference() = (this :> ICircular).Circumference()
    member this.BottomArea()   = (this :> ICircular).Area()
    interface ICircular with
        member this.Diameter() = radius * 2.00
        member this.Circumference() = radius * 2.00 * 3.14156
        member this.Area() : double = radius * radius * 3.14156
    interface IQuadrilateralArea with
        member this.Area(length : double, width : double) : double = length * width

let circle = Circle(46.8506)

let describeCircle(round : ICircular) =
    printfn "Circle Characteristics";
    printfn "------------------------------";
    printfn "Radius:        %f" circle.Radius;
    printfn "Diameter:      %f" (round.Diameter());
    printfn "Circumference: %f" (round.Circumference());
    printfn "Area:          %f" (round.Area());
    printfn "==============================";

let ball = Sphere(46.8506)

let describeSphere(round : ICircular) =
    printfn "Sphere Characteristics";
    printfn "------------------------------";
    printfn "Radius:        %f" ball.Radius;
    printfn "Diameter:      %f" (round.Diameter());
    printfn "Circumference: %f" (round.Circumference());
    printfn "Area:          %f" (round.Area());
    printfn "==============================";
    
let cup = Cylinder(46.8506, 28.96)

let describeCylinder(round : ICircular) =
    printfn "Cylinder Characteristics";
    printfn "------------------------------";
    printfn "Radius:        %f" cup.Radius;
    printfn "Height:        %f" cup.Height;
    printfn "Diameter:      %f" (round.Diameter());
    printfn "Circumference: %f" (round.Circumference());
    printfn "Area:          %f" (round.Area());
    printfn "==============================";

describeCircle circle
describeSphere ball
describeCylinder cup

This would produce:

Circle Characteristics
------------------------------
Radius:        46.850600
Diameter:      93.701200
Circumference: 294.367942
Area:          6895.657349
==============================
Sphere Characteristics
------------------------------
Radius:        46.850600
Diameter:      93.701200
Circumference: 294.367942
Area:          27582.629395
==============================
Cylinder Characteristics
------------------------------
Radius:        46.850600
Height:        28.960000
Diameter:      93.701200
Circumference: 294.367942
Area:          6895.657349
==============================

Press any key to continue . . .

A Class in its Own Methods

Passing a Class as Parameter to its Own Methods

An instance of a class can be passed as a parameter to one of its own methods. To do this, you primarily pass the parameter as if it were any class. Here is an example:

type Point() =
    member this.Equivalent (same : Point) = . . .

In the body of the method, do whatever you want. If you decide to use the parameter, all of the other members of the class are available through the parameter. Probably the simplest way to use the parameter is to assign each of its values to the equivalent member of the class. Here is an example:

type Point(x, y) =
    let mutable xCoordinate = x
    let mutable yCoordinate = y
    member this.X with get() = xCoordinate and set(value) = xCoordinate <- value
    member this.Y with get() = yCoordinate and set(value) = yCoordinate <- value

    member this.Equivalent (same : Point) =
        this.X <- same.X
        this.Y <- same.Y

When calling the method, make sure you pass an instance of the class to it. You can first create and define the class, then pass it. Here is an example:

type Point(x, y) =
    let mutable xCoordinate = x
    let mutable yCoordinate = y
    member this.X with get() = xCoordinate and set(value) = xCoordinate <- value
    member this.Y with get() = yCoordinate and set(value) = yCoordinate <- value
    new() = Point(0, 0)
    
    member this.Equivalent (same : Point) =
        this.X <- same.X
        this.Y <- same.Y
    

let showPoint (pt : Point) =
    printfn "Point Coordinates: A(%d, %d)" pt.X pt.Y

let pt = new Point()

pt.X <- 4
pt.Y <- 6
showPoint pt

let one = new Point()
one.Equivalent pt
showPoint(one)

This would produce:

Point Coordinates: A(4, 6)
Point Coordinates: A(4, 6)
Press any key to continue . . .

Instead of first declaring a variable of the class and initializing it, you can create an instance of the class in the parentheses of the calling method. To do this, you may need a constructor that can specify the values of the properties of the class so the argument can be rightfully initialized. Here is an example:

type Point(x, y) =
    let mutable xCoordinate = x
    let mutable yCoordinate = y
    member this.X with get() = xCoordinate and set(value) = xCoordinate <- value
    member this.Y with get() = yCoordinate and set(value) = yCoordinate <- value
    new() = Point(0, 0)
    
    member this.Equivalent (same : Point) =
        this.X <- same.X
        this.Y <- same.Y

let showPoint (pt : Point) =
    printfn "Point Coordinates: A(%d, %d)" pt.X pt.Y

let pt = new Point()

pt.X <- 4
pt.Y <- 6
showPoint pt

let one = new Point()
one.Equivalent (Point(-3, 2))
showPoint(one)

This would produce:

Point Coordinates: A(4, 6)
Point Coordinates: A(-3, 2)

Passing a Constructor

Instead of a formal method, you can use a constructor of the class to pass an instance of the same class. Then, in the constructor, use the argument as you see fit, knowing that all the members of the class are available. Here is an example:

type Point(x, y) =
    let mutable xCoordinate = x
    let mutable yCoordinate = y
    member this.X with get() = xCoordinate and set(value) = xCoordinate <- value
    member this.Y with get() = yCoordinate and set(value) = yCoordinate <- value
    new() = Point(0, 0)
    new(same : Point) = Point(same.X, same.Y)
    
    member this.Equivalent (same : Point) =
        this.X <- same.X
        this.Y <- same.Y 

Obviously the purpose of passing a class to one of its own methods is not to find its equivalent. Instead, you can create a method that takes an instance of the same class but modifies that instance. For example, for our Point class, we may want to create a new point that is distanced by one unit from the current Point object. Here is an example of doing that:

type Point(x, y) =
    let mutable xCoordinate = x
    let mutable yCoordinate = y
    member this.X with get() = xCoordinate and set(value) = xCoordinate <- value
    member this.Y with get() = yCoordinate and set(value) = yCoordinate <- value
    new() = Point(0, 0)
    new(same : Point) = Point(same.X, same.Y)
    
    member this.Equivalent (same : Point) =
        this.X <- same.X
        this.Y <- same.Y

    member this.CreatePointOneUnitAway(addUnit : Point) =
        this.X <- addUnit.X + 1
        this.Y <- addUnit.Y + 1

let showPoint(pt : Point) =
    printfn "Point Coordinates: A(%d, %d)" pt.X pt.Y

let pt = new Point()

pt.X <- 4
pt.Y <- 6
showPoint pt

let one = new Point()
one.CreatePointOneUnitAway pt
showPoint one
one.CreatePointOneUnitAway(Point(-8, -3))
showPoint one

This would produce:

Point Coordinates: A(4, 6)
Point Coordinates: A(5, 7)
Point Coordinates: A(-7, -2)
Press any key to continue . . .

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