1
votes

Polymorphism for inputs was solved using functional idiomatic approach and now looking forward to solve it for return types that involved a JSON serializer which actually demands to know the type of the record.

Input parameters were enforced to have some specific fields as mandatory and the solution allowed to pass different types as long as the field members existed. Solution was referred to as SRTP or structural (or duck) typing.

Now I've a roadblock where this function is essentially a web service call which returns the latest JSON schema based on the type of the object passed. I pass in mandatory fields (Registration, Owner, Wheels) only and the server returns the original mandatory data along with the custom fields and both types (Car, Truck) have different kinds of JSON schemas.

The block is with JSON serializer that needs to know the type of the object being passed and the type has to be hard coded in order to serialize.

So in a way function has both polymorphic inputs and outputs.

type Car = {
    Registration: string
    Owner: string
    Wheels: int
    customAttribute1: string
    customAttribute2: string
}

type Truck = {
   Registration: string
   Owner: string
   Wheels: int
   customField5: string
   customField6: string
}


let inline someComplexFun v  =
    let owner =  (^v: (member Owner: string)(v)) 
    let registration = (^v: (member Registration: string)(v))
    // send the mandatory fields to server to fetch rest of the custom fields.

    use response = request.GetResponse() :?> HttpWebResponse
    use reader = new StreamReader(response.GetResponseStream())
    use memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(reader.ReadToEnd()))
    (new DataContractJsonSerializer(typeof<Car>)).ReadObject(memoryStream) :?> Car

Now this last line essentially will change if Truck type was passed

(new DataContractJsonSerializer(typeof<Truck>)).ReadObject(memoryStream) :?> Truck

Note: Now If there's a lateral approach using a different functional idiomatic way, I'm flexible to choose a different path. As long as function can not only receive and return these two specific types.

P.S. Is reflection an answer to this?

1
Well, the very definition of a function is taking in an input of a certain type and generating an input of the same or another type. Doesn't DataContractSerializer retain info about the type and do generics? If not your life is a bit difficult, and maybe you need to switch to another serializer. But first I would break up your your function, at least into two, serialization should be separate from everything else. - s952163

1 Answers

0
votes

If necessary, you can check the type info and pass that on. Since you are already using typeof, you can use that on v as well. If we remain within the same example:

type Vehicle = {
    Registration: string
    Owner: string
    VehicleType: System.Type
}

let inline someComplexFun v  =
   let t = typeof<'v>
   let owner =  (^v: (member Owner: string)(v)) 
   let registration = (^v: (member Registration: string)(v))
   {Registration = registration; Owner = owner; VehicleType = t}

You could use t to identify which serializer to apply or extract it from the VehicleType field.