The design suggestion Give advisory messages when using (!) and := and ask users to use .Value instead has been approved in principle. This RFC covers the detailed proposal.
- Suggestion
- Approved in principle
- Implementation
- Discussion
Give advisory messages on the use of !
, :=
, incr
and decr
from the F# standard library, linking people to a guidance page
and suggesting to change to use cell.Value
operations.
When :=
, !
, incr
, decr
are encountered an informational message is emitted, for example:
a.fs(5,32): info FS3370: The use of '!' from the F# library is deprecated. See https://aka.ms/fsharp-refcell-ops. For example, please change '!cell' to 'cell.Value'.
Users encountering these informational warnings can
-
Convert their code to use a
let mutable
, appropriately scoped. For examplelet f () = let cell = ref 3 for i in 0..10 do incr cell printfn "cell = %A" !cell cell := !cell + 5 printfn "cell = %A" !cell decr cell
can become
let f () = let mutable cell = 3 for i in 0..10 do cell <- cell + 1 printfn "cell = %A" cell cell <- cell + 5 printfn "cell = %A" cell cell <- cell - 1
-
Convert their code to use suggested forms
!cell ---> cell.Value cell := expr ---> cell.Value <- expr incr cell ---> cell.Value <- cell.Value + 1 decr cell ---> cell.Value <- cell.Value - 1
-
OR add the following code to their project
let (!) (r: 'T ref) = r.Value let (:=) (r: 'T ref) (v: 'T) = r.Value <- v let incr (r: int ref) = r.Value <- r.Value + 1 let decr (r: int ref) = r.Value <- r.Value - 1
-
OR suppress the informational warning through
--nowarn:3370
Since F# 0.1, F# has had :=
, !
, incr
, decr
operations for mutable heap-allocated reference cells. As of F# 4.0, let mutable x = ...
supports automatic promotion to a reference cell if the x
is captured in a closure. As a result, the explicit use of ref
cells is now far less common for F# programming, so much so that, in retrospect, we would never have given them such high presence in the FSharp.Core library design. Additionally, reference cells are objects (actually records), and using them should use object notation.
Because of this, we can now gently give advisory messages when using these.
let (!) (r: 'T ref) = r.Value
let (:=) (r: 'T ref) (v: 'T) = r.Value <- v
let incr (r: int ref) = r.Value <- r.Value + 1
let decr (r: int ref) = r.Value <- r.Value - 1
and instead ask people to use r.Value
instead
This has two advantages
-
for programmers coming from most other languages,
!
already has a very specific meaning - usually boolean negation. For these people - and arguably others -r.Value
is clearer -
it reduces the number of operators necessary to learn in F# coding
-
in the very, very long-term we could consider giving
!x
the usual meaning as an overloaded operator suitable for using with boolean values.
This is a backwards compatible change. Informational warnings are not errors even if --warnaserror
is on, unless the explicit error number
is selected.
The informational message is sufficient to gradually advise all users that these constructs are considered deprecated.
None