简体   繁体   中英

F#: Span, raise, and the bottom type (or lack thereof)

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

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"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM