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

F# Status on CoreRT and UWP #6055

Open
charlesroddie opened this issue Jul 5, 2018 · 18 comments

Comments

Projects
None yet
9 participants
@charlesroddie
Copy link
Contributor

commented Jul 5, 2018

[2018-12-06 update] F# UWP apps can be released on the Windows Store.
#6055 (comment)


Recent testing has assessed the compatibility of F# with CoreRT and .NET Native. Only minor issues have been found, which are easily worked around (see specific issues below).

CoreRT issues can always be tracked and worked on here, and .NET Native issues can now also be tracked now that users can compile using it (See gatekeeper.xml section).

This post is a documentation of the status of F# and CoreRT as requested by @dsyme. This post will be kept up to date. One purpose is to inform F# developers using CoreRT and .NET Native. The second purpose is to inform the request for allowing F# usage on the Windows Store, a 1 line change that may require approval.

Testing

CoreRT and .Net Native went through basic tests (the F# cheatsheet), and specific tests (tail calls and highly nested generics as recommended by @MichalStrehovsky, and some of the F# test suite). .Net Native was further tested in a production app using typical F# structures (a symbolic algebra engine using large discriminated union trees, standard usage of record types, reactive UI using Xamarin.Forms, SQLite). CoreRT is used by a number of F# users already. (@ChrisPritchard has written a number of games without encountering any issues.)

Specific Issues

Issue UWP (.Net Native) CoreRT Workaround
sprintf Fails Can work for some types using rd.xml Use concrete string methods like String.Format.
.ToString() on discriminated unions and record types Fails Fails Override .ToString() on these types.
LINQ expressions Fails Fails Use an alternative to LINQ (e.g. SQL) or use LINQ from C#.
.tail instructions Ignored OK Avoid a style that is dependent on optimization of complex tail calls.
F# Events OK Fails Use standard .Net Events on CoreRT.
Highly nested generics OK Fails (Not yet encountered in realistic code.)
char enums Fails ? Use int enums

Of the issues affecting UWP, lack of support for .tail does not break typical F# code (as Fable and historically mono AOT prove), and the other two issues have simple workarounds.

See https://github.com/FoggyFinder/FSharpCoreRtTest/blob/master/README.md#description-of-current-issues for more detail, and the MainIssues branch for relevant code.

.Net Native: gatekeeper.xml blocks F#

The remaining problem is a non-technical one. F# usage of .Net Native is blocked by gatekeeper.xml.

<FSharpRule on="true">
<ErrorLevel>error</ErrorLevel>
...
</FSharpRule>

This can be disabled on user systems to enable compilation with .Net Native, allowing creation of working UWP apps. However these apps cannot be successfully uploaded to the store since they will fail the F# test when compiling on Microsoft servers. We therefore need official editing of GatekeeperConfig.xml, either by turning it off or by replacing error with warning.

Reasons to allow F# UWP applications on the Windows Store:

  1. Already promised. 2015-10 @crutkas: "We are committed to bringing F# support to .NET Native."

  2. No technical work required. There are no technical issues currently blocking F# usage.

  3. Large user demand. 1500+ votes for Add F# support for .NET Native and 2000+ votes for F# support in .Net native for UWP when those were active. This thread is a continuation of F# Support in .NET Native and UWP and .Net Native F# Support; the latter contains use cases.

@morganbr

This comment has been minimized.

Copy link
Contributor

commented Jul 11, 2018

@charlesroddie, thank you for investigating this in depth. Can you please tell us more about what goes wrong when you try to use sprintf, ToString and Quotations on .NET Native (UWP)?

@charlesroddie

This comment has been minimized.

Copy link
Contributor Author

commented Jul 11, 2018

sprintf gives a System.IndexOutOfRangeException on UWP, as does using ToString on DUs and record types. On CoreRT there is an NRE. @zpodlovics identified the sprintf issue as coming from dynamic code generation:

let mi = typeof<ObjectPrinter>.GetMethod("GenericToString", NonPublicStatics)
let mi = mi.MakeGenericMethod(ty)
mi.Invoke(null, [| box spec |])
@charlesroddie

This comment has been minimized.

Copy link
Contributor Author

commented Jul 13, 2018

There is no general issue with F# quotations; the only issue we have found is with LINQ. The function causing the problem is Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.QuotationToExpression. This gives a fail fast error.

E.g. if db is an sqlite connection, db.QueryAsync<T>() .Table<T>() .OrderByDescending(fun x -> x.Timestamp) fails. A workaround is to use SQL: db.QueryAsync<T>("select * from T order by Timestamp desc").

LINQ requires care even from C# and inherently uses a lot of reflection I suppose.

F# query expressions seem to work OK.

@jptarqu

This comment has been minimized.

Copy link

commented Aug 7, 2018

Has there been any progress on this (official editing of GatekeeperConfig.xml)?

Thank you all for all your hard work.

@MichalStrehovsky

This comment has been minimized.

Copy link
Member

commented Sep 13, 2018

We are looking into removing the F# blocking in the Store compilation machines for the next release of .NET Native for UWP apps.

F# will remain officially unsupported, but we'll not prevent people who understand the implications (and who did enough testing to make sure it works okay for their use case) from uploading to the Store. People will still need to hack their local Visual Studio installation to remove the blocking locally because we don't believe the experience of using F# with the level of support the .NET Native compiler has is anywhere near pleasant.

The focus of the .NET Native team has been on completing ARM64 support in the next release. The work to lift the remaining technical limitations to fully support F# is unfortunately non-trivial.

For an example of the technical limitations on top of the issues found by the testing in the top post, you can try this:

  1. Create a blank UWP app project in Visual Studio
  2. Add a new F# .NET Standard 2.0 library project
  3. Put this in the F# project:
namespace FSharpLibrary

module Fib =
    let rec fib = function
        | n when n=0I -> 0I
        | n when n=1I -> 1I
        | n -> fib(n - 1I) + fib(n - 2I)
  1. Add a reference to the F# project from the UWP app and add a call to the method in F# from it.
  2. Build a Release version of the app

The .NET Native compiler will emit a couple warnings about unsupported LDTOKEN instructions to stdout (there's several places in FSharp.Core.dll where the IL is doing LDTOKEN of an uninstantiated generic method, such as in static System.Void <StartupCode$FSharp-Core>.$Query..cctor() - this is not currently supported by the native code generator backend we use. Then the compiler will crash with an internal error.

@charlesroddie

This comment has been minimized.

Copy link
Contributor Author

commented Sep 13, 2018

Great news! Allowed but not officially supported is the sensible decision.

For an example of the technical limitations on top of the issues found by the testing in the top post...

Thanks. We will check this and keep the issue list updated.

@dsyme

This comment has been minimized.

Copy link

commented Sep 13, 2018

The .NET Native compiler will emit a couple warnings about unsupported LDTOKEN instructions to stdout (there's several places in FSharp.Core.dll where the IL is doing LDTOKEN of an uninstantiated generic method, such as in static System.Void <StartupCode$FSharp-Core>.$Query..cctor() - this is not currently supported by the native code generator backend we use. Then the compiler will crash with an internal error.

We can likely fix this easily in a future FSharp.Core (e.g. change to emit ldtoken of an instantiated generic method and then call GetGenericMethodDefinition() )

@FoggyFinder

This comment has been minimized.

Copy link

commented Sep 13, 2018

For an example of the technical limitations on top of the issues found by the testing in the top post, you can try this:

hm, I can't reproduce it:

test_uwp

Did I do something wrong?

@MichalStrehovsky

This comment has been minimized.

Copy link
Member

commented Sep 14, 2018

We can likely fix this easily in a future FSharp.Core (e.g. change to emit ldtoken of an instantiated generic method and then call GetGenericMethodDefinition() )

That would help! We've had an issue open to make it work for a long time. It never met the bar because we thought only IL obfuscators emit that kind of IL (and we have hack in place that checks if the subsequent instruction is a simple pop, which fixes the obfuscator...).

hm, I can't reproduce it

What version of the .NET Native compiler did you use? I used 2.1.8. Also, do did you modify the RD.XML in the empty UWP app template? The problem goes away after removing the *Application* line because we no longer need to compile all of FSharp.Core, only a subset that's statically needed.

@FoggyFinder

This comment has been minimized.

Copy link

commented Sep 14, 2018

What version of the .NET Native compiler did you use? I used 2.1.8.

The same.

Also, do did you modify the RD.XML in the empty UWP app template?

No, I didn't. My rd (without comments and whitespaces):

<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
  <Application>
    <Assembly Name="*Application*" Dynamic="Required All" />
  </Application>
</Directives>

Version of FSharp.Core: 4.5.2

@MichalStrehovsky

This comment has been minimized.

Copy link
Member

commented Sep 14, 2018

Here's my project: FSharpApp.zip

One thing I noticed is that the compiler only crashes when building x86. It compiles fine for x64.

@FoggyFinder

This comment has been minimized.

Copy link

commented Sep 14, 2018

One thing I noticed is that the compiler only crashes when building x86. It compiles fine for x64.

yep, exactly, I had x64

@JaggerJo

This comment has been minimized.

Copy link

commented Nov 16, 2018

Are we stuck on "Allowed but not officially supported" for now or are there any plans towards "Officially supported" ?

@charlesroddie

This comment has been minimized.

Copy link
Contributor Author

commented Dec 6, 2018

@JaggerJo: yes we are, as fully described in @MichalStrehovsky's post.

We can confirm that .Net Native compilation works now on Store compilation machines, and we have released our beta F# app on the store (link).

@charlesroddie

This comment has been minimized.

Copy link
Contributor Author

commented Mar 13, 2019

Direct access to UWP UI classes from F# depends on either

  1. Creating an F# template for a UWP class library analogous to the current C#/VB templates, or
  2. Exposing Windows.Foundation.UniversalApiContract as NuGet package, which would allow creating a plain net core/standard class library and adding this package.

Until then F# can only be used 1. in parts of a solution that don't have to reference controls directly (i.e. models, viewmodels), or 2. indirectly via Xamarin.Forms.

@pauldorehill

This comment has been minimized.

Copy link

commented Jun 6, 2019

@charlesroddie are there any workarounds to getting access to the UWP UIs (similar to the gatekeeper hack)? I'm using Fabulous and writing some custom UWP renderers, but as it stands I need to use a C# UWP Library for the views.

@charlesroddie

This comment has been minimized.

Copy link
Contributor Author

commented Jun 9, 2019

@pauldorehill Yes using C# for the custom renderers is the right approach and will be for the next year or so.

WinUI 3.0, in whatever form that takes, is likely to have better F# support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.