It’s good to experiment with this sort of thing. I think the sort of solution you’re trying for here needs to be a core language feature, and short of that it doesn’t solve the actual problem it’s addressing.
Here’s what I mean: a function that uses this macro forces the calling code to acknowledge that it knows that parameters will be (might be) mutated. To call the function one has to import the macro and use a special syntax. And ok, in a way that’s stronger than clear documentation, you essentially make the programmer sign a consent form for mutation of the collections.
But this isn’t actually solving the problem, because if I expect and want those parameters mutated, it’s just extra steps. Furthermore, since it isn’t a language feature, we can’t force everyone to use it, so it’s still the status quo out there, which is that when you pass a collection to a method, it might mutate it before handing it back.
What would go a lot further is a pair of functions, freeze
and thaw
, with methods specialized for all the mutable collection types in Base. If you call freeze(d::Dict)
, you get back a FrozenDict <: AbstractDict
, which simply doesn’t respond to the methods for mutating the dictionary. Julia handles this kind of wrapping very efficiently, it’s zero extra allocation and the methods on the base object are almost always inlined into the underlying methods. thaw
, of course, just gives me my Dict back.
That lets me insist that a collection is not to be mutated, if something tries, I get an error right away. If I’m chasing down a mutation bug, I can just freeze
the variable and see what’s doing it by the stacktrace.
This comes with some minor inconveniences, admittedly, like methods which only take a Dict
(though this is nearly always lazy/wrong and can be corrected with the correct abstract signature), you can’t freeze a Dict
that’s an immutable struct member (because that is itself mutation), but it would go much further to solving the unwanted-mutation problem than an opt-in method signature macro imho.
As a language feature, I do like the idea you’re exploring here, although it would take some very far-reaching changes to Julia to allow it to reject code which mutates a reference without a signature allowing it to do so. But in terms of what can be done to prevent unwanted mutation, frozen collections gets closer to solving the problem.