Cross-platform libraries #3219
Replies: 15 comments 2 replies
-
My +1 for sticking to BCL support as API (i.e. |
Beta Was this translation helpful? Give feedback.
-
This is a fun one. BCL is the obvious impulsive choice since it is the default any developer is going to reach for when trying to do something like file interop. That being said, there are rough edges that I am not crazy about, namely:
I am torn. I guess I am still probably inclined to vote for BCL first, with separately installable libraries to pad it out, but only marginally. It was quite refreshing in Rust to see a very modern, minimalist BCL, where nearly everything is delegated to packages. On the flip side though, the rust ecosystem correctly handles transitive collisions, so generally, you can have deeper dependency graphs without problems. You often end up with deeper graphs and more collisions when you push everything out to packages as they try to reuse common code not found in the BCL (think serialization for example). As we know this is problematic in .NET as the runtime only allows 1 version of the DLL to be loaded at a time. One can dream I guess. The signature file is an interesting idea by the way. |
Beta Was this translation helpful? Give feedback.
-
For information, Thoth.Json next version will provide a single library which works on all the platform at the same time. I suppose BCL via a separate library is probably the easiest solution. It will also make the documentation job/learning curve easier because people will be able to use what they already know. Personal comment/experience: However, the BCL is not really friendly and I find that it is not fun to play with. I had to use it for Nacara and in the end I decided to drop it in favour of minimising my needs to write code that use the BCL especially for watchers. I am still uncertain if this is related to the BCL API per se or the .NET runtime. |
Beta Was this translation helpful? Give feedback.
-
I little background. The main reason for #3212 was that I tried to transpile some Bioinformatics examples at NDC and suddenly discovered that it contained a Leaning towards the BCL is the easiest and more convenient choice. BCL might be the easy (convenient) choice, but as you all agree, it's not a great (simple) experience for F# programmers, and we could do much better with Fable. The idea of minimal Fable library(s) that makes it easy and simple to write cross runtime applications is super interesting the more I think of it. An F# optimized library you would use even when targeting .NET, then as a bonus your code will also work when targeting Python, Node.js, Rust or Dart. I find such an idea really really interesting. One Fable to rule them all ... even when using .NET. |
Beta Was this translation helpful? Give feedback.
-
While this is definitely true, I don't see a reason why we can't do both, i.e. provide support for some targeted BCL IO APIs and a more pleasing F# facade built on top of it. This way we can still enable easy path for porting existing IO code via the well-known and well-documented BCL APIs, and also enable an exciting new API for those that would be willing to try it. IMO this would expand the potential reach of this library to more projects, and perhaps get more collaboration in the process. |
Beta Was this translation helpful? Give feedback.
-
Thanks a lot for your comments! I understand that increasing support for the BCL has some benefits:
Still, I'm not sure they outweigh the drawbacks:
One example of 3 (and I'm sure there are many more) is I also think we can handle the points listed in BCL benefits by writing libraries that resemble the BCL APIs. Say, for example, users only need to replace @ncave When you say adding support for the BCL in a separate package, do you mean that users can add a Nuget reference to their project and this will automatically add the new replacements? At the moment this is not possible with Fable, but we can try to extend the plugin mechanism to support this. |
Beta Was this translation helpful? Give feedback.
-
I assume you mean async stream reading using
The IO package source will be compiled with the rest, no? Maybe I'm missing the point you're describing. I guess my argument for a combined IO library (mostly static BCL IO API + a nice F# facade), is to increase its chance to be useful to a larger audience, and prevent it from falling into obscurity. But perhaps I'm overthinking it, there is always room for more than one IO library, if there is somebody to support it. |
Beta Was this translation helpful? Give feedback.
-
At any rate, I would prefer to move IO, http, etc support to a different repo. Doing it here has several disadvantages:
It's true that we have |
Beta Was this translation helpful? Give feedback.
-
@alfonsogarciacaro Makes sense.
Absolutely, that's what I meant by separate package, apologies if that was unclear. Ultimately, the best outcome is something that people would be happy to contribute to, so in that sense I don't really have a preference either way, just sharing some non-strongly held opinions to be taken with at least 2 grains of salt. |
Beta Was this translation helpful? Give feedback.
-
On that note, are there any pre-existing functional IO libraries to model after, or are we starting with a clean slate? |
Beta Was this translation helpful? Give feedback.
-
Oh one more point about the BCL. Because it starts from C# foundations, it assumes overloads. Overloads are a PITA and are sometimes not supported in other languages. These then often require replacements to be coded into the compiler, which mean they are more than just a namespace redirect. Because of this, splitting this out into a library could create complexity as you might have to make changes in 2 repos. Can plugins help here perhaps? |
Beta Was this translation helpful? Give feedback.
-
@alexswan10k The way I see it, if we want to create these libraries in their own repos we have two options:
In both cases the packages would be distributed through Nuget independently of the Fable tool. I guess that in the case of 1. we'll have to coordinate more between languages because everything will be in the same repo, while in the case of 2. we can distribute replacements for each language separately. |
Beta Was this translation helpful? Give feedback.
-
I think in the end, it depends on what we want to focus on. Do we want to make contribution easy? A normal F# library is probably easier to contribute to than plugins or replacements. Do we want to make the API easy to discover? A normal F# library, means that only the supported function are available. No need for a compatibility matrix Do we want to re-use existing knowledge ? Using the BCL, is the to go in this case. Because, we don't have to design the surface API Do we prefer to make the user experience first class or make it easier for us to "design"? Similar to "API easy to discover", because there will be no "No replacement found for XXX". I think that whatever direction, we choose we need to distribute it as a Package NuGet to avoid polluting the F# compiler. Doing so, will avoid forcing the user to upgrade the compiler itself to get bug fixes for an API. Upgrading the compiler, is always something that can be dangerous if a behavior changed in it etc. While, upgrading a library is more "normal". |
Beta Was this translation helpful? Give feedback.
-
What about modeling such a library e.g |
Beta Was this translation helpful? Give feedback.
-
After #3212 I've been thinking about how to handle IO with Fable. So far, I've always been reluctant to extend support for .NET BCL, but if we want to promote Fable as a true cross-platform solution, we will need to count with ways to deal with things like files, http or json in a consistent manner across languages. However, I'm still not sure if the BCL is the best way for this: because it's easy to miss things (overloads, new APIs...) and because it increases the workload in this repo.
In my opinion it would be preferable to have cross-platform libraries with minimal APIs that we can control better. There have been some attempts by the community but probably we should try to discuss a common approach and publish a couple of libraries that the community can also use as a model.
One solution is two publish two packages that have the same API, like Thoth.Json and Thoth.Json.Net do, but this has caused problems to user, for example when they want to write a cross-platform library (not an app) that uses Thoth.Json as dependency.
The alternative is to have a single package and in the source files use
#if FABLE_COMPILER
for JS-specific code like Fable.React does. But this can become cumbersome pretty quickly and adding more languages to the mix won't make it easier.Recently I added the
FABLE_COMPILER
property when invoking MsBuild so devs can also use it in the .fsproj as well. I'm wondering now if it makes sense to add the language-specific constant as well (e.g.FABLE_COMPILER_RUST
) so we can have an .fsproj that includes different files depending on the language target.We could have a common signature file to ensure all files expose the same API, and when developing we could have different Solution Configurations that select one language or the other.
What do you think? Should we give this a try or do you have any other suggestion (or do you still prefer to have more BCL support)?
@MangelMaxime @dbrattli @ncave @alexswan10k
Beta Was this translation helpful? Give feedback.
All reactions