Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for F#9 Nullable #293

Open
marklam opened this issue Dec 19, 2024 · 5 comments
Open

Support for F#9 Nullable #293

marklam opened this issue Dec 19, 2024 · 5 comments
Labels
enhancement New feature or request good first issue Good for newcomers

Comments

@marklam
Copy link

marklam commented Dec 19, 2024

Is your feature request related to a problem? Please describe.
Using the option CE with <Nullable>enable</Nullable> in the .fsproj, some let! declarations need type annotations to compile.

An example is in the repo https://github.com/marklam/Nullness, but the crux of it is:

module Program

open FsToolkit.ErrorHandling

type [<Measure>] m
type [<Measure>] r

type P = | P
type S = | S

let y (s : S option ) (p : P option)=
    option {
        // Needs annotation
        //let! (_s : S) = s
        let! _s = s

        // Needs annotation
        //let! (_p : P) = p
        let! _p = p

        ()
    } |> ignore

[<EntryPoint>]
let main argv =
    0

Describe the solution you'd like
The option CE to work without hints to the type inference.

Describe alternatives you've considered
Adding type hints.

(I also tried rebuilding FsToolkit.ErrorHandling with <Nullable>enable</Nullable> but I didn't know enough about the implementation of Option.bind etc to achieve anything.)

Additional context
This was originally raised as an issue with F#9's nullability changes dotnet/fsharp#17776

@TheAngryByrd
Copy link
Collaborator

This is gonna be difficult. I've been trying to keep the Fsharp.Core version as low as possible. We'd probably have to either bump the version and force everyone onto 9 or create a separate project that shadows things similar to FSharp.Core.Extended.

@marklam
Copy link
Author

marklam commented Dec 21, 2024

Ah, I see, there are knock-on-effects.

Is the problem that FSharp.Core > 6 would force consumers to update their projects to a newer SDK, or that it could cause conflicts with packages that have an upper limit on FSharp.Core?

@TheAngryByrd
Copy link
Collaborator

Yeah it kind of relates to #187.

I think having another project that shadows would be the best case (but albeit a alot more to maintain because we'll need Async/Task/VOption and corresponding tests)

@TheAngryByrd
Copy link
Collaborator

TheAngryByrd commented Dec 21, 2024

Here's a prototype if anyone wants to take an run with it.

module OptionCE =

    type OptionBuilderBase () =

        member inline _.Bind(x: 'b voption,[<InlineIfLambda>] f : 'b -> voption<'c>) : voption<'c> =
            ValueOption.bind f x

        member inline _.BindReturn(x: 'b voption,[<InlineIfLambda>] f : 'b -> 'c) : voption<'c> =
            ValueOption.map f x

        member inline _.Return (x: 'a) = ValueSome x

        member inline _.ReturnFrom (x: 'a voption) = x

        member inline _.Zero () = ValueSome ()

        member inline _.Delay([<InlineIfLambda>] f : unit -> voption<_>) = f   

        member inline _.Source(o: 'a voption) = o
        member inline _.Source(o : 'a option) = Option.toValueOption o
        member inline _.Source(o) = ValueOption.ofObj o


    type OptionBuilder () =

        inherit OptionBuilderBase ()

        member inline _.Run(f) = f () |> ValueOption.toOption


    type ValueOptionBuilder () =

        inherit OptionBuilderBase ()

        member inline _.Run(f) = f () 

    [<AutoOpen>]
    module OptionCEExtensions =
        let option = OptionBuilder ()
        let voption = ValueOptionBuilder ()

module OptionExamples =
    open OptionCE

    type AB = A | B
    type AbNull = AB | null

    let y (s : int option) (p : AB | null)=
        option {
            let! (_s) = s
            let! p = p
            let isa = p.IsA
            let! resizeArray = ResizeArray<_>()
            let! r = ResizeArray<int>()
            let! s = "null"
            let! l  = ValueNone
            let! b = None
            let! aaa  = [||]
            return _s, p
        }

@marklam
Copy link
Author

marklam commented Dec 22, 2024

Yes, that prototype works for all the code I tested it in, except for code that has a match or a use! expression, understandably.

@TheAngryByrd TheAngryByrd added enhancement New feature or request good first issue Good for newcomers labels Dec 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

2 participants