Hi my blog readers! Again in this F# Advent 2023, Merry Christmas and happy new year 2023! 😊
Before I discuss the evolving improvements of F#, let's celebrate the release of .NET 8.0 in November this year at dotnetConf 2023! This release has even major version number, means that this is LTS release that is supported for three years since the release.
NOTE about the use of .NET instead of .NET Core:
If some of you may wonder that I'm not saying ,NET Core 8.0, because Microsoft has removed the "Core" since ,NET 5.0. See also my previous blog at https://fsharpmonologue.blogspot.com/2022/12/advent-2022-whats-new-in-f-7-and-some.html and Microsoft's explanation on why this is just .NET. This is the last blog that explains why going forward if I discuss .NET 5.0 and later I just use .NET instead of .NET Core.
NOTE about F# 8: F# 8 comes with .NET 8.0 release. Therefore these improvement in F# 8 requires .NET 8.0.
Now, let's discuss what are those improved features in F# 8!
Evolving improvement on F# 8
In this F# Advent, I won't discuss all of new features in F# 8, as all of them has already discussed in this Microsoft blog: https://devblogs.microsoft.com/dotnet/announcing-dotnet-8/
What really caught my attention is the way the existing feature evolved: the previous features laid the foundations of the improvement. It is a good thing, as sometimes new features or even improvements may break or even if it may not break sometimes it will create a controversy, as we have seen in C# param bangbang annotation, the "param!!" that now ends up rejected, and the notes of C# LDM meeting about this issue that concludes that this feature is rejected.
Let's discuss my own choice of these three feature evolution: F# string interpolation, string literals, numeric literals, and TailCall diagnostic attribute.
F# string interpolation
The F# string interpolation is very useful, and it was introduced in F# 5: Docs on what's new in F# 5
Let's start from a simple usage of this feature, by comparing before and after having string interpolation.
In this example, I print an expression of how many years old Indonesian independence using F# printfn with F# format patterns, before and after F# 5:
As we see, this is very useful and also helpful, in a sense that it simplifies many things, including less use of format patterns. Of course, you can still use the format patterns, like this example from F# docs:
And since F# is strongly typed, this string interpolation combined with format patterns is also strongly typed at compile time. For example, if you mix the format with wrong types you'll get compile error, like this example::
In F# 8, you can use an improvement of having to include the curly braces as part of the string without escaping them, by having extended double dollar signs "$$" instead of just single dollar "$".
This is very convenient when we have a sample to have HTML templating from the blog of F# 8 announcement:
In that sample code, notice that the CSS syntax of curly brace feels more natural in F# 8. This is why I called this evolving feature improvement, instead of introducing new feature that has no or little relation with existing feature!
Here is another sample of F# format patterns combined with string interpolation, this improvement is also amazingly powerful, because the format and the string flow nicely. For example:
String literal improvement
Not just that, the string literal handling is evolved: string literal defined anywhere else can be combined with other string and also format patterns, and also can be used further with printf, sprintf, and other prontf operation. This is also still valid when combined with string interpolation.
For example:
Numeric literals improvement
Numeric literals have been available quite long time, and usually we can only assign a constant value. While we of course can combine these numeric literals with others, in F# 8 the assignment can also contain arithmetic operations. This would be very useful as we could assign calculations of any numeric values as long as the types are correct.
For example (taken from F# code in the announcement of F# 8):
We can now see the evolving of this numeric literals may be minor, but this is very useful indeed. I personally think that this is an added value, and it is similar added value like pervious string literal discussion.
Tailcall diagnostics attribute
We know that we can have recursive functions to be optimized as tailcall functions, especially if the functions meet the conditions to be compiled as recursive functions that has tailcall.
One of the condition is that the function must have accumulator, like the example in F# Tutorial:
Now we could "test" the tailcall. I create the same function with different name and with added TailCall attribute, and then compile it to see if it has warning or not:
There's no warning, and it's a tailcall recursive function. Now if I just use the sample of sum with no tailcall accumulator and mark it, then it give a warning:
Unfortunately, that warning isn't shown in the Visual Studio's Error List pane output:
To see both panes, here it is:
To be honest, this is quite surprising!
Don't worry, I already submit a bug report: https://github.com/dotnet/fsharp/issues/16467