let testByref (x: int byref) s =
x <- x + 1
printfn "%s %d" s x
let mutable x = 0
// Not working. **How to make this kind of usage valid?**
"hi" |> testByref &x
// Working
testByref &x "hi"
But that’s not exactly the same issue, right?
Anyway, curious, why it was allowed before? I’d expect at least mention about such changes.
This is exactly the same issue.
There were massive, severe, horribly broken holes in byref
programming in F#. For example, you could do bizarre things like allow byref
s to escape the scopes in which they were defined, which might accidentally work, but in practice would likely just lead to crashing code.
Changes in byref
scoping and allowed use were mentioned in the F# 4.5 blog post, RFC, and soon docs will be updated (there used to not even be a topic on byref
programming and behavior with it.).
The reason I asked about this is because when I am trying to use GitHub project EFCore.FSharp I found the cloned code base is not compiled and some lines are using this pattern. Please check: https://github.com/bricelam/EFCore.FSharp/blob/8f05755efa6b5e90d866ef995cfb9601b7e23991/EFCore.FSharp/Migrations/Design/FSharpSnapshotGenerator.fs#L172
By the way, if some expert can contribute to this project it would be fantastic because EF Core is so great and used in a lot of places but without full support by F# which is so sad for me. And I don`t know how to make this project work for me so far.
As an aside, this kind of code was disallowed in F# 4.1 as well, which dates back to March 2017 for the release. F# 4.0 used to allow this. In F# 4.5, we have far more intricate checks in place that affect other areas, but the end result is the same as if you’d used F# 4.1 or F# 4.5.
.NET Fiddle is still on F# 4.0 it seems.
Building the project, it looks like there are 14 places where there is this incorrect usage of byref
.
Looking a bit closer, I wonder if they’re mistakenly using byref
when they actually mean ref
. The two are fundamentally different concepts. byref
is a pointer. ref
is a storage location for a value that was (a) the primary story for mutability in F# for a long time, and (b) the way you pass things by reference in F#.
On second thought, byref
is probably still the best way to pass something by reference, since it won’t incur the extra allocations and will still mostly have the same semantics.
However, application of a byref
to a generic function that causes its type to be specialized is unsupported as of F# 4.1, and even more unsupported as of F# 4.5.