Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

obj[] and string[] as parameters

I am using Microsoft.FSharp.Reflection.FSharpValue.MakeUnion and this requires a Reflection.UnionCaseInfo and an obj[] (that can be empty) as parameters.

However, I am getting a Type mismatch. Expecting a obj [] but given a string [] The type 'obj' does not match the type 'string' when calling with the result of a function that is a string[].

The simplest example I can create of this happening is as follows (I have a test wrapped around this and it doesn't compile because of the line marked !!.

let one (a:obj[]) = a |> Array.map (fun o->printfn "%A" o) |> ignore
one [|"a";"b";"c"|] // OK!
let str = [|"a";"b";"c"|] //the equivalent of my function return
one str//!!Type mismatch.

I am not sure if I am meant to be casting/converting string[] into an obj[] or ... well, if I am just doing something else wrong that I don't know about.

edit: the actual issue is as described below

let split (by:string) (input:string) = System.Text.RegularExpressions.Regex.Split(input,by)

let buildArgs content = 
 match content with
 | "" -> [||]
 | _ -> content |> split " " //Type mismatch

this is what I used to solve: is there a better way?

 | _ -> content |> split " "|> Array.map (fun s->s:>obj)//make sure obj[] is returned

Casting and Conversions (F#) as reference

I have also tried this

let buildArgs content :obj[] = ... // Type mismatch

but that also gives me an error:

Type Mismatch on the last line of the function if I don't do the Array.map.

like image 700
CodeBeard Avatar asked Aug 18 '13 16:08

CodeBeard


1 Answers

I think your current approach is fine; sometimes I find something like [|for str in ... -> box str|] to be a bit more readable than ... |> Array.map (fun str -> box str) but your mileage may vary. As to why you run into this, there are two somewhat subtle issues here.

As Phil Trelford's comments imply, the .NET type system allows string[] to be treated as obj[] (though doing this from F# requires an upcast and downcast even though the .NET type system isn't so strict). In my opinion this type system "feature" is an abomination and I'd generally avoid it even though it's probably safe in this case (for concurring opinions on the undesirability of array covariance see Covariance and Contravariance in C#, Part Two: Array Covariance and Array covariance: not just ugly, but slow too).

So in general, a string[] won't be treated as an obj[] by the compiler. Why then is everything fine when you pass in [|"a"; "b"; "c"|]? The answer here is that in the specific case of array literals the compiler allows the type of an array expression to be a supertype of each element's type if such a supertype can be inferred (e.g. because it's constrained to obj[] by the signature of another method, as in your case). However, this only works in the case of array literals (that is, expressions of the form [|e1; e2; ... |]).

like image 131
kvb Avatar answered Sep 20 '22 10:09

kvb