Revert a modified version of the same type in F #

If I have a class hierarchy like

type Employee(name) =
  member val name: string = name

type HourlyEmployee(name, rate) =
  inherit Employee(name)
  member val rate: int = rate

type SalariedEmployee(name, salary) =
  inherit Employee(salary)
  member val salary: int = salary

      

And I want a function that updates the field in a name

clean way, how is this possible? A couple of bad options:

let changeName(employee: Employee) = 
  // no idea what class this was, so this can only return the base class

let changeName<'a when 'a :> Employee>(employee: 'a) =
  // 'a has no constructor

      

The closest I came up with was to make it virtual Employee.changeName

and implement it for each class. It just seems like a lot of extra work and also a mistake, since the return type Employee

must be returned back to the original class.

It looks like there should be an easier and safer way to accomplish such a task. Is this something necessary when cool classes are required?

Update

Yes, I could just change the field name

as implemented in my code, but this is what I want to get away from.

Update 2

The solution I came up with, which meets the security requirements and the brevity of the requirements, would be to define

type Employee<'a> = {name: string; otherStuff: 'a}

      

and then just use the syntax with

to change the name. But otherStuff: 'a

- clearly ugly and hacked code, so I'm still open to better solutions.

+3


source to share


1 answer


If you're looking for something clean and idiomatic F # , then you shouldn't use the inheritance hierarchy in the first place. This is an object oriented concept.

In F #, you can model Employee in the following way using algebraic data types:

type HourlyData = { Name : string; Rate : int }
type SalaryData = { Name : string; Salary : int }

type Employee =
| Hourly of HourlyData
| Salaried of SalaryData

      

This will allow you to create values Employee

like this:

> let he = Hourly { Name = "Bob"; Rate = 100 };;

val he : Employee = Hourly {Name = "Bob";
                            Rate = 100;}

> let se = Salaried { Name = "Jane"; Salary = 10000 };;

val se : Employee = Salaried {Name = "Jane";
                              Salary = 10000;}

      



You can also define a function to change the name in its pure form:

let changeName newName = function
    | Hourly h -> Hourly { h with Name = newName }
    | Salaried s -> Salaried { s with Name = newName }

      

This allows you to change the name of an existing value Employee

like this:

> let se' = se |> changeName "Mary";;

val se' : Employee = Salaried {Name = "Mary";
                               Salary = 10000;}

      

+6


source







All Articles