Home

Classes and Functions

 

Fundamentals

 

Returning an Object from a Function

A function can be made to return an object of a class type. Of course, you must know the class of the object you want to return. You can create your own class. 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:

open System
open System.Windows.Forms

let emplNbr1, emplSal1 = "8022-3840", 24.55
let emplNbr2, emplSal2 = "5840-2497", 16.25
let emplNbr3, emplSal3 = "2081-7008", 22.75

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

    member this.EmployeeNumber 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 * 40.00
    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

// A function that returns an object
let calculateWeeklySalary emplNbr mon tue wed thu fri sat sun =
    let EmployeeNumber =
        if emplNbr = emplNbr1 then emplSal1
        elif emplNbr = emplNbr2 then emplSal2
        else emplSal3
    let timeWorked = mon + tue + wed + thu + fri + sat + sun
    let payroll = new EmployeePayroll(EmployeeNumber, timeWorked)
    payroll

// Form: Payroll Preparation
let payrollPreparation = new Form(Width = 450, Height = 325, Text = "Payroll Preparation")

// Label: Employee Number
let lblEmployeeNumber = new Label(Left = 23, Top = 22, Width = 80, Text = "Employee #:")
payrollPreparation.Controls.Add lblEmployeeNumber

// Text Box: Hourly Salary
let txtEmployeeNumber = new TextBox(Left = 110, Top =  19, Width = 75, Text = "0000-0000")
payrollPreparation.Controls.Add txtEmployeeNumber

// Labels: Days
let lblMonday    = new Label(Left =  23, Top = 51, Width = 50, Height = 13, Text = "Monday")
let lblTuesday   = new Label(Left =  80, Top = 51, Width = 50, Height = 13, Text = "Tuesday")
let lblWednesday = new Label(Left = 134, Top = 51, Width = 65, Height = 13, Text = "Wednesday")
let lblThursday  = new Label(Left = 198, Top = 51, Width = 50, Height = 13, Text = "Thursday")
let lblFriday    = new Label(Left = 253, Top = 51, Width = 50, Height = 13, Text = "Friday")
let lblSaturday  = new Label(Left = 307, Top = 51, Width = 50, Height = 13, Text = "Saturday")
let lblSunday    = new Label(Left = 365, Top = 51, Width = 50, Height = 13, Text = "Sunday")
payrollPreparation.Controls.AddRange([| lblMonday; lblTuesday; lblWednesday; lblThursday; lblFriday; lblSaturday; lblSunday |])

// Text Boxes: Days
let txtMonday    = new TextBox(Left =  26, Top = 67, Width = 50, Text = "0.00")
let txtTuesday   = new TextBox(Left =  83, Top = 67, Width = 50, Text = "0.00")
let txtWednesday = new TextBox(Left = 140, Top = 67, Width = 50, Text = "0.00")
let txtThursday  = new TextBox(Left = 197, Top = 67, Width = 50, Text = "0.00")
let txtFriday    = new TextBox(Left = 254, Top = 67, Width = 50, Text = "0.00")
let txtSaturday  = new TextBox(Left = 311, Top = 67, Width = 50, Text = "0.00")
let txtSunday    = new TextBox(Left = 368, Top = 67, Width = 50, Text = "0.00")
payrollPreparation.Controls.AddRange([| txtMonday; txtTuesday; txtWednesday; txtThursday; txtFriday; txtSaturday; txtSunday |])

// Button: Prepare
let btnPrepare = new Button(Left = 26, Top = 97, Width = 393, Height = 35, Text = "Prepare")
payrollPreparation.Controls.Add btnPrepare

// Label: Time Worked
let lblTimeWorked = new Label(Left = 111, Top = 147, Width = 85, Text = "Time Worked:")
payrollPreparation.Controls.Add lblTimeWorked

// Text Box: Time Worked
let txtTimeWorked = new TextBox(Left = 198, Top = 144, Width = 75, Text = "0.00")
payrollPreparation.Controls.Add txtTimeWorked

// Label: Time
let lblTime = new Label(Left = 195, Top = 180, Width = 30, Height = 13, Text = "Time")
payrollPreparation.Controls.Add lblTime

// Label: Pay
let lblPay = new Label(Left = 254, Top = 180, Width = 30, Height = 13, Text = "Pay")
payrollPreparation.Controls.Add lblPay

// Label: Regular
let lblRegular = new Label(Left = 116, Top = 199, Width = 75, Text = "Regular:")
payrollPreparation.Controls.Add lblRegular

// Text Box: Regular Time
let txtRegularTime = new TextBox(Left = 198, Top = 196, Width = 50, Text = "0.00")
payrollPreparation.Controls.Add txtRegularTime

// Text Box: Regular Pay
let txtRegularPay = new TextBox(Left = 255, Top = 196, Width = 50, Text = "0.00")
payrollPreparation.Controls.Add txtRegularPay

