Per advice from Daniel from HN (thank you!), I have reposted this Ask HN I made earlier about immutability. [1]
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 use attrs for this. The objects are not truly immutable in the sense that you can modify then if you are really determined to but typical assignment of a new value to a attrs defined field (where frozen=True) will raise an error.
Speaking as someone who Friday had to fix an embarrassing bug in my Python code because lists aren’t immutable when passed to another function, I like the way you think.
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).
I try to treat real/physical Python objects as disposable. Everything in the runtime can be recreated from something else - be it a file on disk, a table in a DB, redis, a blob on S3, etc… and try not to put too much weight on the actual objects themselves. Modifying an object is really not something I ever do. I/O is dealt with elsewhere. I guess you could call it a hybrid approach of functional programming where objects are just used as structs that might have a few methods for synthetic properties.
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.
Exactly my main issue. I see this code as something that asserts that an object is not modified by that "bad" code, but I fail to see more use-cases. I've been thinking about doing some kind of dictionary datastore with these frozen objects but I'm not sure if it is actually useful.
I wish more languages have the concept of "object/memory freezing" especially at runtime, similar to runtime assertion checks, but without using 3rd party compiler plugins to instrument my code.
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"
Why would you want a runtime check if you can have a compile time check?
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.
# 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'm guessing this would be most useful when interfacing with naughty code that you can't rewrite. E.g. you need to call a function from another library that does something useful and also modifies its argument, and you only want it to do the useful thing.
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.
I like the purity that might come with decorating basically everything in a codebase with `@freeze_params()`, although I wonder/worry about what the runtime overhead might be. I really wish that something like that could be checked statically.
It probably could be checked statically if someone taught the type checker about this package so that it could track which variables are frozen at which points in the code.
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.
I knew about dataclasses when I started writting gelidum, but I wanted to make the immutable objects be from any classes, those under my control or not.
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.
Such a question. Why does the function keep adding the default value "baz" to the existing list every time foo () is called, instead of creating a new list every time?
diegojromero|4 years ago
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.
[1] https://news.ycombinator.com/item?id=27503947
[2] https://pypi.org/project/frozendict/
4ec0755f5522|4 years ago
https://www.attrs.org/en/stable/examples.html#immutability
macintux|4 years ago
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.
whalesalad|4 years ago
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.
nightfly|4 years ago
Seems like it's insurance, which doesn't seem bad
diegojromero|4 years ago
trinovantes|4 years ago
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"
1ris|4 years ago
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.
unknown|4 years ago
[deleted]
emef|4 years ago
rcthompson|4 years ago
diegojromero|4 years ago
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.
nickysielicki|4 years ago
rcthompson|4 years ago
diegojromero|4 years ago
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.
m_mueller|4 years ago
diegojromero|4 years ago
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.
slava_kiose|4 years ago
unknown|4 years ago
[deleted]
unknown|4 years ago
[deleted]