I was thinking the other day about my days working with Ruby On Rails and how the strings are mutable in Ruby and the freeze method. My mind wandered about that, the several freeze packages that exist (even the frozendict [2] package) that make frozen classes of objects.
I haven't worked professionally with Haskell or Erlang, but some of their functional capabilities are nice and have ejerced a big influence in my work with Ruby on Rails and Python. Specially the ideas of having immutable objects and keeping updates at minimum.
I thought on doing a freeze package that could make frozen objects recursively in Python. The idea is to make easier to share objects between threads without having to worry about updates inside threads.
However, I'm not sure that this package is useful at all. Maybe is because Python is not a well-suited language for this? Maybe is because my lack of knowledge about functional programming? Maybe is because it doesn't make sense to "freeze" objects?
Some ideas I have in the back of my mind for this package are:
- Some kind of basic datastore-server where data is immutable (threaded server?). - Storing all updates some kind of super-object by storing all history as immutable objects.
What are some sources to learn about immutability on programing languages? How could you use a freeze package in Python or other languages? Would it be useful to share information between threads?
Any advice/idea/feeback/criticism or comment on this matter is appreciated.
I will say, however, that what I want from Python isn’t actually “frozen” data structures but cloned ones (or, like some/most FP languages, structures with nested values that are only cloned when necessary).
Vals, not vars.
Well, lists are never immutable in Python; you want to use tuples for that.
For that reason I’m having a tough time seeing the use case for this. I could see it being useful with “bad” code that mutates things it shouldn’t… but can’t really think of a way I’d integrate this in an environment where I control most or all of the code.
Seems like it's insurance, which doesn't seem bad
C++'s insane "const * const" syntax makes it hard to conceptualize when I just want "create object, do bunch of non trivial stuff, freeze object forever"
what is insane about const * const? (although a const unique_ptr<T> is obiously better and propagate_const ist nice) For you usecase if "create object, do bunch of non trivial stuff, freeze object forever" you propably want a IIFE.
Also, my problem with const pointers is that they don't enforce deep immutability and can cause all sorts of compilation errors if I try to pass them to non-const functions (usually to external libraries). Then I'd end up type casting my pointers which defeats the purpose of static type checking.
# on_update="nothing": does nothing when an update is tried
frozen_shared_state = freeze(shared_state, on_update="nothing")
frozen_shared_state.count = 4 # Does nothing, as this update did not exist
yikes. Thoughts on when this feature would ever be useful? Just the thought of working in a codebase with this subtle inconsistency makes me cringe.I added this feature yesterday. Note the default value is "exception". With "nothin" I was thinking in passing some frozen object through a pipeline of unsafe/inherited/bad code, but without polluting the console with warnings or stopping the execution with exceptions.
Performance is bad, I mean, all params are deep-copied because I assume frozen then "inplace" is not intended as they could be objects used by other parts of code.
It looks like mypy can actually understand the hint: https://mypy.readthedocs.io/en/stable/final_attrs.html
It sucks that this would require such a substantial effort throughout a codebase, though. I guess that’s just the inherent cost of typed python.
@dataclass(frozen=True)
this tends to be enough for my usecases. you can still circumvent (and sometimes have to in dataclass post_init) with object.__setattr__.Having said that, I think dataclasses are a better solution for making immutable objects if the class is going to be made from the start.
https://hypirion.com/musings/understanding-persistent-vector...
Thank you for your input!
const auto foo = [&]() {
Foo x;
x.call_some_non_const_method();
x.something_else_non_const();
return x;
}();
I don't know what to say about your problems with external libraries taking non-const parameters. Const correctness is one of the most basic things you learn about when you first learn C++, so whether or not you think it's a good system I can't imagine there are going to be many good external libraries that aren't const correct.I'd also add even if you thought you could enforce this at runtime, in practice it wouldn't really work due to pointer aliasing.
What if some of those structs are from libraries and I can't mark their inner fields as const? Yes, most libraries I've used are well tested so I don't need to worry about them modifying my fields but there's no guarantee that I won't.
> I'd also add even if you thought you could enforce this at runtime
I'm well aware this is a hard problem. It was something I frequently discussed with my lab mate who wrote his thesis on this exact topic. I'm simply saying it would be a nice-to-have construct like assertions.
I’ve only used tuples in Python as a small data structure, will have to experiment with using them as a list substitute, thanks.