After I posted this comment https://github.com/fsharp/fslang-suggestions/issues/349#issuecomment-1124206512 I'm still feeling I'm missing out...
Sample code reproduced here for the reader's convenience:
let spanOfOptString(os: Option<string>) =
match os with Some(s) -> s.AsSpan()
| None -> raise(Exception())
error FS0412: A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
So, F# types a no-return function raise
as Exception -> 'a
with a free 'a
("the OCaml way"), and the type variable happened to be bound to a byref type ReadOnlySpan
, which was illegal. I felt like I was punished for a crime I didn't commit...
I could find a workaround which was something like
let checkedSpanOfString(os: Option<string>) =
match os with Some(s) -> s.AsSpan()
| None -> raise(Exception()) // 'a = unit
ReadOnlySpan.Empty // both arms: ReadOnlySpan<char>
https://sharplab.io/#gist:32b520574fde97de8d7389ab04f64bc4
but IMHO this is somewhat ugly. And I don't think we should expect something equivalent to .Empty
to be available for all byref types? (I don't think I've ever used any other byref types than (ReadOnly
)Span
/Memory
but that's another story)
While F# core team doesn't seem to be moving towards introducing the bottom type to the language (which is perhaps a sensible engineering decision),
does anybody have a better alternative to make this work?
Update
@chadnt's answer can be inlined to get
let checkedSpanOfString(os: Option<string>) =
let s = match os with Some(s) -> s
| None -> raise(Exception())
s.AsSpan()
https://sharplab.io/#gist:a5eab805c539c45048b4072fa7b096c5
Its IL looks much simpler than my original version
CodePudding user response:
It looks like assigning the string value first seem to solve it.
open System
let valueOrRaise = function
| Some v -> v
| None -> raise(Exception())
let checkedSpanOfString (os: string option) =
let s = valueOrRaise os
s.AsSpan()
https://sharplab.io/#gist:2ca959f498be87f1b52212182af237b4
In FSI:
> (checkedSpanOfString (Some "foo")).ToString();;
val it: string = "foo"