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

Implementing interface method returning byref<'t> cannot just throw #5776

Closed
marklam opened this issue Oct 16, 2018 · 10 comments
Closed

Implementing interface method returning byref<'t> cannot just throw #5776

marklam opened this issue Oct 16, 2018 · 10 comments

Comments

@marklam
Copy link

marklam commented Oct 16, 2018

For an interface method with a byref<'t> return, it's not possible to provide an implementation that just throws an exception

Repro steps

open System

type Ii<'T> =
    abstract GetSpan : int -> ReadOnlySpan<'T>

[<Struct>]
type X(value : int) =
    interface Ii<int> with
        member __.GetSpan n = ReadOnlySpan()

[<Struct>]
type Y(value : int) =
    interface Ii<int> with
        member __.GetSpan n = failwith "Nope"

Expected behavior

Compiles

Actual behavior

The line

member __.GetSpan n = failwith "Nope"

reports the error
FS0412 A type instantiation involves a byref type. This is not permitted by the rules of Common IL.

Known workarounds

Include an unreachable dummy return value

        member __.GetSpan n = failwith "Nope";  ReadOnlySpan()

Related information

Visual F# Tools 10.2 for F# 4.5 15.8.0.0. Commit Hash: 39fd7b8.

@cartermp
Copy link
Contributor

Thanks, that definitely looks like a bug.

@cartermp cartermp added this to the 16.0 milestone Oct 16, 2018
@dsyme
Copy link
Contributor

dsyme commented Oct 18, 2018

It's by design. failwith is a generic function instantiated with the return type. The same would apply to Unchecked.defaultof<_>. Byrefs are just whacky wierd on .NET

You can record a language suggestion if you like

@cartermp
Copy link
Contributor

We'll have to strongly consider doing work here. Since both raise and failwith are generic functions, you cannot throw an exception like you can in C#:

    interface Ii<T>
    {
        int GetSpan(ReadOnlySpan<T> sp);
    }

    struct Y : Ii<int>
    {
        public int GetSpan(ReadOnlySpan<int> sp)
        {
            throw new Exception("Nope");
        }
    }

@dsyme
Copy link
Contributor

dsyme commented Oct 19, 2018

Yes, it would make sense to do something here, though it is a bit of a corner case. It's shame .NET generics have this limitation on byref instanatiations.

@marklam
Copy link
Author

marklam commented Oct 19, 2018

Could the 'something' also encompass the pipe operator? (like #5286)

@dsyme
Copy link
Contributor

dsyme commented Oct 19, 2018

Could the 'something' also encompass the pipe operator? (like #5286)

No. I'm very loathe to go down that long slippery slope since it's a bug farm.

Anything we do here would be for raise and nothing else. Not even for failwith.

@marklam
Copy link
Author

marklam commented Oct 19, 2018

No. I'm very loathe to go down that long slippery slope since it's a bug farm.

Fair enough :-)

@cartermp
Copy link
Contributor

@dsyme Do you still think a language suggestion is necessary, or should we just use this to track and update the RFC?

@dsyme
Copy link
Contributor

dsyme commented Oct 25, 2018

@dsyme Do you still think a language suggestion is necessary, or should we just use this to track and update the RFC?

We can use this to track I suppose, special casing raise is fine

@cartermp
Copy link
Contributor

Filed: fsharp/fslang-suggestions#872

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants