DEV Community

Discussion on: Mutable Default Arguments in Python

 
rhymes profile image
rhymes • Edited

Citing Guido Van Rossum in the response about the freeze protocol mentioned in the other comment:

Even if you skip past the
question of why you would want to freeze a dictionary (do you really want to
use it as a key?), one find that dicts are not naturally freezable -- dicts
compare using both keys and values; hence, if you want to hash a dict, you
need to hash both the keys and values, which means that the values have to
be hashable, a new and suprising requirement -- also, the values cannot be
mutated or else an equality comparison will fail when search for a frozen
dict that has been used as a key.

and then

One person who experimented with an
implementation dealt with the problem by recursively freezing all the
components (perhaps one of the dict's values is another dict which then
needs to be frozen too).

and then

Executive summary: freezing dicts is a can of worms and not especially useful.

from mail.python.org/pipermail/python-d...

If we take a step back we can understand this ourselves. In Python dict keys need to be immutable but their values don't. So what "freezing a dict" might mean? Not being able to add new key values pairs? Maybe that's achievable by playing with a subclass of collections.UserDict but if any of the values of the dict are objects themselves, you can still change the object and thus you'll end up passing around a "frozen" hash that's not actually constant throughout its life.

Basically, a can of worms :D

Object.freeze({a: 3}) in JS will return a frozen object BUT if the I swap 3 for an object in another variable, I can actually change that value and the result is that your frozen object might not allow you to add new keys or assign to it, but its actually value is still not the same of when you frozen it:

const anotherObj = {d: 4};
undefined
const x2 = Object.freeze({a: anotherObj})
undefined
x2
{}

a: {}
​​
d: 4
​​
<prototype>: Object {  }

<prototype>: Object {  }

anotherObj
Object { d: 4 }

anotherObj.d = 5
5
x2
{}

a: Object { d: 5 }

<prototype>: Object {  }

sorry for the mess but I copy and pasted quickly from the browser's console :D

Same happens with Ruby BTW:

[26] pry(main)> obj = {a: 3}
=> {:a=>3}
[27] pry(main)> frozen = {b: obj}.freeze
=> {:b=>{:a=>3}}
[28] pry(main)> frozen[:c] = 10
FrozenError: can't modify frozen Hash
from (pry):28:in `<main>'
[29] pry(main)> obj[:a] = 10
=> 10
[30] pry(main)> frozen
=> {:b=>{:a=>10}}

so yeah, freeze is a neat idea but not very useful in a language like Python (nor very useful in Ruby beyond making strings immutable and other few cases)