-
-
Notifications
You must be signed in to change notification settings - Fork 370
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
clean division between "value" and "object" #3
Comments
How would that look API-wise? Would something like |
I'm not sure. I'm trying to decide what I think the default for |
The default should be what most people (and I!) would expect it to do. We’re still on Python and don’t have free COW structures etc. Therefore any immutability gimmickry ought to be opt-in (but in place and simple to use). |
I think you're right; Python programmers are going to expect mutability by default, trying to turn that off would just be an ideological statement, not useful functionality. So how about just having a |
Hi, I found this ticket because I was looking for an ALSO: on the subject of "value types", I would like to point out my new library sumtypes (honestly I didn't come here looking for a place to advertise, but it seems relevant). |
I’m reluctant to implement immutable myself because it adds another method I have to highly invasively muck with ( But |
@hynek I guess there's two separate aspects of immutability: making sure declared attributes are immutable, and making sure new attributes can't be dynamically assigned to. Neither of these actually require defining I assumed Attribute must have already implemented the descriptor protocol, but I see now I'm wrong, and, for example, mutating an attribute post-instantiation will allow setting it to a value that a validator wouldn't accept, because validators are not run on mutation. So maybe it would be best if Attribute instances do provide the descriptor protocol, both to support validating mutation as well as implementing immutability if it's requested? |
I kinda want to recommend setting up a performance test suite at this point, because while it seems to me like using the descriptor protocol ought to be zero-cost on PyPy and "fast enough" on CPython, it also seems like it would be worth knowing that for sure. (Although I also assumed that attrs would validate on mutation and this is a slightly unpleasant surprise. Hmm.) |
attrs had validation on mutation once but there were so many loopholes that I decided to take it out because the performance hit for everyone simply wasn’t worth it. I’m pretty sure that using descriptors is measurably slower. I’ll happily be proven wrong with a benchmark. :) |
What do you mean "so many loopholes"? Other than |
@glyph well, there's also other methods on Personally I think it's worth doing validation with the descriptor protocol even though someone could bypass with But... yeah, that might be a bit too surprising/weird for people who do want to dig down into the representation. I mean, Pickling would still work just fine, but maybe there are some useful things that would break? |
Also, as a follow-up to my previous mention of
There may be some clever trick I'm missing to still use |
Oh, never mind. There is a way to use both slots and descriptors: http://stackoverflow.com/questions/4912499/using-python-descriptors-with-slots It's just a matter of having the user's descriptor be named different from the slot. |
most obvious loophole: I don’t want to sound like an ass but adding features that are invasive but only interesting to a small fraction of people made I’m open to descriptor-based solutions that have no negative impact on performance though. |
Mutability doesn't seem like a particularly obscure or minority concern :). That said, I'm not sure what you're objecting to. Doing validation on attributes by default? Doing validation on attributes at all? Or the actual topic of this bug, |
Echo chamber. :) I’m objecting the tangent of validating on assignment. I don’t object immutability but I feel it should be a separate decorator. Maybe |
OK good. Let's have another issue to discuss that. For the case of |
You mentioned not wanting to do it yourself, but nothing except |
Just to be clear: my main issue is not being lazy but wanting to keep attrs clean. :) Moving settattr magic into a separate decorator seems a fair compromise to me. |
Cool, thank you, I asked the question very awkwardly but that was exactly the form of answer I wanted :). |
See also #50 ? |
Objects, as in object-oriented programming, are side-effecty, mutable state, whose methods ought to represent I/O.
Values, as in functional programming, are immutable data, whose methods ought to represent computation.
Python does not have as good a division between these very different sorts of beasts as it should, but it does have one critical distinction: the
__hash__
method.characteristic
has this issue which crops up occasionally where you end up with objects that you can't put into a dictionary as a key, because one of its attributes is a dictionary. Sometimes people expect to be able to do this becausecharacteristic
makes so many other things easy, and just expect dictionaries to suddenly be immutable; sometimes people expect hash-by-identity.I propose that attr provide a way to specifically create two types of objects with a distinct interface; one that creates a "value" and one that creates an "object", so that users can see issues around mutability far earlier in the process.
So, for example, the "object" type would:
__hash__
by default, provide an__eq__
that does structural equality, and__gt__
/__lt__
that just raise exceptions__hash__
, but then also switch to an identity-based__eq__
and the 'value" type would
hash()
on all of its arguments at construction time so it would fail immediately if it contained a mutable typeThe text was updated successfully, but these errors were encountered: