Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# Generic Records

I am trying to build a generic function to manipulate a record my code looks like:

type Status = Active | Inactive

type IStatus =
    abstract member Status: Status

type User = 
    { 
        Username : string;
        Status : Status
    }
    interface IStatus with
        member x.Status = x.Status


let ChangeStatus<'T when 'T :> IStatus> newStatus (t:'T) =
    {t with Status = newStatus}

Now I get the following error:

expression was expected to have type
    'T    
but here has type
    User    

Obviously I just want to create a type constraint for Records which implement IStatus. Am I thinking too OO? Or is there merit to this approach and how do I create this ChangeStatus function?

Thank you for reading.

like image 836
Mr. Baudin Avatar asked Jun 28 '26 00:06

Mr. Baudin


1 Answers

I don't think it's possible what you're trying to do, because it would need a "generic record cloner" I mean a generic record expression and that's not supported at the moment.

You can create a clone method for each subclass, that should work but you will have to repeat the code to clone the record. It might be a generic solution but involving reflection.

However if you change your design you can get the desired functionality. For instance you can use a generic nested record:

type Status = Active | Inactive

type StatusRecord<'T> =
    { 
        Item   : 'T
        Status : Status
    }

let changeStatus newStatus t = {t with Status = newStatus}

// TEST

type User  = {Username  : string}
type Group = {Groupname : string; members : User list}

let user  = {Status = Active; Item = {Username = "User1"}}
let group = {Status = Active; Item = {Groupname = "Group1"; members = []}}

This is a very lightweight solution, you will write less code but it will change your design which depending on the rest of your code will make sense or not.

like image 71
Gus Avatar answered Jul 01 '26 06:07

Gus