// Label: Overtime
let lblOvertime = new Label(Left = 116, Top = 225, Width = 60, Text = "Overtime:")
payrollPreparation.Controls.Add lblOvertime

// Text Box: Overtime
let txtOvertimeTime = new TextBox(Left = 198, Top = 222, Width = 50, Text = "0.00")
payrollPreparation.Controls.Add txtOvertimeTime

// Text Box: Overtime Pay
let txtOvertimePay = new TextBox(Left = 255, Top = 222, Width = 50, Text = "0.00")
payrollPreparation.Controls.Add txtOvertimePay

// Label: Line
let lblLine = new Label(Left = 100, Top = 244, Width = 270, Height = 13)
lblLine.Text <- "-----------------------------------------------------------------------"
payrollPreparation.Controls.Add lblLine

// Label: Gross Salary
let lblGrossSalary = new Label(Left = 117, Top = 264, Width = 75, Text = "Gross Salary:")
payrollPreparation.Controls.Add lblGrossSalary

// Text Box: Gross Salary
let txtGrossSalary = new TextBox(Left = 198, Top = 260, Width = 70, Text = "0.00")
payrollPreparation.Controls.Add txtGrossSalary

let btnPrepareClick e =
    let employeeNumber = txtEmployeeNumber.Text
    let monday    = float txtMonday.Text
    let tuesday   = float txtTuesday.Text
    let wednesday = float txtWednesday.Text
    let thursday  = float txtThursday.Text
    let friday    = float txtFriday.Text
    let saturday  = float txtSaturday.Text
    let sunday    = float txtSunday.Text

    let payroll = calculateWeeklySalary employeeNumber monday tuesday wednesday thursday friday saturday sunday
    
    let strTotalTime   = sprintf "%0.02f" payroll.TimeWorked
    let strRegularTime = sprintf "%0.02f" payroll.RegularTime
    let strOvertime    = sprintf "%0.02f" payroll.Overtime
    let strRegularPay  = sprintf "%0.02f" payroll.RegularPay
    let strOvertimePay = sprintf "%0.02f" payroll.OvertimePay
    let strGrossSalary = sprintf "%0.02f" payroll.GrossSalary
    
    txtTimeWorked.Text <- strTotalTime
    txtRegularTime.Text <- strRegularTime
    txtRegularPay.Text  <- strRegularPay
    txtOvertimeTime.Text <- strOvertime
    txtOvertimePay.Text <- strOvertimePay
    txtGrossSalary.Text  <- strGrossSalary

btnPrepare.Click.Add btnPrepareClick

// Button: Close
let btnClose = new Button(Left = 284, Top = 260, Text = "Close")
let btnCloseClick e = payrollPreparation.Close()
btnClose.Click.Add btnCloseClick
payrollPreparation.Controls.Add btnClose

do Application.Run payrollPreparation

Here is a test of the program:

Returning an Object from a Function

Returning an Object from a Function

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:

let calculateWeeklySalary emplNbr mon tue wed thu fri sat sun =
    let EmployeeNumber =
        if emplNbr = emplNbr1 then emplSal1
        elif emplNbr = emplNbr2 then emplSal2
        else emplSal3
    let timeWorked = mon + tue + wed + thu + fri + sat + sun
    new EmployeePayroll(EmployeeNumber, timeWorked)

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:

let calculateWeeklySalary emplNbr mon tue wed thu fri sat sun : EmployeePayroll =
    let EmployeeNumber =
        if emplNbr = emplNbr1 then emplSal1
        elif emplNbr = emplNbr2 then emplSal2
        else emplSal3
    let timeWorked = mon + tue + wed + thu + fri + sat + sun
    new EmployeePayroll(EmployeeNumber, timeWorked)

You can pass 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.

Remember that Windows controls are based .NET classes. You can use use a function that produces a Windows control. Here are examples:

open System
open System.Windows.Forms

let emplNbr1, emplSal1 = "8022-3840", 24.55
let emplNbr2, emplSal2 = "5840-2497", 16.25
let emplNbr3, emplSal3 = "2081-7008", 22.75

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

    member this.EmployeeNumber 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 * 40.00
    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

// A function that returns an object
let calculateWeeklySalary emplNbr mon tue wed thu fri sat sun : EmployeePayroll =
    let EmployeeNumber =
        if emplNbr = emplNbr1 then emplSal1
        elif emplNbr = emplNbr2 then emplSal2
        else emplSal3
    let timeWorked = mon + tue + wed + thu + fri + sat + sun
    new EmployeePayroll(EmployeeNumber, timeWorked)

