Skip to content

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

Closed

Description

@marklam

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.

Activity

  1. cartermp commented on Oct 16, 2018

    @cartermp
    Contributor

    Thanks, that definitely looks like a bug.

  2. added this to the 16.0 milestone on Oct 16, 2018
  3. dsyme commented on Oct 18, 2018

    @dsyme
    Contributor

    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

  4. cartermp commented on Oct 18, 2018

    @cartermp
    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");
            }
        }
  5. dsyme commented on Oct 19, 2018

    @dsyme
    Contributor

    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.

  6. marklam commented on Oct 19, 2018

    @marklam
    Author

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

  7. dsyme commented on Oct 19, 2018

    @dsyme
    Contributor

    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.

  8. marklam commented on Oct 19, 2018

    @marklam
    Author

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

    Fair enough :-)

  9. cartermp commented on Oct 19, 2018

    @cartermp
    Contributor

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

  10. dsyme commented on Oct 25, 2018

    @dsyme
    Contributor

    @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

  11. modified the milestones: 16.0, Unknown on Nov 19, 2018
  12. removed this from the Unknown milestone on Jan 31, 2019
  13. cartermp commented on May 26, 2020

    @cartermp
    Contributor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions