Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# Records with members vs Classes

Tags:

f#

In F# you can define records with member functions, and you can also create classes.

type Album = {
    Id: int
    Name: string
    DateReleased: DateTime
    Genre: Genre }
with
    member this.PrintMessage() =
        printf "Hello from %s\n" this.Name

so used

let first = 
        { Id = 1; 
          Name = "Hello World!"
          Genre = KPop;
          DateReleased = DateTime(1991, 8, 12) }
first.PrintMessage()

and with classes it could be something like this.

type Album(
     Id: int, 
     Name: string, 
     DateReleased: DateTime, 
     Genre: Genre ) as me =
     do
         me.PrintMessage()
     member this.PrintMessage() =
         printf "Hello %s" Name

When it is convenient to use one or the other? Can Domain Modeling only be done with records?

Can a class be converted to a record and vice versa by some hidden FSharp Casting?

like image 721
Santi Avatar asked Mar 05 '23 02:03

Santi


1 Answers

Domain modeling can be done with both records AND classes. I think when to use one or the other is primarily a matter of preference and environment. Personally I typically do not use classes, however I know some people who use them quite frequently. Classes rely more on mutation and are more performant at a cost of ease of use. Personally I feel as a general guidance that if you are going to write object oriented style then use classes and if you are writing functional style use records. Records pattern match and deconstruct easier. Part of this distinction is cultural, just because you can do a thing in a particular way doesn't mean other people will be able to understand you easily. Code is written to be read, both by yourself and others. When you pick records or classes it communicates intent about the style and usage of those types. Finally I don't know that a class can be converted to a record within F# and if it can I would actually still recommend against it. This is because using records as classes and classes as records clashes with the cultural norms around those constructs. I personally think your example member is fine for both records and classes. I normally like to use modules with the same name for functions associated with a given type because it can make it less confusing when the function happens to consume something other than the record type. However I don't think anyone well mannered would balk at either of your code examples there.

type Album(
    Id: int, 
    Name: string, 
    DateReleased: string, 
    Genre: int ) as me =
    let mutable genre = Genre  
    //readonly property
    member val Id = Id
    //autoproperty with get and set
    member val Name = Name with get, set
    member val DateReleased = DateReleased with get, set
    //property with explicit get and set
    member this.Genre 
        with get () = genre
        and set (value) = genre <- value

see When should I use let, member val and member this.?

like image 50
VoronoiPotato Avatar answered Mar 12 '23 14:03

VoronoiPotato