Thoughts on the Future of F#/Fable #3351
Replies: 21 comments 22 replies
-
@alfonsogarciacaro I'm glad to hear from you, I'm sure you're juggling a lot of responsibilities so I appreciate your time.
I agree, IMO that's already the case with F# anyway, and by extension with Fable, so no big change there, perhaps just a little shift in the emphasis. E.g. for Rust it already makes most sense to build the domain logic in F#/Fable and interface it with a native adapter. |
Beta Was this translation helpful? Give feedback.
-
Hello @alfonsogarciacaro, glad to hear from you :). When reading your message, I have a fealing that you minimise the interop importance. Most of the suite of my comment is related to that fear.
I don't think trying to focus on provided F#/Fable only for the domain programming is going to provides the effect you have in mind. I think that not a lot of teams are confident in mixing 2 languages on the same side. In the past, some people advocate to use F# for doing domain programming and use C# to consume it. Most of the stories I heard was that the interop between both world was not that smooth (obviously we can put the fault on C# 😝) I also think that even if you move some domain logic to F#, you would still need to be able to interop with the native language. Imagine you are working on a web application, which generates PDF (you fill some form and then a PDF is generated). The stack would be something like that:
You also have 2 system that are trying to communication with each other, so you need to have types that can be created/consumed by both of them. If I try to think of existing project who has the same ideas/constraints, I can think of 2 projects:
Example:
Interop is essential on that project too.
I think of Game engines, because they often have a native runtime/set of APIs and then you use scripting languages to create your game logic. Often, you use a small scripting language like Lua to make most of your scripts. But when, performance matter or if the scripting language is too simple to work safely on complex domain logic then you use another language like Rust, C++, etc. In order, to achieve that interop is essential too. So engine does better than others because they are able to provide tooling that understand code coming from any direction.
This is indeed, something that we are seing more. We see more people using Elmish as a hook to control the state of their React component. Fable 4, with the introduction of JSX support goes in this direction.
I had to deal with a situation where I moved away from a transpiler to a new one. In my case Haxe -> Fable. The situation was that most of the code has been rewritten in the new language, because consuming the utilities from the pre-compile code was difficult and it was easier/more maintainable to move as much code to the new language. I am saying that to say, that opting out of a transpiler is not that easy, if in the same codebase. I agree that F#/Fable community/docs needs to make progress on selling real world usage and not basic code. What I mean by that, is that in Fable most of the example show you how to create a naive website. I think there is a reason why the following ressource are liked/mind opening:
Sorry, if there are other great ressource for Fable. I listed the one that I always redirected people too when they need support If my fear of your minimising the interop feature is not founded then I agree with @ncave in that recently (during last 1-2 year) he community shift from trying to solve everything in Fable. To using native stuff and adding Fable on top of it. A good example of that, is that several person now write their application using React to control global flow and F# via hooks to control the components internal states. Problem, is that this way of doing it is not really communicated. Most of the documentation that can be found, were created during the early days of Fable. |
Beta Was this translation helpful? Give feedback.
-
Good to hear from you again @alfonsogarciacaro. This is a difficult topic, but I'm glad you bring it up. For Python I have basically given up on bindings. I didn't really get started to be honest. The problem with bindings is that they require you to be expert in two languages which is twice as hard (now you have two problems). Python programmers would not want to use F# to generate Python applications anyway. But there could be an interest in generating domain specific libraries using F# and then transpile to the target language e.g. JS and Python, and even be able to reuse the same code for multiple targets. For Python you don't even want to generate Python, but instead use Rust or Go as target to get the performance boost and generate Python extension modules that you can import into your Python application. This is the reason I'm looking at Fable2Go now (so I can use it from Python). But I see two different use-cases for Fable here:
|
Beta Was this translation helpful? Give feedback.
-
Hi @alfonsogarciacaro. I feel for you.. I am currently juggling a new baby + new contract so it seems like there is never enough time any more. I hope you are doing well anyway. My points have pretty much been covered above but I will write them out anyway as there is perhaps some nuance worth considering. I agree that the easiest way to gain traction in languages is to not try and replace everything they already do, but simply provide a toolkit to more efficiently do some currently frustrating things better (e.g. domain modelling). As @ncave has mentioned above we have thought this about Rust for some time. It is very unlikely we are going to be able to improve the interop experience to native Rust, as we do not have the same starting point to work from (our types are too high level, and we do not have type information of the api's we are trying to call). Rather than do this, why not let it be used alongside Rust, where F# code does the high-level stuff, and it is then used like a library from the Rust code (in a typesafe manner). Rust is very noisy at high level domain modelling due to its explicitness, so F# is a perfect fit here. The key reason this works so well is Fable2Rust generates type information, thus making calling it the same experience as calling another Rust function. On the js side, the key missing piece for Fable is good Typescript type generation (either .d.ts or full .ts). In the early days this made no sense as Fable only really attempted to generate javascript (to be consumed by a bundler), but increasingly teams are building everything in Typescript, and they are unlikely to be persuaded to use only F# for everything. By having good types, you make the interop story trivial, and thus the barrier to entry low. You also give teams the ability to "opt out" at any later date (and just inherit the generated Typescript code), making it a low risk decision. I am constantly arguing with people about the "risk" of adopting F# from a management side, so this problem is unfortunately quite real, and pervasive. Personally I see Fable having a bright future as F# |> Typed language. This gets around the enterprise adoption problem, which is perhaps the biggest issue IMO. To @MangelMaxime 's point about C# interop, Typescript and Rust outputs actually have advantages over the current C# interop experience, as both can support discriminated unions (C# still can't do this!), also the F# can coexist alongside your Rust/Ts/Other code (C# requires a totally new project, which is again a big sell). Additionally, you can inherit your generated code if you change your mind. I do hope the C# story will improve over time, although history has not really shown much evidence for this. I do want to stress that the existing full-fat experience is very good, and worth preserving if possible. Perhaps focusing energy on doing everything the existing ecosystems already do well is somewhat of a futile endeavour though. |
Beta Was this translation helpful? Give feedback.
-
I've certainly seen these concerns voiced from others as well. My initial worries about this approach are firstly that people may see this as suggesting that Fable isn't suitable for end-to-end dev, although this depends on how the messaging is done (e.g. you could market it as "if you want to test the F# waters, just use it as a domain language first!). But this leads me to the second point (and my bigger worry) which is that people simply won't go for it. I've seen (as I'm see we all have) the "my code simply isn't complicated enough to warrant F#" or "I'm productive enough in my standard language already". The existing barriers to adopting F# + Fable (different toolchain, different language, different ML syntax etc.) are still going to be there. Yes, the bindings problem goes away but you end up with another binding problem of DTOs between JS and F#. What I fear we'll end up with is something where it's not clear where and when to use F# and when "not to" (if there even exists such a thing ;-). Don't want to sound overly negative - I'm always somewhat conservative with ideas like this as I think it through - but I think that Fable is a niche market within a nicht market of F#. |
Beta Was this translation helpful? Give feedback.
-
I think that compiling F# to JavaScript is the only use case worth investing in. The others are distractions. Let's remove the dead weight and focus on the one use case that people love and use daily. I'm afraid that Fable (F# to JS) loses its usefulness when interop becomes harder. |
Beta Was this translation helpful? Give feedback.
-
Thanks a lot all of you for your answers! I'm happy to hear that you already had similar thoughts. I was somewhat concerned that Fable could be overreaching, considering the limited resources. And I'm more and more convinced that the focus is necessary to guarantee the project survival and to properly transmit the message. I also understand the concerns about removing support for interop with native libraries/APIs from F#, but this is not going to happen. @alexswan10k has put in better words than me: it's about improving interop with F# from native code. In fact, this is a problem mostly solved in most cases. The only thing we are missing is Typescript support, which prevents integration of F#/Fable in existing Typescript projects, but hopefully we can fix this soon. We're not going to remove current support for all-F# React projects either. In fact, React interop is mostly done with Feliz since a while ago so this can evolve independently of Fable itself. About examples of Domain-specific projects, I can think of some already compiling to Fable.
|
Beta Was this translation helpful? Give feedback.
-
I tend to agree with @isaacabraham that F# for domain logic only - is not a good bet. If speaking about Rust/Python/Node backend integration - this is very possible, as it's quite easy to extract all domain logic in a separate library and binding will not a big issue there. While when talking about UI, it's very hard to imagine for me. UI business logic is tied to the rendering and native controls itself, for example - logic of showing/hiding controls, logic of navigation (including navigation controls), animation logic, validation logic, local data store and reactive updates - all of that are often very tightly coupled with the chosen UI framework and native code and can't be easily moved to "domain library". I would personally consider writing full frontend app in Fable, but not only part of it, since it would be very hard to find the boundary for the F# code and I can't expect any sophisticated business non-UI logic to live there. If keeping bindings for all mainstream frameworks is an unfeasible task, it might be a better idea to focus on Fable-only library like Sutil. This could bring a win-win scenario, on one hand time will only be spent on one library, on the other hand - if most F# frontenders will start using single library - any contribution will be useful for everyone. |
Beta Was this translation helpful? Give feedback.
-
We've been using Fable as a way to write (huge) SPAs in F# end to end. The F# -> JS part works nicely 95% of the time, so you really only occasionally have to care about the actual JS ecosystem under the covers. We also share a lot of code between the font and back-end, which usually just works. This is huge for us and provides tremendouse value. On the other hand I don't see why I'd want to compile F# code to python, go, $language as this approach comes with a lot more problems than targeting a single language. RemObjects offer a platform to share code between Object Pascal, C#, Swift, Java, Go and Visual Basic. To provide a common lowest denominator they provide a shared base library ElementsRTL so code is actually portable. Consuming F# from other languages is not fun either as heavily used language constructs like discriminated unions are not available in the target language. Surely the public interface could hide that fact or provide some helper functions around that limitation, but the experience if far from great. Using F# libraries from C# is an example here. So IMHO F# transpiling only makes sense if the generated code does not have to be consumed by user code again (or just in exceptions). (If I'd really had to share code between F# and langX I'd probably use Native AOT and create exported functions. Erik Sink seems to build nice tooling around this) |
Beta Was this translation helpful? Give feedback.
-
Creating full web apps with F# is one of my favorite things. But I do realize that bindings are problematic, which is why I like Fable.Lit and Fable 4 JSX so much. That is the best of both worlds. I also maintain a large app that uses Fable.React / Feliz and it has been such a joy to build and maintain that I’m just not ready to give up on the idea of using F# on the front end. |
Beta Was this translation helpful? Give feedback.
-
Hey Alfonso, it is nice to hear from you. My first thinking is that Fable is already doing great as it is either half experience (Just the client) or full experience (via SAFE and other custom stacks) and It would be a very hard blow in the fable's reputation to switch the messaging to "It's better used on domain!" IMO as I would believe the perceived message could be (as others have mentioned as well) that Fable is not capable of delivering, which is certainly not true. In the Bindings area, I think a good solution to ease the core team's burden would be to create an organization akin to fsprojects (or even ask to move certain projects there if it is feasible). I know some of the Fable.* bindings work like that but perhaps being clearer when it comes to what is maintained by who and that it is entirely up to the community to keep it growing can ease some of those pains (I've seen you spread too thing between a lot of Fable.* namespaces/projects and this may have contributed to your effort calculations) Having that said I think the web is very good enough these days to warrant a "Fable" framework (Like Sutil as @Lanayx has already mentioned) where the community can focus on it without worrying if it has "bindings" for "X" as keeping up with the other js projects is simply impossible. Rather than focus on I think many of the areas the community may want are already there in one shape or form (Feliz.Engine, Fable.Store, Elmish works everywhere, Fable.Remoting) so perhaps the missing effort (or more likely the already spread thin effort) is about focusing more on Fable's defaults to ease up these maintainer's concerns, everything else can go to a 100% community maintained organization. I've been trying hard to show that Fable can actually be very good without many of the tooling bloated experiences from the JS/Node community with my Perla project and 90% of the time I have to worry about what the web community is expecting the other 10% is knowing that the Fable community already has most of it's needs covered within that area, so I personally biased think that "Fable for just domain" is not a killer use case and can damage fable's own (and its community's) efforts at least within the Web story In regard of the other target languages, I find hard to see how the usage can be communicated as I'm not part of those ecosystems but I don't think their messaging fits the same as the F# -> JS/TS/JSX story, this may also be another point that makes it harder to have a clear goal for fable. Is fable spreading too thin? I think for the most part Fable is still considered mostly a Web related tool so... with my biased point of view I would still focus in that area And sorry if this is somewhat not clear or deviated from your points it has been hard to write as I've taken your news as worrying for the Fable project and it's community in any case I'd just want to be clear that I support whatever decision the Fable's core team and community take |
Beta Was this translation helpful? Give feedback.
-
Another option would be to look at investing more time / energy into the TS to Fable project. But I'm keen to try out the Fable 4 JSX work (we have one customer that's already using it with good results). And it does make sense for the Fable project itself to focus on the language interop side of things than frameworks like React - that makes total sense, especially given that many non-JS experts don't understand React or JS libraries that much - some folks just want to treat that side of the world as "non-F#" code and just call it from F#. The truth is though if you're writing for the JS world, even in F#, you will at some point need to learn about the underlying runtime + toolchain etc.. My main concern is around branding Fable / having people read Fable's use case as "F# is good for DSLs and domain login in JS but don't do anything else" rather than "Fable 4 is now even better at language interop than it's ever been!". |
Beta Was this translation helpful? Give feedback.
-
Hi everyone, Web Software Architect and former CTO Nerd here 👋 who has never really worked with .Net in production 👀. Last week, without knowing anything about this thread, I made a drunk in bar issue post related to TypeScript and Fabel. @alfonsogarciacaro was so kind to point me to this place here. Original post collapsed: Chicken-Egg: F# <-> TypeScript — Missing in the Web Ecosystem (#3359)
In summary, my humble thesis is:
The reason why this is sad, is that F# as a domain modeling tool would be the perfect business logic / state management solution in end-to-end application development. The bug fire pit where verbose 1000 and 1 state management solutions exist. Give me the ease of
...and I will throw out complex state-typescript interface code today, and hire the first F# developers tomorrow. F# appears to me like the missing puzzle piece for a long standing issue. TypeScript brought types, Rust brought binary processing and F# could bring sanity to application domain modeling. I will however never push anyone / myself to write JSX / React Components / DOM / Node Apis in F#. Beside believing that synergies emerge from surfing a platform (and not try to overpower it), talent liquidity and fluidity is just way to important for that. IMO the weird "purist" vanity goals to write everything in Rust, Flutter, C#, Elexir whatever are computer science endeavors but completely disconnected from what product and software engineering is: Swiftly build accessible and healthy teams to solve user needs. |
Beta Was this translation helpful? Give feedback.
-
About ts2fable, I have the project in the coming months to work on a new version of it / replacement. The way to write bindings has greatly changed since ts2fable was first created. 1-2 years ago I would say that ts2fable was doing 80-90% of the job and I only had 10% to rewrite/fix. But today, I think the ratio is more like 50%. It doesn't mean that you can't use ts2fable the same way we did in the past. Just that if you want a better binding syntax ts2fable doesn't provide it today. About the discussion should Fable be promoted as a Domain modelling solution or focus more on binding. I think the answer is both of them are correct, and it will depends on what the community do around Fable. I say both of them are correct because:
The difficulty that Fable face is the same as F#, we have a great language. People using it are convinced that it can be used as a full replacement or in combination with others languages but there is not a lot of ressources or support for it. IHMO if people want to shape F#/Fable future, then they should regroup themself around project that they like or share values with. For examples, I share a lot of values with Fable and that's why I am active around it, same goes with Ionide and for this reason I contribute a lot around UX and tooltips rendering. Fable.Packages is the work of several years of prototypes and discussions, to comes up with the product we have today and the specs. Same goes with Fable interop, which allows to have almost 1-1 match in term of syntax for the most commons binding features. All that to say, that if people think that domain modelling should be more advocate then, they should create an initiative (aka a new website / projects) to create the ressources (blogs, examples, tutorials, demo, etc.) around that. Kind of like The Elmish books is an initiative for Elmish and Feliz/React. |
Beta Was this translation helpful? Give feedback.
-
Fable's advantage in JS land is that JS is not special. At least in my experience, there was rarely a case where I wished I was writing JS instead of F# when using it. While F# covers the weakness and strengths of JS, it does an excellent job covering the weakness of Dart while completely hiding the strengths. But that is an easy fix. Fable doesn't need to be an entry point. As long as Fable generates good and sensible native signatures for the F# functions, we can apply dependencies for those functions as arguments to minimize the need for native bindings. For example, for an Elmish-like implementation, I could only compile the As a lazy person, Fable also solves the pain of creating shared models between the front and back end in two languages that are hard to sync. Having F# as the domain language saves a good deal of time. So I agree with the sentiment that Fable could stop being a complete replacement and turn into a tool for dealing with the target weaknesses while complementing the strengths. It's just that JS doesn't have enough strengths. 😬 |
Beta Was this translation helpful? Give feedback.
-
Thanks again for all your comments! I can see the experiences vary and that there are supporters both for F# for domain and F# for everything approaches. But the good news is: we can have both! As @Nhowka and others above say, the important thing is that Fable compiled code exposes itself well to native code. We're very close to have this for Typescript (half of the tests are already running for TS) which will make it easier to integrate F# in existing TS projects without having to rewrite everything. And hopefully the same will happen with Python, Rust and Dart. About keeping Fable as a good fit for F# only web apps. We can do it as we have done so far. Basically, the main change is I will focus more on the "core" compiler and less on integration with JS frameworks and tools. This is a necessity because I have less time now and I am (almost) not working on frontend apps. But I think it can also be beneficial because it avoids "internal competition" and gives more space to contributors and are more interested in this area and less in compiler internals. There maybe some features that do require internal work, like JSX, but in most cases it can happen independently (see Feliz). Regarding TS > Fable interop, this is a complex issue. I haven't been involved in ts2fable for a while but there have been many great contributions. I hope also that @MangelMaxime project can help here so all-F# apps are still attractive :) |
Beta Was this translation helpful? Give feedback.
-
@D1no Fable 4.1.x has been released with stablish support for TypeScript. More info here: https://fable.io/blog/2023/2023-04-20-Better_Typed_than_Sorry.html |
Beta Was this translation helpful? Give feedback.
-
@alfonsogarciacaro I am pretty happy by the way the Fable is maintained. Fable was one of the reasons, if not the main, for me to use F#. I understand how hard to is maintain Open Source projects with family and work. By the way, I still didn't have time to see depth in the Dart implementation, but It's in my todo list. Also I want to take a look to implement the parser for Zig, that will open F# path for a number of environments. I most interested in webassembly, native code and use inside Elixir with zigler. I will take some time to understand the codebase for this. |
Beta Was this translation helpful? Give feedback.
-
Just to add: We are happy using F#/Fable/Elmish/Electron to implement a biggish desktop app (40K lines F# - very algorithm-dense). We write everything in F#. F#/Elmish allows development from many different students on a complex cross-platform app with nearly all of the pain hidden and after 3 years of dev and adding features it is still nicely maintainable and robust. Web GUI is not great but there is no good cross-platform desktop alternative for something that can be easily picked up by new (student, amateur) developers which is has a large enough feature set. Our app has some pretty complex GUI stuff because we want really good UI. https://github.com/tomcl/ISSIE I'd LIKE a better toolchain (from F#/MVU - no other language/framework would provide the simplicity, maintainability and add-onability we need while being easy to learn). Well Elm might be ok for GUI, but you can't write a fast digital simulator in Elm, and I doubt it would be nice in a large app. https://github.com/tomcl/ISSIE Thanks Alfonso for FABLE! PS - I am open to ideas for a better toolchain (I hate electron) - even for better languages than F#. I just have not yet found them. All programming is a compromise... |
Beta Was this translation helpful? Give feedback.
-
Yes, thanks. I have thought about using that. It will be quite a big change. Is there an equivalent of svg? The UI at the moment is a lot of complex SVG interactive stuff + things around it that could be anything. |
Beta Was this translation helpful? Give feedback.
-
Hello team!
First of all, sorry for not being active in the past two months. I stopped freelancing at the end of last year and between work and family is getting more difficult to find time (and energy) for Open Source. But I hope I can be back when things calm down. Although unfortunately I'm not using Fable at work at the moment, so I'm not going to have so many opportunities to contribute, meaning that I'll need to be more effective which has led me to some reflections I would like to share with you.
After several years working mostly in F#, in my current position I have to maintain multiple existing projects using different technologies: dotnet (mostly C# but also a little of F#), python, javascript, dart/flutter and several query languages: sql, mdx and dax. I'm currently trying to modernize these projects and help standardize practices and architectures.
If I have a task involving a new technology, I try to look for "official" tutorials and the most "standard" way of doing things with that technology. When I find myself in this situation, I realize that it would be impossible for me to try (or even find about) something like Fable.
So far, we've promoting Fable as an (almost) full replacement for JS. However, although on one hand we can say F# and functional programming have won in the sense that most languages are incorporating immutability, fluent syntax and union types/pattern matching, on the other hand this also means it's more difficult for F# to compete as it offers less benefits in relation to the costs (introducing a new language and tooling in already complicated stacks).
It's true that one of the selling points of Fable has been the promise of still being able to use native libraries and tools. In order to accomplish this, we have spent a lot of time creating bindings and adding features for interop, including IDE tooling. But this requires constant effort to keep up-to-date, there is always friction and obviously the experience is never on par with native.
This has made think we could make a virtue of necessity and instead of focusing so much on using F# as a full replacement for the target language and having powerful interop, we could promote F#/Fable as the best way of doing domain programming isolated (up to a point) from the rest of the plumbing code.
For example, we could use F# app for Elmish, but React/TypeScript for the UI in a web app, XAML in WPF, and Dart/Flutter for mobile. In a server, the services could be written in F#, while the controllers (HTTP API) and database contexts in the "native" language of the platform: C#, Rust or Python.
This new approach could maximize our effort and give more sense to the introduction of F# in a project:
What do you think? Would it make sense to promote F#/Fable for domain programming integrated in multi-language projects from now on? @ncave @dbrattli
Beta Was this translation helpful? Give feedback.
All reactions