From a4179913d2a9fc11f3f6c8be36f820f776f71e25 Mon Sep 17 00:00:00 2001 From: Mangel Maxime Date: Fri, 27 Feb 2026 10:57:11 +0100 Subject: [PATCH 1/3] docs: Blog anouncing Fable 5 RC --- .../2026-02-27-Fable_5_release_candidate.md | 239 ++++++++++++++++++ package-lock.json | 1 + package.json | 1 + 3 files changed, 241 insertions(+) create mode 100644 docs/blog/2026/2026-02-27-Fable_5_release_candidate.md diff --git a/docs/blog/2026/2026-02-27-Fable_5_release_candidate.md b/docs/blog/2026/2026-02-27-Fable_5_release_candidate.md new file mode 100644 index 0000000..0a7bebf --- /dev/null +++ b/docs/blog/2026/2026-02-27-Fable_5_release_candidate.md @@ -0,0 +1,239 @@ +--- +layout: fable-blog-page +title: Announcing Fable 5 Release Candidate +author: Mangel Maxime +date: 2026-02-27 +author_link: https://twitter.com/MangelMaxime +author_image: https://github.com/MangelMaxime.png +# external_link: +abstract: | + Fable 5 RC is Here: New Targets, Better Tooling, and Nullness Support +--- + +More than 1 year after the first alpha release, we are happy to announce that Fable 5 is now in release candidate stage! + +You can install Fable 5 by running the following command: + +```bash +# This is only necessary if you haven't installed any dotnet tool yet in the directory +dotnet new tool-manifest + +dotnet tool install fable --prerelease +``` + +If you already have Fable installed, you can update it by running: + +```bash +dotnet tool update fable --prerelease +``` + +:::info +When upgrading, make sure to upgrade your dependencies as well. +::: + +## Compatibility with Fable 4 + +Fable 5 is compatible with Fable 4 projects, except that it is now a `net10.0` tool. + +## Project cracking + +We remove support for the old project cracker using Buildalyzer. It is now replaced by invoking MSBuild directly, which should be more robust for the future. + +## `WarnAsError` support + +It has been a long-standing request to support `true` in Fable, and we are happy to announce that it is now supported in Fable 5. + +You can enable it in your project file like this: + +```xml + + true + +``` + +Fable will now treat all warnings from **your** code as errors, but it will still allow warnings from dependencies. + +This behavior should mimic how standard F# compiler works. + +## F# 9 support + +Fable 5 add support for F# 9 features: + +* [Nullable reference types](https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#nullable-reference-types) +* [Discriminated union .Is* properties](https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#discriminated-union-is-properties) +* [Partial active patterns can return bool instead unit option](https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#partial-active-patterns-can-return-bool-instead-of-unit-option) +* [Empty-bodied computation expressions](https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#empty-bodied-computation-expressions) +* [Updates to the standard library (FSharp.Core)](https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#updates-to-the-standard-library-fsharpcore) + +## JavaScript / TypeScript + +JavaScript target is still the most used and stable target, and we kept improving it during the last year. + +### Supports direct nested types when using `jsOptions` + +```fs + let opts = + jsOptions (fun o -> + o.level2.level3.valueA <- 10 + o.level2.level3.valueB <- 20 + o.topValueA <- 20 + ) +``` + +generates + +```js +export const opts = { + level2: { + level3: { + valueA: 10, + valueB: 20, + }, + }, + topValueA: 20, +}; +``` + +### Simplify `Pojo` bindings + +Fable has a number of ways to create [Plain Old JavaScript Objects](https://fable.io/docs/javascript/features.html#plain-old-javascript-objects) (POJOs). + +In Fable 4, people discovered a way of abusing a combination of attributes to write POJO bindins in a F# natural way. + +```fs +open Fable.Core + +[] +[] +type Options + [] + ( + searchTerm: string, + ?isCaseSensitive: bool + ) = + member val searchTerm: string = jsNative with get, set + member val isCaseSensitive: bool option = jsNative with get, set + +let options1 = new Options("foo") + +let options2 = new Options("foo", isCaseSensitive = true) +``` + +Improving on this, Fable 5 introduce a new attribute, `Pojo`, that can be used to write the same code with only one attribute: + +```fs +open Fable.Core + +[] +[] +type Options + ( + searchTerm: string, + ?isCaseSensitive: bool + ) = + member val searchTerm: string = jsNative with get, set + member val isCaseSensitive: bool option = jsNative with get, set + +let options1 = new Options("foo") + +let options2 = new Options("foo", isCaseSensitive = true) +``` + +Both examples generate the same JavaScript code: + +```js +export const options1 = { + searchTerm: "foo", +}; + +export const options2 = { + searchTerm: "foo", + isCaseSensitive: true, +}; +``` + +## Python + +If you have been following the Fable 5 alpha releases, you know the Python target has received a staggering amount of love. + +This is all thanks to Dag and early adopters who have been testing it. + +### Interop has been improved + +Python interop has been improved to support more features of Python, such as decorators, classes, etc. + +#### Decorators + +```fs +open Fable.Core + +[] +type User = + { + Name: string + Age: int + } +``` + +generates + +```python +@dataclasses.dataclass +class User: + name: str + age: int32 +``` + +#### Classes + +```fs +open Fable.Core + +[] +type Config() = + member val Name = "default" with get, set + member val Port = 8080 with get, set +``` + +generates + +```python +class Config: + name: str = "default" + port: int = 8080 +``` + +You can learn more about Python interop in the [Python target documentation](https://fable.io/docs/python/features.html). + +#### Native task + +You can use `task { }` computation to write asynchronous code that compiles to native Python `async def` functions. + +## Rust + +Rust target kept improving as well, and is now using Rust 2024 language edition. + +## Hello Erlang/BEAM ! + +Dag Brattli added a new target for Erlang/BEAM, which is still in early stages. + +He has been testing is using [Fable.Giraffe](https://github.com/dbrattli/Fable.Giraffe) and the first results are promising: + +> ## Benchmarks +> +> Simple `/ping` endpoint returning "pong", 10,000 requests with 100 concurrent +> connections (oha): +> +> | Metric | BEAM | .NET | Python | +> |---|---|---|---| +> | Requests/sec | 124,256 | 70,375 | 4,006 | +> | Avg latency | 0.79 ms | 1.40 ms | 24.9 ms | +> | P99 latency | 2.49 ms | 3.50 ms | 34.2 ms | + +Indeed, it seems like Erlang/BEAM is a great target for Fable, and we are excited to see how it evolves in the future. + +## Conclusion + +Fable 5 would not have been possible without the help of many people who contributed to it in different ways, from testing, to reporting issues, to contributing code. + +Thank you all for your help and support during the last year, and we hope you will continue to help us in the future to make Fable even better! diff --git a/package-lock.json b/package-lock.json index 71a7b81..e3fbe34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,7 @@ "requires": true, "packages": { "": { + "name": "fable-compiler.github.io", "dependencies": { "bulma": "^0.9.4", "dart-code": "github:Dart-Code/Dart-Code", diff --git a/package.json b/package.json index 747b136..3dc6a24 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,5 @@ { + "name": "fable-compiler.github.io", "private": true, "engines": { "node": ">=14.0.0", From dd4e42a132ca9b16c4657f12389474b27ad8beaf Mon Sep 17 00:00:00 2001 From: Mangel Maxime Date: Fri, 27 Feb 2026 21:21:34 +0100 Subject: [PATCH 2/3] docs: reword to say we support .NET 10 and F# 10 --- docs/blog/2026/2026-02-27-Fable_5_release_candidate.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/blog/2026/2026-02-27-Fable_5_release_candidate.md b/docs/blog/2026/2026-02-27-Fable_5_release_candidate.md index 0a7bebf..1ebb263 100644 --- a/docs/blog/2026/2026-02-27-Fable_5_release_candidate.md +++ b/docs/blog/2026/2026-02-27-Fable_5_release_candidate.md @@ -55,9 +55,9 @@ Fable will now treat all warnings from **your** code as errors, but it will stil This behavior should mimic how standard F# compiler works. -## F# 9 support +## .NET 10 and F# 10 support -Fable 5 add support for F# 9 features: +Fable 5 add support for the following F# features: * [Nullable reference types](https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#nullable-reference-types) * [Discriminated union .Is* properties](https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#discriminated-union-is-properties) From 9d1e778e8f57498b4c66f7eaef963b1f7a667f44 Mon Sep 17 00:00:00 2001 From: Mangel Maxime Date: Tue, 3 Mar 2026 16:18:44 +0100 Subject: [PATCH 3/3] docs: improve python section --- .../2026-02-27-Fable_5_release_candidate.md | 64 ++++++++----------- 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/docs/blog/2026/2026-02-27-Fable_5_release_candidate.md b/docs/blog/2026/2026-02-27-Fable_5_release_candidate.md index 1ebb263..ad18bb9 100644 --- a/docs/blog/2026/2026-02-27-Fable_5_release_candidate.md +++ b/docs/blog/2026/2026-02-27-Fable_5_release_candidate.md @@ -158,56 +158,42 @@ If you have been following the Fable 5 alpha releases, you know the Python targe This is all thanks to Dag and early adopters who have been testing it. -### Interop has been improved +* **Python 3.12-3.14 support** (3.10/3.11 are deprecated) +* **fable-library via PyPI** - No more bundled runtime files +* **Modern type parameter syntax** - Better type hinting in generated code +* **`Py.Decorate` attribute** - Add Python decorators from F# +* **`Py.ClassAttributes` attribute** - Fine-grained class generation control +* **Improved Pydantic interop** - First-class support for data validation -Python interop has been improved to support more features of Python, such as decorators, classes, etc. +### Rust Core with PyO3 -#### Decorators +One of the biggest changes is that the core of fable-library is now written in Rust using PyO3. +The motivation is **correctness**, not performance: -```fs -open Fable.Core - -[] -type User = - { - Name: string - Age: int - } -``` +**Why Rust?** -generates - -```python -@dataclasses.dataclass -class User: - name: str - age: int32 -``` +* **Correct .NET semantics** - Sized/signed integers (int8, int16, int32, int64, uint8, etc.) +* **Proper overflow behavior** - Matches .NET exactly +* **Fixed-size arrays** - No more Python list quirks for byte streams +* **Reliable numerics** - Fable 4's pure Python numerics were a constant source of bugs -#### Classes +### fable-library via PyPI -```fs -open Fable.Core +Before Fable v5, the runtime was bundled in the NuGet package and copied to your output directory. -[] -type Config() = - member val Name = "default" with get, set - member val Port = 8080 with get, set -``` +Now it's a simple pip/uv dependency: -generates +```bash +# Install with pip +pip install fable-library -```python -class Config: - name: str = "default" - port: int = 8080 +# Or with uv (recommended) +uv add fable-library ``` -You can learn more about Python interop in the [Python target documentation](https://fable.io/docs/python/features.html). - -#### Native task - -You can use `task { }` computation to write asynchronous code that compiles to native Python `async def` functions. +:::info +You can learn more about Fable.Python in general on our [documentation](https://fable.io/docs/python/build-and-run.html) or this [blog post](https://cardamomcode.dev/fable-python#heading-introduction-to-fablepython) +::: ## Rust