question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Unexpected behaviour of static abstract members in F#7

See original GitHub issue

The compiler fails to detect an implemented static member that is the implementation of a static abstract member of an implemented interface, in an unexpected fashion.

Repro steps

The following code shows the behavior.

  type App<'F, 'a> = App of obj

  type IFunctor<'F when 'F :> IFunctor<'F>> =
    static abstract fmap<'a, 'b> : ('a -> 'b) -> App<'F, 'a> -> App<'F, 'b>

  type FList =
    static member wrap (xs : list<'a>) : App<FList, 'a> = App xs
    static member unwrap (App xs : App<FList, 'a>) : list<'a> = xs :?> _

    interface IFunctor<FList> with
      static member fmap<'a, 'b> (f : 'a -> 'b) (v : App<FList, 'a>) : App<FList, 'b> =
        FList.wrap (List.map f (FList.unwrap v))

  // This fails compilation with
  // "error FS0039: The type 'FList' does not define the field, constructor or member 'fmap'."
  let mapper1 f = FList.fmap f

  // This works just fine.
  let private fm<'F when 'F :> IFunctor<'F>> f = 'F.fmap f
  let mapper2 f = fm<FList> f

Expected behavior

I would expect reference to FList.fmap in mapper1 to work. And, if it doesn’t work, then at least I’d expect fm<FList> f in mapper2 to fail as well.

Actual behavior

mapper1 fails compilation with “error FS0039: The type ‘FList’ does not define the field, constructor or member ‘fmap’.” but mapper2 compiles (and runs).

Known workarounds

None.

Related information

F#7/net7.0 build.

Issue Analytics

  • State:closed
  • Created 6 months ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
vzarytovskiicommented, Mar 8, 2023

I am going to close this as by design, please refer to RFC: https://github.com/fsharp/fslang-design/blob/main/FSharp-7.0/FS-1124-interfaces-with-static-abstract-members.md#alternatives, and specifically the conlusion for the implementation - https://github.com/fsharp/fslang-design/blob/main/FSharp-7.0/FS-1124-interfaces-with-static-abstract-members.md#conclusion

If you’d like, you can create a language suggestion for implementing a specific syntax ((MyRepeatSequence :> IGenNext<MyRepeatSequence>).Next(str)), as described in https://github.com/fsharp/fslang-design/blob/main/FSharp-7.0/FS-1124-interfaces-with-static-abstract-members.md#option-d---give-some-kind-of-explicit-call-syntax

0reactions
August-Almcommented, Mar 7, 2023

@En3Tho Thank you for reply! I think I get the picture. What irks me about the F# design choice is not that I have to be explicit about the interface implementation. The questionable design, in my view, is that ListF.fmap f does not work if only the interface is implemented. I would understand such a behavior for an instance member, because then you can actually explicitly cast the instance to the interface, i.e., do (myObj :> IMyInterface).Method (). In the present situation, with a static method, there is no myObj to cast, so there is no explicit way of saying “consider ListF as an IFunctor<ListF> here”. Instead, you’re forced to do the arguably very non-explicit workaround let fm<'F when 'F :> IFunctor<'F>> f = 'F.fmap f in fm<ListF> f.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Static abstract members in interfaces - .NET
NET 6 breaking change where `static` interface members can now be marked ... process the associated metadata and have unexpected behavior.
Read more >
Static abstract methods in interfaces - C# 11.0 draft feature ...
There is currently no way to abstract over static members and write generalized code that applies across types that define those static members....
Read more >
[Open issue]: static abstract interfaces and static classes · ...
With static abstract interface methods, consider: using System; public class C : IMethods { public static void M() { } } internal interface...
Read more >
Why can't I have abstract static methods in C#? - ...
A call to a static method is done through the class name, not through an object reference, and the Intermediate Language (IL) code...
Read more >
Static Program Analysis
Static program analysis is the art of reasoning about the behavior of computer programs without actually running them.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found