Search code examples
f#type-conversiontype-coercion

nested runtime coercion for a Nullable double


Let's say I have a value defined as a sort of commission formula

let address_commission = 1.0 // minimal simplified example

and I want to apply the above said commission to an amount I'm reading from the DB (the code is from a window WCF service I have in production)

let address_commission = 1.0 // minimal simplified example
new Model.ClaimModel( 
  //RequestRow = i, recounting
  Code = (row.["claim_code"] :?> string), 
  EvtDate = (row.["event_date"] :?> DateTime),
  // skipping lines...
  Amount = (row.["amount"] :?> double) * address_commission,

now I see that the amount line compiles fine, but I also need to include the same commission in the following

PrevAmount = (if row.IsNull("prev_amount")  then Nullable()  else  (row.["prev_amount"] :?> Nullable<double>)),

which is wrong since The type 'float' does not match the type 'obj'

Therefore I've tried also

PrevAmount = (if row.IsNull("prev_amount")  then Nullable()  else  (((row.["prev_amount"] :?> double) * address_commission) :?> Nullable<double>)),

but it also fails with The type 'double' does not have any proper subtypes and cannot be used as the source of a type test or runtime coercion.

What is the correct way to handle this?


Solution

  • :?> is a dynamic cast and it's only checked at run-time so better try to avoid it. If you are accessing databases it helps to open the open FSharp.Linq.NullableOperators namespace. (The link is gone for me but it's somewhere on docs or msdn). Then you can use ?*? and similar operators. For example:

    let x = System.Nullable<float> 4.
    let y = x ?* 3.0
    //val y : System.Nullable<float> = 12.0
    

    You can have ? on either or both sides.

    You will get back a Nullable float which you can coerce to an option with Option.ofNullable(y) or to a double float y.