Mutable fields of private records

Hi,

I use `private` records from time to time because they are a nice way to show the inside while protecting the instantiation.

I’ve noticed something that looks weird to me though, you can’t mutate a mutable field of a private record. If you don’t want a field to be mutated, you can just not mark it as `mutable`, so I don’t understand this limitation. Is there any specific reason to that?

This is not a purely theoretical question, I’m also a maintainer of ReScript that was originally a fork of OCaml and I’m considering lifting this limitation.

I’m all ears :slight_smile:

Private type makes it possible to observe the structure of a value of a private type without being able to construct or modify it directly. This is in particular useful to create a lightweight of refinement type for instance, a type for positive vectors

module P: sig
 type t = private {
   mutable x: float;
   mutable y: float;
   mutable z: float
  }
  type index = X | Y | Z
  val make: x:float -> y:float -> z:float -> t
  val (.%()<-): t -> index -> float -> unit
end 

since the make and .%() functions can enforce that all components of the vector are positive (by raising an exception if this is not the case).

This property is broken if you allow mutations of the fields of a private record.

In regular OCaml (I don’t know if this is also the case with ReScript), you cannot have a record where one field is internally mutable but exposed as immutable. So private can be used as a workaround for that, exposing direct access to the fields without the ability to mutate them.

I agree that there could be use cases for records where you want to forbid creation but allow field mutations, and OCaml doesn’t allow you to write that. If you do have use cases for this you could submit a feature request and we’ll try to see if we can find a clean way to express it.

Thanks for your answers.

Indeed, given you can’t have an immutable field in the signature while its implementation is mutable (we kept the limitation in rescript but I’m also wondering if it’s not something we could relax), in the case of the positive vectors, you had to choose between enforcing this use case even when fields are mutable or enforce it by not allowing mutable fields in this case, I guess both have pros and cons.

Mutability of fields needs to be part of the interface/module types in order to guide correct optimization. If mutability could be hidden by a signature then every optimization pass would have to pessimistically assume all fields are possibly mutable.

In the context of multicore OCaml, the external visibility of mutability might also be important for inserting some memory fences to ensure that the right values are being read. But maybe I’m wrong.

Nevertheless, perhaps something like private mutable on fields could be made a thing? The mutability could then still be visible in the interface but not usable from the outside, just like how private works for the whole type.