let createLabel     left top width text : Label = new Label(Left = left, Top = top, Width = width, Text = text)
let createDaysLabel left text : Label = new Label(Left = left, Top = 51, Width = 55, Height = 13, Text = text)
let createTextBox   left top width : TextBox = new TextBox(Left = left, Top = top, Width = width, Text = "0.00")
let createButton    left top text : Button = new Button(Left = left, Top = top, Text = text)

// Form: Payroll Preparation
let payrollPreparation = new Form(Width = 450, Height = 325, Text = "Payroll Preparation")

// Labels
let lblEmployeeNumber = createLabel  23 22 80 "Employee #:"
let lblMonday         = createDaysLabel  23 "Monday"
let lblTuesday        = createDaysLabel  80 "Tuesday"
let lblWednesday      = createDaysLabel 134 "Wednesday"
let lblThursday       = createDaysLabel 198 "Thursday"
let lblFriday         = createDaysLabel 253 "Friday"
let lblSaturday       = createDaysLabel 308 "Saturday"
let lblSunday         = createDaysLabel 365 "Sunday"
let lblTimeWorked     = createLabel 111 147 85 "Time Worked:"
let lblTime           = createLabel 195 180 40 "Time"
let lblPay            = createLabel 254 lblTime.Top lblTime.Width "Pay"
let lblRegular        = createLabel lblTimeWorked.Left 199 80 "Regular:"
let lblOvertime       = createLabel lblTimeWorked.Left 225 60 "Overtime:"
let lblGrossSalary    = createLabel 117 262 78 "Gross Salary:"
let lblLine           = createLabel 100 244 270 "-"
payrollPreparation.Controls.AddRange([| lblEmployeeNumber; lblMonday; lblTuesday; lblWednesday; lblThursday; lblFriday; lblSaturday; lblSunday; lblTimeWorked; lblTime; lblPay; lblRegular; lblOvertime; lblGrossSalary; lblLine |])

// Text Boxes
let txtEmployeeNumber = createTextBox 110 19 75
let txtMonday         = createTextBox  26 67 50
let txtTuesday        = createTextBox  83 txtMonday.Top txtMonday.Width
let txtWednesday      = createTextBox 140 txtMonday.Top txtMonday.Width
let txtThursday       = createTextBox 197 txtMonday.Top txtMonday.Width
let txtFriday         = createTextBox 254 txtMonday.Top txtMonday.Width
let txtSaturday       = createTextBox 311 txtMonday.Top txtMonday.Width
let txtSunday         = createTextBox 368 txtMonday.Top txtMonday.Width
let txtTimeWorked     = createTextBox 198 144 75
let txtRegularTime    = createTextBox txtTimeWorked.Left 196 50
let txtRegularPay     = createTextBox 255 196 50
let txtOvertimeTime   = createTextBox 198 222 50
let txtOvertimePay    = createTextBox 254 txtOvertimeTime.Top 50
let txtGrossSalary    = createTextBox 198 260 70
payrollPreparation.Controls.AddRange([| txtEmployeeNumber; txtMonday; txtTuesday; txtWednesday; txtThursday; txtFriday; txtSaturday; txtSunday; txtTimeWorked; txtRegularTime; txtRegularPay; txtOvertimeTime; txtOvertimePay; txtGrossSalary |])

// Buttons
let btnPrepare = createButton 26 97 "Prepare"
let btnClose = new Button(Left = 282, Top = 260, Text = "Close")
payrollPreparation.Controls.Add btnPrepare

lblWednesday.Width <- 65
lblTime.Height <- 13
lblPay.Height <- lblTime.Height
lblLine.Height <- lblTime.Height
btnPrepare.Width <- 393
btnPrepare.Height <- 35
txtEmployeeNumber.Text <- "0000-0000" 
lblLine.Text <- "-----------------------------------------------------------------------"

let btnPrepareClick e =
    let employeeNumber = txtEmployeeNumber.Text
    let monday    = float txtMonday.Text
    let tuesday   = float txtTuesday.Text
    let wednesday = float txtWednesday.Text
    let thursday  = float txtThursday.Text
    let friday    = float txtFriday.Text
    let saturday  = float txtSaturday.Text
    let sunday    = float txtSunday.Text

    let payroll = calculateWeeklySalary employeeNumber monday tuesday wednesday thursday friday saturday sunday
    
    let strTotalTime   = sprintf "%0.02f" payroll.TimeWorked
    let strRegularTime = sprintf "%0.02f" payroll.RegularTime
    let strOvertime    = sprintf "%0.02f" payroll.Overtime
    let strRegularPay  = sprintf "%0.02f" payroll.RegularPay
    let strOvertimePay = sprintf "%0.02f" payroll.OvertimePay
    let strGrossSalary = sprintf "%0.02f" payroll.GrossSalary
    
    txtTimeWorked.Text <- strTotalTime
    txtRegularTime.Text <- strRegularTime
    txtRegularPay.Text  <- strRegularPay
    txtOvertimeTime.Text <- strOvertime
    txtOvertimePay.Text <- strOvertimePay
    txtGrossSalary.Text  <- strGrossSalary

