I'd love to hear about general approach, that's not specific to Hashtbl
The general problem you are trying to solve is to take a mutable data structure and treat it as if it were immutable. The fact that this occurs as you create a new record is a red herring here. (Although I will point out that because you are creating a record in which every field is different, the old_rec with
is superfluous and distracting.)
The general solution to treating a mutable data structure as if it were immutable is copy, then mutate. But this solution is fraught with peril:
It's not clear under exactly what circumstances a shallow copy is good enough or when you might have to write a deep copy.
If the abstraction is mutable, there's no guarantee it even offers a copy operation (or the appropriate copy operation).
Copies can be expensive, especially deep copies.
This considerations are what lead people to avoid mutable state in the first place. I realize that this is hard to do in Caml, because the standard libraries are unusually imperative for a functional language. Nevertheless, I believe the correct "general" strategy in the long run is to replace mutable abstractions with purely functional data structures.
Addendum: Here's a example for hash tables:
let extend key val tbl =
let h = Hashtbl.copy tbl in
let _ = Hashtbl.replace tbl key val in
h
Provided Hashtbl.copy
is deep enough, you can use this as a functional way of extending a hash table. But you'd be better off with red-black trees.