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

abstract static member invocation (still) not working in JS #3829

Open
DunetsNM opened this issue May 27, 2024 · 6 comments
Open

abstract static member invocation (still) not working in JS #3829

DunetsNM opened this issue May 27, 2024 · 6 comments

Comments

@DunetsNM
Copy link
Contributor

DunetsNM commented May 27, 2024

Description

It's claimed in Fable 4.18.0 release notes that static interfaces are now supported however my code still fails to compile to JS.

Repro code

It's simplified version of #3822 I reported before (claimed to be fixed by 4.18.0 but it's actually not), you can try to run it in https://fable.io/repl/

type AbstractId<'ImplId when 'ImplId :> AbstractId<'ImplId>> =
    static abstract member Parse: idStr: string -> 'ImplId

type MyId = MyId of int
with 
  interface AbstractId<MyId> with
    static member Parse (idStr: string) =
        System.Int32.Parse idStr |> MyId

let inline parse<'ImplId when 'ImplId :> AbstractId<'ImplId>> (idStr: string) : 'ImplId =
    'ImplId.Parse idStr

printfn "Id constructed: %A" (MyId 1234)
printfn "Id parsed: %A" (parse<MyId> "1234")

Expected and actual results

Expected

Code outputs

Id constructed: MyId 1234
Id parsed: MyId 1234

Just like it does in LINQPad, for example:

image

Actual

It fails to compile. Note that it passes F# compilation step but fails further translation to JS

image

Related information

If I comment out last line it compiles and runs fine:

image

  • Fable version: 4.18.0
  • OS: Windows 11
@DunetsNM
Copy link
Contributor Author

DunetsNM commented May 27, 2024

@ncave I did read the other linked issue #3566 and the comment you left on my previous report : #3822 (comment)

So this is the example code that compiles:

[<Interface>]
type ITesting =
    static member inline Testing x = x

However I still can't understand this pattern nor how to translate my AbstractId<> interface to it. Testing member is not abstract after all, and the ITesting interface has no concrete implementations.

@DunetsNM
Copy link
Contributor Author

DunetsNM commented May 27, 2024

I hope to reuse this code both in the Fable frontend and F# backend, don't mind some conditional compilation if that's the only way currently. But is it even possible at the moment to make it Fable-friendly?

type AbstractId<'ImplId when 'ImplId :> AbstractId<'ImplId>> =
    static abstract member Parse: idStr: string -> 'ImplId

It's defined in a separate library, any concrete "Id" type that implements the interface should be parseable from a string.

@ncave
Copy link
Collaborator

ncave commented May 27, 2024

@DunetsNM You are correct, this is a different issue than #3566. Also, we can leave #3822 closed and keep this one, as they're the same issue.

#3566 was about the F# 8.0 feature concrete static members with implementation in interfaces.

This one is about the F# 7.0 feature abstract static methods in interfaces. I agree it's a feature we should try to support in Fable, despite its drawbacks and misunderstandings.

Until this is fixed, perhaps some other type constraints can work for you as a temporary work-around.

(Side note, please keep in mind that Fable REPL usually lags behind recent Fable releases, so it's not always the best place to check recent Fable release fixes).

@MangelMaxime
Copy link
Member

@DunetsNM You are correct, this is a different issue than #3566. Also, we can leave #3822 closed and keep this one, as they're the same issue.

Sorry, I thought it was fixed by the latest PR but misunderstood it.

(Side note, please keep in mind that Fable REPL usually lags behind recent Fable releases, so it's not always the best place to check recent Fable release fixes).

In general, now days it is updated with each Fable release. I just need to click 2 buttons so unless I forget about it all is good. I was not able to find a way to trigger it from Fable release unfortunately...

@DunetsNM
Copy link
Contributor Author

No worries guys and thanks for the context.

Until this is fixed, perhaps some other type constraints can work for you as a temporary work-around.

Sure, we use SRTP in some places however I find it more limited than IWSAM e.g. member-constrained generic type can't be a part of enclosing generic type signature, it must belong to a function or a member signature. Also after upgrading old net6.0 SRTP-heavy code to net7.0 or net8.0 it started to compile much slower (haven't benchmarked it against IWSAM but hope that it'll be faster). Anyway, neither of those are Fable-specific issues.

@ncave
Copy link
Collaborator

ncave commented Jun 19, 2024

Some thoughts on JS/TS implementation:

Since TypeScript doesn't support static methods in interfaces, we'll have to change the calling convention for those static calls and pass the class that implements the static interface as the first argument, similar to how class methods work in Python.

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