btnPrepare.Click.Add btnPrepareClick

// Button: Close
let btnCloseClick e = payrollPreparation.Close()
btnClose.Click.Add btnCloseClick
payrollPreparation.Controls.Add btnClose

do Application.Run payrollPreparation
     
 

Passing an Object as Parameter

A function can be defined to take an object as parameter. When creating such a function, you should specify the data type of the parameter. In the body of the function, use the parameter as you see fit.

Instead of just one object as parameter, a function can take more than one object as parameter. The parameters can be of the same class. Here is an example:

let calculateMedicare (week1 : EmployeePayroll) (week2 : EmployeePayroll) =
    let grossPay = week1.GrossSalary + week2.GrossSalary
    grossPay * 1.45 / 100.00

In the same way, the constructor of a class can take (a) parameter(s) that is(are) of (the) type(s) of a class. In the body of the class, you can access the members of the parameter(s). Here are examples:

open System
open System.Windows.Forms

let emplNbr1, emplSal1 = "8022-3840", 24.55
let emplNbr2, emplSal2 = "5840-2497", 16.25
let emplNbr3, emplSal3 = "2081-7008", 22.75

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

    member this.EmployeeNumber 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 * 40.00
    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

 type SalarySummary(week1 : EmployeePayroll, week2 : EmployeePayroll) =
    member this.TimeWorked     with get() = week1.TimeWorked + week2.TimeWorked
    member this.RegularTime    with get() = week1.RegularTime + week2.RegularTime
    member this.Overtime       with get() = week1.Overtime + week2.Overtime
    member this.RegularPay     with get() = week1.RegularPay + week2.RegularPay
    member this.OvertimePay    with get() = week1.OvertimePay + week2.OvertimePay
    member this.GrossSalary    with get() = week1.GrossSalary + week2.GrossSalary

// A function that returns an object
let calculateWeeklySalary emplNbr mon tue wed thu fri sat sun : EmployeePayroll =
    let EmployeeNumber =
        if emplNbr = emplNbr1 then emplSal1
        elif emplNbr = emplNbr2 then emplSal2
        else emplSal3
    let timeWorked = mon + tue + wed + thu + fri + sat + sun
    new EmployeePayroll(EmployeeNumber, timeWorked)

// Passing objects to a function
let calculateSocialSecurity (week1 : EmployeePayroll) (week2 : EmployeePayroll) =
    let grossPay = week1.GrossSalary + week2.GrossSalary

    if grossPay < 118500.00 then
        grossPay * 6.20 / 100.00 // FY 2015
    else
        118500.00 * 6.20 / 100.00

let calculateMedicare (week1 : EmployeePayroll) (week2 : EmployeePayroll) =
    let grossPay = week1.GrossSalary + week2.GrossSalary
    grossPay * 1.45 / 100.00

let createLabel     left top width text : Label = new Label(Left = left, Top = top, Width = width, Text = text)
let createDaysLabel left text : Label = new Label(Left = left, Top = 52, Width = 55, Height = 13, Text = text)
let createTextBox   left top width : TextBox = new TextBox(Left = left, Top = top, Width = width, Text = "0.00")
let createWeek1DaysTextBox left : TextBox = new TextBox(Left = left, Top = 68, Width = 50, Text = "0.00")
let createWeek2DaysTextBox left : TextBox = new TextBox(Left = left, Top = 103, Width = 50, Text = "0.00")
let createButton    left top text : Button = new Button(Left = left, Top = top, Text = text)

// Form: Payroll Preparation
let payrollPreparation = new Form(Width = 500, Height = 405, Text = "Payroll Preparation")

// Labels
let lblEmployeeNumber = createLabel  23 22 80 "Employee #:"
let lblMonday         = createDaysLabel  77 "Monday"
let lblTuesday        = createDaysLabel 134 "Tuesday"
let lblWednesday      = createDaysLabel 188 "Wednesday"
let lblThursday       = createDaysLabel 252 "Thursday"
let lblFriday         = createDaysLabel 307 "Friday"
let lblSaturday       = createDaysLabel 361 "Saturday"
let lblSunday         = createDaysLabel 419 "Sunday"
let lblWeek1          = createLabel lblEmployeeNumber.Left  71 51 "Week 1:"
let lblWeek2          = createLabel lblEmployeeNumber.Left 106 51 "Week 2:"

