Summary
I want to instantiate a class by only assigning some named parameters dynamically. I want to do this based on whether or not some values are None.
So something that looks like this:
new PhotoEditInput(id=id, title=titleOpt, slug=slugOpt, description=descrOpt, origImageHash=hashStrOpt)
PhotoEditInput's constructor has 64 overloads because it can take any of 6 parameters while leaving the others unassigned. So the constructor can be called from new PhotoEditInput() with no params at all, to new PhotoEditInput(id: string, slug: string, title: string, description: string, orderindex: string, origImageHash: string) with all params assigned, and anything in between.
Each of the xOpt values is an option and I want to leave Nones unassigned. So e.g. if titleOpt is None then I don't want to assign the title named parameter.
Question: How can I assign these named variables or pick a specific overload dynamically?
Background
I am using GraphQLProvider to generate queries and mutations. I want to create a function that lets a user edit any field of a photo object while leaving all the others unchanged.
So for the optional fields in the below function if they are None I don't want to change that field in photo with ID id. I only want the Some values changed.
let changePhotoFields (id : string) (titleOpt : string option) (slugOpt : string option) (descrOpt : string option) (hashOpt : string option) =
// function body
PhotoEditInput is an alias for GraphQlClient.Types.Photos_set_input, which is a type generated by GraphQLProvider that represents the input of changes to a photo entity.
I initially tried instantiating the class with an empty constructor and assigning the fields afterwards but F# won't let me do this. Probably because they are Option<string> with get so I assume that means they are not settable? I'm not so familiar with the .NET ecosystem.
let makeNewPhotoEditInput id titleOpt slugOpt descrOpt hashOpt =
let input = new PhotoEditInput(id=id)
input.Title <- titleOpt // Property 'Title' cannot be set
input.Slug <- slugOpt // Property 'Slug' cannot be set
input.Description <- descrOpt // Property 'Description' cannot be set
input.OrigImageHash <- hashOpt // Property 'OrigImageHash' cannot be set
input
If I can get this way to work that would probably be the simplest option. Is there a way I can set these fields despite them not having setters?
I'm now trying to assign fields conditionally using named arguments. E.g. something like this:
new PhotoEditInput(id=id, title=titleOpt, slug=slugOpt, description=descrOpt, origImageHash=hashOpt)
However this doesn't work because title, slug, and the other args are strings, not string options.
I've also tried making them strings but nullable so that F# doesn't complain about the types, but that breaks at runtime.
let toNull = function Some x -> x | _ -> null
new PhotoEditInput(id=id, title=toNull titleOpt, slug=toNull slugOpt, description=toNull descrOpt, origImageHash=toNull hashOpt)
Apparently the constructor can't handle nulls – even though presumably not assigning an argument is no worse than just making it null ♂️.
So the question is: how can I dynamically choose a specific overload that only assigns fields that are non-null?
In JS if a function supported (the equivalent of) named arguments you'd do something like
new PhotoEditInput({ id: id, title: titleOpt ?? undefined, slug: slugOpt ?? undefined, description: descrOpt ?? undefined, origImageHash: hashOpt?? undefined })
is there an equivalent in F#? Perhaps with some of F#'s introspection magic? If so how would I do this?
EDIT in response to @CaringDev's answer:
It looks like the constructor does take 64 overloads. You can pass each parameter individually. I'd imagine that the only way to differentiate between them is by naming the parameter you're assigning, e.g. new PhotoEditInput(id=id).
Maybe the fact that it's a generated type means it can do things that you can't do with regular classes, I don't know. Either way your way won't work unfortunately.
In addition to that I'm also getting a warning that This downcast will erase the provided type 'PhotoEditInput' to the type 'RecordBase'.