let lblTimeWorked     = createLabel 84 193 85 "Time Worked:"
let lblTime           = createLabel 168 226 40 "Time"
let lblPay            = createLabel 227 lblTime.Top lblTime.Width "Pay"
let lblRegular        = createLabel lblTimeWorked.Left 245 80 "Regular:"
let lblOvertime       = createLabel lblTimeWorked.Left 271 60 "Overtime:"
let lblGrossSalary    = createLabel 294 271 78 "Gross Salary:"
let lblLine           = createLabel 23 291 450 "-"
let lblSocialSecurityTax = createLabel 60 313 110 "Social Security Tax:"
let lblMedicareTax       = createLabel 280 313 85 "Medicare Tax:"
payrollPreparation.Controls.AddRange([| lblMonday; lblTuesday; lblWednesday; lblThursday; lblFriday; lblSaturday; lblSunday; lblWeek1; lblWeek2 |])
payrollPreparation.Controls.AddRange([| lblEmployeeNumber; lblTimeWorked; lblTime; lblPay; lblRegular; lblOvertime; lblGrossSalary; lblLine |])
payrollPreparation.Controls.AddRange([| lblSocialSecurityTax; lblMedicareTax |])

// Text Boxes
let txtEmployeeNumber = createTextBox 110 19 75
let txtWeek1Monday    = createWeek1DaysTextBox  80
let txtWeek1Tuesday   = createWeek1DaysTextBox 137
let txtWeek1Wednesday = createWeek1DaysTextBox 194
let txtWeek1Thursday  = createWeek1DaysTextBox 251
let txtWeek1Friday    = createWeek1DaysTextBox 308
let txtWeek1Saturday  = createWeek1DaysTextBox 365
let txtWeek1Sunday    = createWeek1DaysTextBox 422
let txtWeek2Monday    = createWeek2DaysTextBox  80
let txtWeek2Tuesday   = createWeek2DaysTextBox 137
let txtWeek2Wednesday = createWeek2DaysTextBox 194
let txtWeek2Thursday  = createWeek2DaysTextBox 251
let txtWeek2Friday    = createWeek2DaysTextBox 308
let txtWeek2Saturday  = createWeek2DaysTextBox 365
let txtWeek2Sunday    = createWeek2DaysTextBox 422

let txtTimeWorked     = createTextBox 171 190 75
let txtRegularTime    = createTextBox txtTimeWorked.Left 244 txtWeek1Monday.Width
let txtRegularPay     = createTextBox 228 txtRegularTime.Top txtWeek1Monday.Width
let txtOvertimeTime   = createTextBox txtTimeWorked.Left 268 txtWeek1Monday.Width
let txtOvertimePay    = createTextBox txtRegularPay.Left txtOvertimeTime.Top txtWeek1Monday.Width
let txtGrossSalary    = createTextBox 375 268 75 // txtWeek1Monday.Width
let txtSocialSecurityTax = createTextBox txtTimeWorked.Left 310 txtWeek1Monday.Width
let txtMedicareTax    = createTextBox txtGrossSalary.Left txtSocialSecurityTax.Top txtGrossSalary.Width

payrollPreparation.Controls.AddRange([| txtEmployeeNumber; txtTimeWorked; txtRegularTime; txtRegularPay; txtOvertimeTime; txtOvertimePay; txtGrossSalary |])
payrollPreparation.Controls.AddRange([| txtWeek1Monday; txtWeek1Tuesday; txtWeek1Wednesday; txtWeek1Thursday; txtWeek1Friday; txtWeek1Saturday; txtWeek1Sunday |])
payrollPreparation.Controls.AddRange([| txtWeek2Monday; txtWeek2Tuesday; txtWeek2Wednesday; txtWeek2Thursday; txtWeek2Friday; txtWeek2Saturday; txtWeek2Sunday |])
payrollPreparation.Controls.AddRange([| txtSocialSecurityTax; txtMedicareTax |])

// Buttons
let btnPrepare = createButton 27 141 "Prepare"
let btnClose   = createButton txtGrossSalary.Left 342 "Close"
payrollPreparation.Controls.AddRange([| btnPrepare; btnClose |])

lblWednesday.Width <- 65
lblTime.Height <- 13
lblPay.Height <- lblTime.Height
lblLine.Height <- lblTime.Height
btnPrepare.Width <- 446
btnPrepare.Height <- 35
txtEmployeeNumber.Text <- "0000-0000"
lblLine.Text <- "-----------------------------------------------------------------------------------------------------------------------------------------------------"

let btnPrepareClick e =
    let employeeNumber = txtEmployeeNumber.Text
    let mon1, mon2 = (float txtWeek1Monday.Text),    (float txtWeek2Monday.Text)
    let tue1, tue2 = (float txtWeek1Tuesday.Text),   (float txtWeek2Tuesday.Text)
    let wed1, wed2 = (float txtWeek1Wednesday.Text), (float txtWeek2Wednesday.Text)
    let thu1, thu2 = (float txtWeek1Thursday.Text),  (float txtWeek2Thursday.Text)
    let fri1, fri2 = (float txtWeek1Friday.Text),    (float txtWeek2Friday.Text)
    let sat1, sat2 = (float txtWeek1Saturday.Text),  (float txtWeek2Saturday.Text)
    let sun1, sun2 = (float txtWeek1Sunday.Text),    (float txtWeek2Sunday.Text)

    let week1Pay = calculateWeeklySalary employeeNumber mon1 tue1 wed1 thu1 fri1 sat1 sun1
    let week2Pay = calculateWeeklySalary employeeNumber mon2 tue2 wed2 thu2 fri2 sat2 sun2
    let payroll = new SalarySummary(week1Pay, week2Pay)

    let socialSecurity = calculateSocialSecurity week1Pay week2Pay
    let medicare = calculateMedicare week1Pay week2Pay

    let strTotalTime      = sprintf "%0.02f" payroll.TimeWorked
    let strRegularTime    = sprintf "%0.02f" payroll.RegularTime
    let strOvertime       = sprintf "%0.02f" payroll.Overtime
    let strRegularPay     = sprintf "%0.02f" payroll.RegularPay
    let strOvertimePay    = sprintf "%0.02f" payroll.OvertimePay
    let strGrossSalary    = sprintf "%0.02f" payroll.GrossSalary
    let strSocialSecurity = sprintf "%0.02f" socialSecurity
    let strMedicare       = sprintf "%0.02f" medicare
    
    txtTimeWorked.Text        <- strTotalTime
    txtRegularTime.Text       <- strRegularTime
    txtRegularPay.Text        <- strRegularPay
    txtOvertimeTime.Text      <- strOvertime
    txtOvertimePay.Text       <- strOvertimePay
    txtGrossSalary.Text       <- strGrossSalary
    txtSocialSecurityTax.Text <- strSocialSecurity
    txtMedicareTax.Text       <- strMedicare

btnPrepare.Click.Add btnPrepareClick

// Button: Close
let btnCloseClick e = payrollPreparation.Close()
btnClose.Click.Add btnCloseClick
payrollPreparation.Controls.Add btnClose

do Application.Run payrollPreparation

Here one example of testing the program:

Passing an Object as Parameter

Passing an Object as Parameter

Here is another example where an employee worked overtime during one week but not during another week:

Passing an Object as Parameter

Passing an Object as Parameter

You can also pass a combination of parameters of class types and primitive types. When you pass a class as argument, you mays want to know whether the object is null or not. In the function, compare the argument to null and take appropriate actions. Here is an example:

open System
open System.Windows.Forms

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

[<AllowNullLiteral>]
type EmployeePayroll(hSalary, tWorked, pDate) =
    let sal = ref hSalary
    let tme = ref tWorked
    let dte = ref pDate

    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.PayDate      with get() = !dte and set(value) = dte := 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 payrollSummary = new Form(Width = 460, Height = 250, Text = "Payroll Summary")

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

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

let display (empl : Employee) (payroll : EmployeePayroll) =
    match payroll 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" empl.EmployeeNumber payroll.HourlySalary payroll.TimeWorked payroll.RegularTime payroll.Overtime payroll.RegularPay payroll.OvertimePay payroll.GrossSalary) |> ignore

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 payroll5840249706192015, payroll2081700806192015, payroll8022384006192015, payroll7042815006192015 = new EmployeePayroll(empl58402497.HourlySalary, 36.50, "06/19/2015"),
                                                                                                         new EmployeePayroll(empl20817008.HourlySalary, 42.50, "06/19/2015"),
                                                                                                         new EmployeePayroll(empl80223840.HourlySalary, 38.00, "06/19/2015"),
                                                                                                         new EmployeePayroll(empl70428150.HourlySalary, 44.00, "06/19/2015")
display empl80223840 payroll8022384006192015
display empl20817008 payroll2081700806192015
display empl58402497 payroll5840249706192015

Passing an Interface as Parameter

An interface can be passed as parameter to a function. Such an interface represents all classes that implement it. Therefore, before using the interface in the function, you may want to find out what particular class is being dealt with. To do this, you can use a matching pattern that checks the type. The option for each pattern starts with the :? operator followed by the name of the class. Here are examples:

// An interface
type IDepreciation =
    abstract Cost : float with get, set
    abstract SalvageValue : float with get, set
    abstract UsefulLife : float with get, set
    abstract DepreciatedValue : float with get

// Depreciation: Straight-Line Method
type StraightLine(totalCost, salvage, estLife) =
    let mutable total = totalCost
    let mutable sv    = salvage
    let mutable life  = estLife
    
    interface IDepreciation with
        member this.Cost         with get() = total and set(value) = total <- value
        member this.SalvageValue with get() = sv    and set(value) = sv    <- value
        member this.UsefulLife   with get() = life  and set(value) = life  <- value
        member this.DepreciatedValue with get() = (total - sv) / life 

// Units of Production
type ProductionUnits(totalCost, salvage, units, usage) =
    let mutable total = totalCost
    let mutable sv    = salvage
    let mutable life  = units
    let mutable us    = usage
    
    member this.Usage with get() = us    and set(value) = us    <- value
    member this.UnitDepreciation with get() = (total - sv) / life 
    
    interface IDepreciation with
        member this.Cost         with get() = total and set(value) = total <- value
        member this.SalvageValue with get() = sv    and set(value) = sv    <- value
        member this.UsefulLife   with get() = life  and set(value) = life  <- value
        member this.DepreciatedValue with get() = ((total - sv) / life)  * us

// Passing an interface to a function
let getDepreciation (wearing : IDepreciation) output =
    match wearing with
    | :? StraightLine -> string wearing.DepreciatedValue + "/year"
    | :? ProductionUnits -> string wearing.DepreciatedValue + "/" + output
    | _ -> "/Unit of Output of Production"

Classes and Records

 

Introduction

Instead of a simple primitive type, a record is good technique to combine various values of primitive types. Once the record has been created, it can be used in a class like a normal type. For example, a record can be passed to a method of a class such as a constructor. Here is an example:

type Employee = {
    EmployeeNumber : int
    FirstName      : string
    LastName       : string
    PayRate        : CompensationCategory }

type Payroll(worker : Employee, units) = . . .

A Record as a Field or a Property

A member of a class can be created from a record. For example, a property of a class can be based on a record. Here are examples:

open System
open System.Windows.Forms

module Records =
    type CompensationCategory =
    | PieceworkRate
    | DifferentialPieceRate

    type Employee = {
        EmployeeNumber : int
        FirstName      : string
        LastName       : string
        PayRate        : CompensationCategory }

module Compensation =
    type Payroll(worker : Records.Employee, units) =
        let w = ref worker
        let u = ref units

        member this.Employee with get() = !w and set(value) = w := value
        member this.Units    with get() = !u and set(value) = u := value
        member this.GrossSalary with get() =
                                    match w.Value.PayRate with
                                    | Records.PieceworkRate -> !u * 2.25
                                    | Records.DifferentialPieceRate ->
                                        if !u <= 150.00 then !u * 2.25
                                        elif !u <= 350.00 then
                                            let first150 = 150.00 * 2.25
                                            let others = (!u - 150.00) * 2.55
                                            first150 + others
                                        else
                                            let first150 = 150.00 * 2.25
                                            let between151And350 = 200.00 * 2.55
                                            let others = (!u - 350.00) * 2.85
                                            first150 + between151And350 + others

let mutable payRate : Records.CompensationCategory = Records.PieceworkRate

let microchipCompany = new Form()
microchipCompany.Text   <- "Microchip Company"
microchipCompany.Width  <- 265
microchipCompany.Height <- 325

let lblEmployeeNumber = new Label()
lblEmployeeNumber.Left  <- 17
lblEmployeeNumber.Top   <- 20
lblEmployeeNumber.Width <- 90
lblEmployeeNumber.Text  <- "Employee #:"
microchipCompany.Controls.Add lblEmployeeNumber

let txtEmployeeNumber = new TextBox()
txtEmployeeNumber.Left  <- 116
txtEmployeeNumber.Top   <-  17
txtEmployeeNumber.Width <-  75
microchipCompany.Controls.Add txtEmployeeNumber

let lblFirstName = new Label()
lblFirstName.Left  <- 17
lblFirstName.Top   <- 46
lblFirstName.Width <- 90
lblFirstName.Text  <- "First Name:"
microchipCompany.Controls.Add lblFirstName

let txtFirstName = new TextBox()
txtFirstName.Left  <- 116
txtFirstName.Top   <-  43
txtFirstName.Width <-  75
microchipCompany.Controls.Add txtFirstName

let lblLastName = new Label()
lblLastName.Left  <- 17
lblLastName.Top   <- 72
lblLastName.Width <- 90
lblLastName.Text  <- "Last Name:"
microchipCompany.Controls.Add lblLastName

let txtLastName = new TextBox()
txtLastName.Left  <- 116
txtLastName.Top   <-  69
txtLastName.Width <-  75
microchipCompany.Controls.Add txtLastName

let lblPayCategory = new Label()
lblPayCategory.Left  <- 17
lblPayCategory.Top   <- 98
lblPayCategory.Width <- 90
lblPayCategory.Text  <- "Pay Category:"
microchipCompany.Controls.Add lblPayCategory

let lblWorkPerformed = new Label()
lblWorkPerformed.Left  <-  17
lblWorkPerformed.Top   <- 128
lblWorkPerformed.Width <-  290
lblWorkPerformed.Text  <- "Work Performed ______________________"
microchipCompany.Controls.Add lblWorkPerformed

let cbxPayCategories = new ComboBox()
cbxPayCategories.Left  <- 117
cbxPayCategories.Top   <-  95
// cbxPayCategories.Width <-  75
cbxPayCategories.Items.AddRange [| "Piecework Rate"; "Differential Piece Rate" |]
let cbxPayCategoriesSelectedIndexChanged e =
    match cbxPayCategories.Text with
    | "Piecework Rate" -> payRate <- Records.PieceworkRate
    | "Differential Piece Rate" -> payRate <- Records.DifferentialPieceRate
    | _ -> ()
cbxPayCategories.SelectedIndexChanged.Add cbxPayCategoriesSelectedIndexChanged
microchipCompany.Controls.Add cbxPayCategories

let lblUnitsProduced = new Label()
lblUnitsProduced.Left  <-  17
lblUnitsProduced.Top   <- 163
lblUnitsProduced.Width <-  90
lblUnitsProduced.Text  <- "Units Produced:"
microchipCompany.Controls.Add lblUnitsProduced

let txtUnitsProduced = new TextBox()
txtUnitsProduced.Left  <- 116
txtUnitsProduced.Top   <- 160
txtUnitsProduced.Width <- 75
txtUnitsProduced.Text  <- "0"
microchipCompany.Controls.Add txtUnitsProduced

let btnCalculate = new Button()
btnCalculate.Left  <- 116
btnCalculate.Top   <- 190
btnCalculate.Text  <- "Calculate"

let lblGrossSalary = new Label()
lblGrossSalary.Left  <-  17
lblGrossSalary.Top   <- 224
lblGrossSalary.Width <-  90
lblGrossSalary.Text  <- "Gross Salary:"
microchipCompany.Controls.Add lblGrossSalary

let txtGrossSalary = new TextBox()
txtGrossSalary.Left  <- 116
txtGrossSalary.Top   <- 221
txtGrossSalary.Width <- 75
txtGrossSalary.Text  <- "0.00"
microchipCompany.Controls.Add txtGrossSalary

let btnCalculateClick e =
    let items = float txtUnitsProduced.Text
    let producer = { Records.EmployeeNumber = int txtEmployeeNumber.Text; Records.FirstName = txtFirstName.Text; Records.LastName = txtLastName.Text; Records.PayRate = payRate }

    let pay = new Compensation.Payroll(producer, items)
        
    txtGrossSalary.Text <- sprintf "%0.02f" pay.GrossSalary

btnCalculate.Click.Add btnCalculateClick
microchipCompany.Controls.Add btnCalculate

let btnClose = new Button()
btnClose.Left  <- 116
btnClose.Top   <- 254
btnClose.Width <-  75
btnClose.Text  <- "Close"
let btnCloseClick e = microchipCompany.Close()
btnClose.Click.Add btnCloseClick
microchipCompany.Controls.Add btnClose

do Application.Run microchipCompany

Here is an example of testing the record:

A Record as a Field or a PropertyA Record as a Field or a Property

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. 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.

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)
    
let order = MealOrder("LS01", TimePeriod.LunchSpecial)

order.Present()

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) = . . .

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)

Passing an Interface to a Method

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

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.

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:

open System
open System.Windows.Forms

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) =
    sprintf "Point Coordinates: A(%d, %d)" pt.X pt.Y

let exercise = new Form(Text = "Geometry")

let lblPoint = new Label(Left = 12, Top = 12, Width = 200)
exercise.Controls.Add lblPoint

let lblAnother = new Label(Left = 12, Top = 42, Width = 200)
exercise.Controls.Add lblAnother

let pt = new Point()

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

let one = new Point()
one.Equivalent pt

lblAnother.Text <- showPoint one

do Application.Run exercise

This would produce:

Passing a Class as Parameter to its Own Methods

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.

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:

open System
open System.Windows.Forms

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) =
    sprintf "Point Coordinates: A(%d, %d)" pt.X pt.Y

let exercise = new Form(Text = "Geometry")

let lblPoint = new Label(Left = 12, Top = 12, Width = 200)
exercise.Controls.Add lblPoint

let lblAnother = new Label(Left = 12, Top = 42, Width = 200)
exercise.Controls.Add lblAnother

let lblOneMore = new Label(Left = 12, Top = 74, Width = 200)
exercise.Controls.Add lblOneMore

let pt = new Point()

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

let one = new Point()
one.CreatePointOneUnitAway pt
lblAnother.Text <- showPoint one

one.CreatePointOneUnitAway(Point(-8, -3))
lblOneMore.Text <- showPoint one

do Application.Run exercise

This would produce:

Passing a Class as Parameter to its Own Methods

   
   
 

Home Copyright © 2014-2015, FunctionX Home