By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,874 Members | 1,028 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,874 IT Pros & Developers. It's quick & easy.

Making immutable instances

P: n/a
Howdy all,

How can a (user-defined) class ensure that its instances are
immutable, like an int or a tuple, without inheriting from those
types?

What caveats should be observed in making immutable instances?

--
\ "Love is the triumph of imagination over intelligence." -- |
`\ Henry L. Mencken |
_o__) |
Ben Finney
Nov 23 '05 #1
Share this Question
Share on Google+
90 Replies


P: n/a
Ben Finney wrote:
How can a (user-defined) class ensure that its instances are
immutable, like an int or a tuple, without inheriting from those
types?

What caveats should be observed in making immutable instances?

In short, you can't. I usually try harder to derive from tuple to achieve this
(defining a few read-only properties to access item through attributes). Using
__slots__ is then required to avoid people adding attributes to the instance.

In fact, I don't know the rationale. I would think it would be a great addition
to be able to say __immutable__ = True or something like that. Or at least, I'd
be grateful if someone explained me why this can't or shouldn't be done.
--
Giovanni Bajo
Nov 23 '05 #2

P: n/a
"Giovanni Bajo" <no***@sorry.com> writes:
Ben Finney wrote:
How can a (user-defined) class ensure that its instances are
immutable, like an int or a tuple, without inheriting from those
types?

What caveats should be observed in making immutable instances?


In short, you can't. I usually try harder to derive from tuple to achieve this
(defining a few read-only properties to access item through attributes). Using
__slots__ is then required to avoid people adding attributes to the instance.


Note that this property of __slots__ is an implementation detail. You
can't rely on it working in the future.

I'm curious as to why you care if people add attributes to your
"immutable" class. Personally, I consider that instances of types
don't let me add attributes to be a wart.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Nov 24 '05 #3

P: n/a
Mike Meyer <mw*@mired.org> writes:
I'm curious as to why you care if people add attributes to your
"immutable" class. Personally, I consider that instances of types
don't let me add attributes to be a wart.


I agree. To me it seems like the OP kind of wants to implement
encapsulation from the back way.

Anyway, as he doesn't mention anything about using this immutability for
any kind of optimisation, I assume it's about "Control".

--
Björn Lindström <bk**@stp.lingfil.uu.se>
Student of computational linguistics, Uppsala University, Sweden
Nov 24 '05 #4

P: n/a
Mike Meyer <mw*@mired.org> wrote:
"Giovanni Bajo" <no***@sorry.com> writes:
In short, you can't. I usually try harder to derive from tuple to
achieve this (defining a few read-only properties to access item
through attributes). Using __slots__ is then required to avoid
people adding attributes to the instance.
Note that this property of __slots__ is an implementation detail.
You can't rely on it working in the future.


That's one thing I meant when I asked about caveats: implementation
warnings. Thanks.

Are there other, more dependable, ways of making immutable objects?
I'm curious as to why you care if people add attributes to your
"immutable" class. Personally, I consider that instances of types
don't let me add attributes to be a wart.


And this is another meaning: style caveats. I genuinely want to
understand these issues.

I refer you to a similar question: do you consider it a wart that you
can't add attributes to instances of Python's built-in types?
foo = ("spam", "eggs")
foo.comment = "I love it." Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'comment'
bar = 1
bar.base = 10

Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'int' object has no attribute 'base'

Is this a wart? Why?

If it's not a wart, why would it be a wart for user-defined types to
have the same behaviour?

--
\ "I spilled spot remover on my dog. Now he's gone." -- Steven |
`\ Wright |
_o__) |
Ben Finney
Nov 24 '05 #5

P: n/a
Ben Finney <bi****************@benfinney.id.au> writes:
Are there other, more dependable, ways of making immutable objects?
Your answer can be found at <URL:
http://www.cs.bgu.ac.il/~omri/Humor/write_in_c.html >
I'm curious as to why you care if people add attributes to your
"immutable" class. Personally, I consider that instances of types
don't let me add attributes to be a wart.

I refer you to a similar question: do you consider it a wart that you
can't add attributes to instances of Python's built-in types?


Didn't I just say that I thought it was a wart?
Is this a wart? Why?
Because it means I have to wrap them to if I want a typefoo with an
extra attribute. I don't have to do that for classes. It makes builtin
types different from user-defined classes in ways other than
performance, which is a bad thing.
If it's not a wart, why would it be a wart for user-defined types to
have the same behaviour?


It's a wart because user-defined classes *don't* have the same
behavior.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Nov 24 '05 #6

P: n/a
Ben Finney <bi****************@benfinney.id.au> wrote:
How can a (user-defined) class ensure that its instances are
immutable, like an int or a tuple, without inheriting from those
types?
You can make a good start by defining __setattr__, __delattr__ (and
__setitem__ and __delitem__ if your class is a container) to raise
exceptions. Of course, these restrictions can be easily worked around
by a sufficiently determined attacker... but if you have to think of the
user of your code as an attacker, you've got worse problems than this
trifling one.

Do not define any of the in-place operator special methods, such as
__iadd__ and friends (or, if you're inheriting from a class that does
define them, override them to raise exceptions).

What caveats should be observed in making immutable instances?


Remember that your redefined __setattr__ IS "in place" even when you're
initializing your istance, so remember to delegate attribute setting to
the superclass (the other special methods mentioned above are less
likely to byte you).

You will probably want to define __hash__ and __eq__ if you're going to
the trouble of making instances immutable.
Alex
Nov 24 '05 #7

P: n/a
Alex Martelli <al***@mail.comcast.net> wrote:
Ben Finney <bi****************@benfinney.id.au> wrote:
How can a (user-defined) class ensure that its instances are
immutable, like an int or a tuple, without inheriting from those
types?
You can make a good start by defining __setattr__, __delattr__ (and
__setitem__ and __delitem__ if your class is a container) to raise
exceptions.
[...]
Do not define any of the in-place operator special methods, such as
__iadd__ and friends (or, if you're inheriting from a class that
does define them, override them to raise exceptions).


That sounds more Pythonic than hacking __slots__. Thanks.
Remember that your redefined __setattr__ IS "in place" even when
you're initializing your istance, so remember to delegate attribute
setting to the superclass (the other special methods mentioned above
are less likely to byte you).
So, for a class that needs to set attributes in __init__ (but after
that, become immutable), how do I get around this? Should I make a
_FooFunctionality class, and then inherit from that to make Foo as the
immutable class that actually gets exported?
You will probably want to define __hash__ and __eq__ if you're going
to the trouble of making instances immutable.


Good tip, thanks.

--
\ "I'm having amnesia and d?j? vu at the same time. I feel like |
`\ I've forgotten this before sometime." -- Steven Wright |
_o__) |
Ben Finney
Nov 24 '05 #8

P: n/a
Alex Martelli <al***@mail.comcast.net> wrote:
Ben Finney <bi****************@benfinney.id.au> wrote:
How can a (user-defined) class ensure that its instances are
immutable, like an int or a tuple, without inheriting from those
types?


[...]
Of course, these restrictions can be easily worked around by a
sufficiently determined attacker... but if you have to think of the
user of your code as an attacker, you've got worse problems than
this trifling one.


I've probably stumbled across something that people often want to do
for ill-considered reasons; I don't really understand the reaction I'm
getting.

Why is "I want to make objects immutable" seen as "I don't trust my
users"? Are Python's existing immutable types also seen the same way?
If not, why the distinction?

For context, I'm intending for the immutability of class instances to
be a properly documented part of the class protocol. Does that sound
more reasonable?

--
\ "In general my children refuse to eat anything that hasn't |
`\ danced on television." -- Erma Bombeck |
_o__) |
Ben Finney
Nov 24 '05 #9

P: n/a
Ben Finney <bi****************@benfinney.id.au> wrote:
...
Remember that your redefined __setattr__ IS "in place" even when
you're initializing your istance, so remember to delegate attribute
setting to the superclass (the other special methods mentioned above
are less likely to byte you).


So, for a class that needs to set attributes in __init__ (but after
that, become immutable), how do I get around this? Should I make a


As I said, you delegate attribute setting to the superclass. E.g:
class Immut(object): .... def __setattr__(*a): raise TypeError, 'immutable'
.... def __init__(self, v=23):
.... super(Immut,self).__setattr__('v', v)
.... x=Immut()
x.v 23 x.v=42 Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in __setattr__
TypeError: immutable

Alex
Nov 24 '05 #10

P: n/a
Ben Finney <bi****************@benfinney.id.au> wrote:
...
Of course, these restrictions can be easily worked around by a
sufficiently determined attacker... but if you have to think of the
user of your code as an attacker, you've got worse problems than
this trifling one.
I've probably stumbled across something that people often want to do
for ill-considered reasons; I don't really understand the reaction I'm
getting.

Why is "I want to make objects immutable" seen as "I don't trust my
users"? Are Python's existing immutable types also seen the same way?
If not, why the distinction?


A type implemented in C offers different possibilities than one
implemented in Python -- no deep conceptual reason, just practical ones.

A substantial fraction of the time, people asking "how do I stop the
users of my code from doing X" proceed by screaming "but they could
still do X if they hopped on their left foot in a moonless midnight
while sprinkling bat's blood!" as a response to any suggestion. So,
when you ask "how do I stop the users of my code from doing X" without
qualification, you're quite likely to get such disclaimers. If you
don't want them, learn to ask about stopping your users from
ACCIDENTALLY doing X, and no reasonable respondant will fail to notice
the qualification.

For context, I'm intending for the immutability of class instances to
be a properly documented part of the class protocol. Does that sound
more reasonable?


There was nothing unreasonable in your original request, either; and I
don't think that making it explicit that you intended to document the
restriction would have changed my answer (although an explicit
acknowlegment that you're looking for restrictions against accidental
misuse rather than against determined attackers surely would).
Alex
Nov 24 '05 #11

P: n/a

Alex Martelli wrote:
A substantial fraction of the time, people asking "how do I stop the
users of my code from doing X" proceed by screaming "but they could
still do X if they hopped on their left foot in a moonless midnight
while sprinkling bat's blood!" as a response to any suggestion. So,
when you ask "how do I stop the users of my code from doing X" without
qualification, you're quite likely to get such disclaimers. If you
don't want them, learn to ask about stopping your users from
ACCIDENTALLY doing X, and no reasonable respondant will fail to notice
the qualification.

Interestingly, that is what I read from the OP, even without the
"ACCIDENTALLY".

Nov 24 '05 #12

P: n/a

"Ben Finney" <bi****************@benfinney.id.au> wrote in message
news:dm**********@rose.polar.local...
Howdy all,

How can a (user-defined) class ensure that its instances are
immutable, like an int or a tuple, without inheriting from those
types?

What caveats should be observed in making immutable instances?
IMHO, this is usually (but not always) a mistake. (If you're programming a
missle guidance system, or it makes your program go faster it's not a
mistake :))
So are PRIVATE, CONST (all types), SEALED, FINAL, etc -- even the best
programmer doesn't foresee what a user will want to do to make best use of
his components, and many a time I've been annoyed (in Java and MS
frameworks) by not being able to access/modify/subclass a member/class that
I know is there because it has to be there (or because I can see it in the
debugger), but it's not accessable because the programmer was overly clever
and had been to OOP school. A fine-grained capability architecture married
to the language and runtime where I can declare my own level cleverness to
override the programmer's would be nice, but I think Python's voluntary
DoThis, _DoThisIfYouReallyHaveTo, and __You'dBetterKnowWhatYou'reDoing__
approach is a better way to go than the undefeatable keyword approach.

m

--
\ "Love is the triumph of imagination over intelligence." -- |
`\ Henry L. Mencken |
_o__) |
Ben Finney

Nov 24 '05 #13

P: n/a
Mike Meyer wrote:
Note that this property of __slots__ is an implementation detail. You
can't rely on it working in the future.
I don't "rely" on it. I just want to catch bugs in my code.
I'm curious as to why you care if people add attributes to your
"immutable" class. Personally, I consider that instances of types
don't let me add attributes to be a wart.


To catch stupid bugs, typos and whatnot. If an instance is immutable, you can't
modify it, period. If you do it, it's a bug. So why not have the bug raises an
exception, rather than go unnoticed?

I don't see your point, either. Why would you want to add attributes to an
object documented to be immutable?
--
Giovanni Bajo
Nov 24 '05 #14

P: n/a
Mike Meyer wrote:
If it's not a wart, why would it be a wart for user-defined types to
have the same behaviour?


It's a wart because user-defined classes *don't* have the same
behavior.


Then *my* solution for this would be to give user-defined classes a way to
behave like builtins, eg. explicitally and fully implement immutability.
Immutability is an important concept in Python programs, and I'm impressed it
does not have explicit support.
--
Giovanni Bajo
Nov 24 '05 #15

P: n/a
Mike wrote:
How can a (user-defined) class ensure that its instances are
immutable, like an int or a tuple, without inheriting from those
types?

What caveats should be observed in making immutable instances?


IMHO, this is usually (but not always) a mistake. (If you're
programming a missle guidance system, or it makes your program go
faster it's not a mistake :))
So are PRIVATE, CONST (all types), SEALED, FINAL, etc -- even the best
programmer doesn't foresee what a user will want to do to make best
use of his components, and many a time I've been annoyed (in Java and
MS frameworks) by not being able to access/modify/subclass a
member/class that I know is there because it has to be there (or
because I can see it in the debugger), but it's not accessable
because the programmer was overly clever and had been to OOP school.


There's a big difference. An immutable object has a totally different semantic,
compared to a mutable object. If you document it to be immutable, and maybe
even provide __eq__ /__hash__, adding attributes from it is surely an user bug.
And surely a bug for which I'd expect an exception to be raised.

Sometimes, I play with some of my objects and I have to go back and check
documentation whether they are immutable or not, to make sure I use the correct
usage pattern. That's fine, this is what docs are for, but couldn't Python give
me some way to enforce this so that, if I or some other dev do the mistake, it
doesn't go unnoticed?
--
Giovanni Bajo
Nov 24 '05 #16

P: n/a
"Giovanni Bajo" <no***@sorry.com> writes:
Mike Meyer wrote:
Note that this property of __slots__ is an implementation detail. You
can't rely on it working in the future. I don't "rely" on it. I just want to catch bugs in my code.


I certainly hope you're not relying on it to catch bugs. You should do
proper testing instead. Not only will that catch pretty much all the
bugs you mention later - thus resolving you of the need to handcuff
clients of your class - it will catch lots of other bugs as well.
I'm curious as to why you care if people add attributes to your
"immutable" class. Personally, I consider that instances of types
don't let me add attributes to be a wart.

To catch stupid bugs, typos and whatnot. If an instance is immutable, you can't
modify it, period. If you do it, it's a bug. So why not have the bug raises an
exception, rather than go unnoticed?


It's only a bug if you didn't mean to do it. If you meant to do it,
you're taking advantage of a powerful feature of Python. If you feel
the need to restrict the use of such features, maybe you should
consider a less powerful language? There are lots of languages around
that prevent accidental creation of attributes - and lots of other
similar usages that are bugs if you don't mean to do them.
I don't see your point, either. Why would you want to add attributes to an
object documented to be immutable?
The documentation is immaterial. The *need* is what's important. I've
had use cases were some object was almost exactly what I wanted,
except I needed another bit of data dragged along. Python lets me do
that for most classes, which is one of the things that I like about it
- it doesn't handcuff me.
If it's not a wart, why would it be a wart for user-defined types to
have the same behaviour?


It's a wart because user-defined classes *don't* have the same
behavior.

Then *my* solution for this would be to give user-defined classes a way to
behave like builtins, eg. explicitally and fully implement immutability.


Well, if you want to propose a change to the language, you need a good
use case to demonstrate the benefits of such a change. Do you have
such a use case? Catching bugs doesn't qualify, otherwise Python would
be radically different from what it is.
Immutability is an important concept in Python programs, and I'm impressed it
does not have explicit support.


I'm not convinced that immutability is that important a concept. Yeah,
you have to know about it, but it seems more like an implementation
detail than a crucial concept. I'm not sure it's more important than
things like interned strings and the sharing of small integers. Most
of the discussion of immutables here seems to be caused by newcomers
wanting to copy an idiom from another language which doesn't have
immutable variables. Their real problem is usually with binding, not
immutability.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Nov 24 '05 #17

P: n/a
bo****@gmail.com <bo****@gmail.com> wrote:
...
qualification, you're quite likely to get such disclaimers. If you
don't want them, learn to ask about stopping your users from
ACCIDENTALLY doing X, and no reasonable respondant will fail to notice
the qualification.

Interestingly, that is what I read from the OP, even without the
"ACCIDENTALLY".


While I followed the maxim "in the face of ambiguity, refuse the
temptation to guess" and didn't put words in his mouth that he had in
fact not said: I explained what he could do, and how that wouldn't work
IF he did NOT mean ``accidentally''. Not sure if this refusal to assume
that the requests are _necessarily_ sensible comes from my several years
of experience fielding question in this and other newsgroups, or my even
more years of experience as a consultant, both freelance and "in-house"
within large organizations...
Alex
Nov 24 '05 #18

P: n/a

Alex Martelli wrote:
bo****@gmail.com <bo****@gmail.com> wrote:
...
qualification, you're quite likely to get such disclaimers. If you
don't want them, learn to ask about stopping your users from
ACCIDENTALLY doing X, and no reasonable respondant will fail to notice
the qualification.

Interestingly, that is what I read from the OP, even without the
"ACCIDENTALLY".


While I followed the maxim "in the face of ambiguity, refuse the
temptation to guess" and didn't put words in his mouth that he had in
fact not said: I explained what he could do, and how that wouldn't work
IF he did NOT mean ``accidentally''. Not sure if this refusal to assume
that the requests are _necessarily_ sensible comes from my several years
of experience fielding question in this and other newsgroups, or my even
more years of experience as a consultant, both freelance and "in-house"
within large organizations...

I fully understand that, in the "formal" life. But I usually lax that
on occasions like here.

Nov 24 '05 #19

P: n/a

Mike Meyer wrote:
"Giovanni Bajo" <no***@sorry.com> writes:
Mike Meyer wrote:
Note that this property of __slots__ is an implementation detail. You
can't rely on it working in the future.

I don't "rely" on it. I just want to catch bugs in my code.


I certainly hope you're not relying on it to catch bugs. You should do
proper testing instead. Not only will that catch pretty much all the
bugs you mention later - thus resolving you of the need to handcuff
clients of your class - it will catch lots of other bugs as well.

That is an ideal case and we all know the real world is not ideal or
every program would be bug free. And I don't think anyone would solely
relies on the language feature for spotting bugs. Whether this kind of
guard is useful is another story.

Nov 24 '05 #20

P: n/a
Op 2005-11-24, Mike schreef <vi********@yahoo.com>:

"Ben Finney" <bi****************@benfinney.id.au> wrote in message
news:dm**********@rose.polar.local...
Howdy all,

How can a (user-defined) class ensure that its instances are
immutable, like an int or a tuple, without inheriting from those
types?

What caveats should be observed in making immutable instances?
IMHO, this is usually (but not always) a mistake. (If you're programming a
missle guidance system, or it makes your program go faster it's not a
mistake :))
So are PRIVATE, CONST (all types), SEALED, FINAL, etc -- even the best
programmer doesn't foresee what a user will want to do to make best use of
his components,


But maybe what the user wants no longer guarantees correct working.
and many a time. I've been annoyed (in Java and MS christelijke vorm er van.
frameworks) by not being able to access/modify/subclass a member/class that
I know is there because it has to be there (or because I can see it in the
debugger),
Maybe that it is there is just an implementation detail.
but it's not accessable because the programmer was overly clever
and had been to OOP school.
I think hiding something that is essentially an implementation detail
is good abstraction and programming practice.
A fine-grained capability architecture married
to the language and runtime where I can declare my own level cleverness to
override the programmer's would be nice, but I think Python's voluntary
DoThis, _DoThisIfYouReallyHaveTo, and __You'dBetterKnowWhatYou'reDoing__
approach is a better way to go than the undefeatable keyword approach.


I disagree.

Suppose I have the following code.

from module import __take_care__

__private_detail__ = ...

I now have two variable that are flaged the same way, but they are not.

__take_care__ is a private variable from an other module which I should
use with extreme care not to break the other package.

__private_detail__ on the other hand is just keeping private data for
my own module, which I should care about as just any other variable
in my module. It are other modules that should take special care
if they should choose to import this variable.

That is why I don't think the underscore prefixes are very usefull.
They constantly flag to take care with a specific variable, while
that variable is nothing special within the module itself.

--
Antoon Pardon
Nov 24 '05 #21

P: n/a
Ben Finney wrote:
Alex Martelli <al***@mail.comcast.net> wrote:
Ben Finney <bi****************@benfinney.id.au> wrote:
How can a (user-defined) class ensure that its instances are
immutable, like an int or a tuple, without inheriting from those
types?


You can make a good start by defining __setattr__, __delattr__ (and
__setitem__ and __delitem__ if your class is a container) to raise
exceptions.
Remember that your redefined __setattr__ IS "in place" even when
you're initializing your istance, so remember to delegate attribute
setting to the superclass (the other special methods mentioned above
are less likely to byte you).


So, for a class that needs to set attributes in __init__ (but after
that, become immutable), how do I get around this? Should I make a
_FooFunctionality class, and then inherit from that to make Foo as the
immutable class that actually gets exported?


Typically, constants are set up in __new__ (which happens before
__init__), because by __init__ time the object is built. Remember
not to complain that you have no copy operation, because there is no
such thing as a copy of a constant (the original constant is good
enough).

--Scott David Daniels
sc***********@acm.org
Nov 24 '05 #22

P: n/a
Alex Martelli <al***@mail.comcast.net> wrote:
Ben Finney <bi****************@benfinney.id.au> wrote:
Why is "I want to make objects immutable" seen as "I don't trust
my users"? Are Python's existing immutable types also seen the
same way? If not, why the distinction?
A type implemented in C offers different possibilities than one
implemented in Python -- no deep conceptual reason, just practical
ones.


So, in the hypothetical situation that all Python types were
implemented in pure Python, what would the ideal behaviour for
immutables be? Or would there be no immutables?
I don't think that making it explicit that you intended to document
the restriction would have changed my answer (although an explicit
acknowlegment that you're looking for restrictions against
accidental misuse rather than against determined attackers surely
would).


I'm looking for a "consenting adults" restriction: classes will have
immutable instances only where it makes sense from the class protocol.
I'm not going to lose sleep over users who go looking for trouble.

--
\ "Think for yourselves and let others enjoy the privilege to do |
`\ so too." -- Voltaire, _Essay On Tolerance_ |
_o__) |
Ben Finney
Nov 24 '05 #23

P: n/a
Antoon Pardon wrote:
Op 2005-11-24, Mike schreef <vi********@yahoo.com>:
and many a time. I've been annoyed (in Java and MS christelijke vorm er van.
frameworks)


Antoon, I don't think Mike wrote it like that :)

I don't even know how I spotted that, since I didn't really read that
part of the text. I guess the Dutch words caught my attention somehow.
It even took a while for me to realize that it must have been an error;
the first few seconds I was trying to find the relationship between
christianity and Java, MS or frameworks. Without success, obviously.

--
If I have been able to see further, it was only because I stood
on the shoulders of giants. -- Isaac Newton

Roel Schroeven
Nov 24 '05 #24

P: n/a
Op 2005-11-24, Roel Schroeven schreef <rs****************@fastmail.fm>:
Antoon Pardon wrote:
Op 2005-11-24, Mike schreef <vi********@yahoo.com>:
and many a time. I've been annoyed (in Java and MS christelijke vorm er van.
frameworks)


Antoon, I don't think Mike wrote it like that :)


You are right, I don't know what happened, but a piece of text from
an other article was pasted in somehow.

My apologies to everyone and especially Mike.

--
Antoon Pardon
Nov 24 '05 #25

P: n/a

"Giovanni Bajo" <no***@sorry.com> wrote in message
news:bq*****************@twister2.libero.it...
Mike wrote:
How can a (user-defined) class ensure that its instances are
immutable, like an int or a tuple, without inheriting from those
types?

What caveats should be observed in making immutable instances?
IMHO, this is usually (but not always) a mistake. (If you're
programming a missle guidance system, or it makes your program go
faster it's not a mistake :))
So are PRIVATE, CONST (all types), SEALED, FINAL, etc -- even the best
programmer doesn't foresee what a user will want to do to make best
use of his components, and many a time I've been annoyed (in Java and
MS frameworks) by not being able to access/modify/subclass a
member/class that I know is there because it has to be there (or
because I can see it in the debugger), but it's not accessable
because the programmer was overly clever and had been to OOP school.

There's a big difference. An immutable object has a totally different
semantic,
compared to a mutable object. If you document it to be immutable, and
maybe
even provide __eq__ /__hash__, adding attributes from it is surely an user
bug.
And surely a bug for which I'd expect an exception to be raised.
Why is it "surely" a bug? It is arguable whether adding new attributes (vs.
changing those that are already there) is, in fact, mutation.
How will adding user attibutes that your code knows nothing about break the
contracts you have specified?
If __hash__/__eq__ does not look at the new attributes, all the better - as
these attributes are just "along for the ride". (But if the hash reflected
into all attrs, things would indeed break.)
Personally, adding attributes to existing objects would not be my preferred
programming style, epsecailly in a langauge like Python with rich and
easy-to-use associative data structures, but sometimes it's the quickest or
only way to get something done -- if you are unwilling (or more likely,
unable) to modify all the levels of method signatures required to pass new
information about an object/state along.
I can see how a compile-time *warning* would be of value to show it is not
the *desired* usage pattern in the eyes of the component programmer, but
beyond that, why get in the way? Python is not Java or any other language --
sometimes I don't like the total dynamicity either (I'd like optional types
and/or type-inference), but it is what it is.
Sometimes, I play with some of my objects and I have to go back and check
documentation whether they are immutable or not, to make sure I use the
correct
usage pattern. That's fine, this is what docs are for, but couldn't Python
give
me some way to enforce this so that, if I or some other dev do the
mistake, it
doesn't go unnoticed?
It sounds like what you may want are opaque objects where you can control
access better -- if that's so, keep them all hidden, and just pass back a
handle or proxy - you could always implement restrictred/readonly or
copy-on-write semantics. (If there isn't one already, auto-proxy generation
for this sort of thing sounds like a fun python cookbook recipe...)
--
Giovanni Bajo



Nov 24 '05 #26

P: n/a
"bo****@gmail.com" <bo****@gmail.com> writes:
Mike Meyer wrote:
"Giovanni Bajo" <no***@sorry.com> writes:
> Mike Meyer wrote:
>> Note that this property of __slots__ is an implementation detail. You
>> can't rely on it working in the future.
> I don't "rely" on it. I just want to catch bugs in my code.

I certainly hope you're not relying on it to catch bugs. You should do
proper testing instead. Not only will that catch pretty much all the
bugs you mention later - thus resolving you of the need to handcuff
clients of your class - it will catch lots of other bugs as well.

That is an ideal case and we all know the real world is not ideal or
every program would be bug free. And I don't think anyone would solely
relies on the language feature for spotting bugs. Whether this kind of
guard is useful is another story.


Python generally regards languages features that either require extra
typing or reduce the flexibility of the language for the purpose of
catching bugs as "not useful." Some people disagree with this, but
it's the way Python is.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Nov 24 '05 #27

P: n/a

"Antoon Pardon" <ap*****@forel.vub.ac.be> wrote in message
news:sl********************@rcpc42.vub.ac.be...
Op 2005-11-24, Mike schreef <vi********@yahoo.com>:
[...snip...]
...but I think Python's voluntary
DoThis, _DoThisIfYouReallyHaveTo, and __You'dBetterKnowWhatYou'reDoing__
approach is a better way to go than the undefeatable keyword approach.


I disagree.

Suppose I have the following code.

from module import __take_care__

__private_detail__ = ...

I now have two variable that are flaged the same way, but they are not.

__take_care__ is a private variable from an other module which I should
use with extreme care not to break the other package.

__private_detail__ on the other hand is just keeping private data for
my own module, which I should care about as just any other variable
in my module. It are other modules that should take special care
if they should choose to import this variable.


If you just import the module and use __private_detail__ vs.
module.__take_care__ -- that solves that problem :)

That is why I don't think the underscore prefixes are very usefull.
They constantly flag to take care with a specific variable, while
that variable is nothing special within the module itself.
I didn't say that the methods used were perfect or fully expressive, but
just in the right direction.
Maybe there should be a few more variations, and they should be documented
and blessed, and *tools* can honor them as they see fit. (Different syntax
hilighting, lint checking, etc.)

m

--
Antoon Pardon

Nov 24 '05 #28

P: n/a
Ben Finney <bi****************@benfinney.id.au> writes:
I'm looking for a "consenting adults" restriction: classes will have
immutable instances only where it makes sense from the class protocol.
I'm not going to lose sleep over users who go looking for trouble.


I think you're defining immutable differently than I do. Python
already supports attributes that clients can't rebind. You can make an
instance in which all attributes have that property. However
attributes added by a client aren't really yours. They don't change
the immutability of your attributes, or affect the behavior of your
class in any way. Such attributes don't really belong to your class;
they belong to the client.

Even in full B&D languages, it's trivial to overcome this restriction
with a subclass:
i = int()
i 0 i.foo = 1 Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'int' object has no attribute 'foo' class Aint(int): pass .... m = Aint()
m 0 m.foo = 1
m.foo 1


The extra class is the kind of boilerplate that Python in general has
so little of, and B&D languages so much of. In Python, I can even fix
it so *your* code uses my wrapped version:

import Finney
class Addable(Finnney.Immutable): pass
Finney.Immutable = Addable

Which means that from now on *your* code that tries to create
Immutables will actually get Addables. The inability to do this in B&D
languages is - well, painfull. That Python doesns't require the
boilerplate in a good thing.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Nov 24 '05 #29

P: n/a

<bo****@gmail.com> wrote in message
news:11**********************@f14g2000cwb.googlegr oups.com...

Mike Meyer wrote:
"Giovanni Bajo" <no***@sorry.com> writes:
> Mike Meyer wrote:
>> Note that this property of __slots__ is an implementation detail. You
>> can't rely on it working in the future.
> I don't "rely" on it. I just want to catch bugs in my code.


I certainly hope you're not relying on it to catch bugs. You should do
proper testing instead. Not only will that catch pretty much all the
bugs you mention later - thus resolving you of the need to handcuff
clients of your class - it will catch lots of other bugs as well.

That is an ideal case and we all know the real world is not ideal or
every program would be bug free. And I don't think anyone would solely
relies on the language feature for spotting bugs. Whether this kind of
guard is useful is another story.


This is a case where the *language* should be expressive as possible, and
the *tools* surrounding it should be of more help.
Have I ever mistyped a python variable and introduced a bug? -- many times,
and it's really annoying. It's a fault that there's no tool that realizes
that "positon" looks a hell of a lot like "position", more than it's the
compiler's fault to make such an assumption, because the compiler can't
"close the loop" with the user, but the tool can. (Or my fault for not using
such a tool - I know there's pylint, etc.)
Nov 24 '05 #30

P: n/a
Ben Finney <bi****************@benfinney.id.au> wrote:
...
A type implemented in C offers different possibilities than one
implemented in Python -- no deep conceptual reason, just practical
ones.
So, in the hypothetical situation that all Python types were
implemented in pure Python, what would the ideal behaviour for
immutables be? Or would there be no immutables?


Pypy is implementing Python in Python and using just the same semantics
as CPython. Of course, there IS some sleight of hand, because there are
still two "sides" -- interpreter level and application level... stuff
implemented in interpreter level Python plays just the same role as
stuff implemented in C does in CPython.

Musing theoretically, I can see an *ideal* approach would have to meet
higher aesthetic goals than Python's -- reach for richer symmetry, e.g.,
all types existing in mutable and immutable flavors (Ruby comes sort of
close, with plain and frozen objects). Python's more about pragmaticity
than purity (and, therefore, than idealness)...

I'm looking for a "consenting adults" restriction: classes will have
immutable instances only where it makes sense from the class protocol.
I'm not going to lose sleep over users who go looking for trouble.


Yep, I understand this, now that you've explained in more detail, and
FWIW I do approve.

One more piece of advice: you might document that, in circumstances
where (using a normal Python class's instances) the obvious approach
would be to add some per-instance attribute to the instances (with
semantics totally outside the class), your users might be better advised
to employ a weakref.WeakKeyDictionary with the instances as keys.
Although a tad more cumbersome, they can get the same semantics this
way, even though it may seem "inside-out" wrt the "intuitive" approach.
Alex
Nov 24 '05 #31

P: n/a
Mike Meyer wrote:
Note that this property of __slots__ is an implementation detail.
You
can't rely on it working in the future. I don't "rely" on it. I just want to catch bugs in my code.


I certainly hope you're not relying on it to catch bugs. You should do
proper testing instead. Not only will that catch pretty much all the
bugs you mention later - thus resolving you of the need to handcuff
clients of your class - it will catch lots of other bugs as well.


This sounds a little academic. Writing a real Python program without testing is
impossible or close to it, so you are really not telling me anything new. Even
*with* testing, there are bugs. I'm sure you well know this.

My feeling is that you're trying to get too much out of my words. I'm not
trying to handcuff anyone. You seem to concentrate on me trying to avoid people
adding attributes to my precious objects. It's not that. If I write a class and
want it to be immutable, it is because it has to be so. If I write a queue
class and I say that people shouldn't call pop() if it's empty, I mean it. If I
enforce it with a RuntimeError, I'm not thinking I'm handcuffing someone. I
don't see a ImmutableError to be so different from it.

I often design objects that I want to be immutable. I might keep it as a key in
dictionaries, or I might have external, non-intrusive caches of some kind
relying on the fact that the instance does not change. Of course, it *might* be
that testing uncovers the problem. Unittests tend to be pretty specific, so in
my experience they happen to miss *new* bugs created or uncovered by the
integration of components. Or if they hit it, you still have to go through
debug sessions. An ImmutableError would spot the error early.

In my view, enforcing immutability is no different from other forms of
self-checks. Do you reckon all kind of asserts are useless then? Surely they
don't help for anything that a good unittest couldn't uncover. But they help
catching bugs such as breakage of invariants immediately as they happen.
Immutability can be such an invariant.

If it's not a wart, why would it be a wart for user-defined types
to
have the same behaviour?

It's a wart because user-defined classes *don't* have the same
behavior.

Then *my* solution for this would be to give user-defined classes a
way to behave like builtins, eg. explicitally and fully implement
immutability.


Well, if you want to propose a change to the language, you need a good
use case to demonstrate the benefits of such a change. Do you have
such a use case? Catching bugs doesn't qualify, otherwise Python would
be radically different from what it is.

One good reason, in my opinion, is that there *are* immutable objects in
Python, among builtins. And people can easily build extension objects which are
immutable. So being impossible to write a regular object in Python which is
immutable is not orthogonal to me.

Now let me ask you a question. What is a good use case for "assert" that
justifies its introduction in the language? What is a good usecase for module
'unittest' which justifies its introduction in the standard library? Why do you
think tuples are immutable and *enforced* to be so?

Immutability is an important concept in Python programs, and I'm
impressed it does not have explicit support.


I'm not convinced that immutability is that important a concept. Yeah,
you have to know about it, but it seems more like an implementation
detail than a crucial concept.


Probably it's just a matter of design styles.
I'm not sure it's more important than
things like interned strings and the sharing of small integers. Most
of the discussion of immutables here seems to be caused by newcomers
wanting to copy an idiom from another language which doesn't have
immutable variables. Their real problem is usually with binding, not
immutability.


I'm not such a newcomer, but (how funny) Python is *the* language that
introduced me to the concept of immutable objects and their importance in
design :)
--
Giovanni Bajo
Nov 24 '05 #32

P: n/a
"Giovanni Bajo" <no***@sorry.com> writes:
My feeling is that you're trying to get too much out of my words. I'm
not trying to handcuff anyone. You seem to concentrate on me trying to
avoid people adding attributes to my precious objects. It's not
that. If I write a class and want it to be immutable, it is because it
has to be so. If I write a queue class and I say that people shouldn't
call pop() if it's empty, I mean it. If I enforce it with a
RuntimeError, I'm not thinking I'm handcuffing someone. I don't see a
ImmutableError to be so different from it.


But why would you call it that, when the object isn't actually
implemented as immutable?

It's pretty misleading to call an object immutable rather than saying
that it shouldn't be changed for some reason.

Throw an exception that describes why it doesn't make sense to change
that particular object instead.

As I said before, I think you're confusing the (in Python pretty
non-existent) concept of encapsulation with Python's immutable types,
which are immutable because the implementation demands it. (A fact I
hope will disappear at some point.)

--
Björn Lindström <bk**@stp.lingfil.uu.se>
Student of computational linguistics, Uppsala University, Sweden
Nov 24 '05 #33

P: n/a
bk**@stp.lingfil.uu.se (Bjrn Lindstrm) writes:
As I said before, I think you're confusing the (in Python pretty
non-existent) concept of encapsulation with Python's immutable types,
which are immutable because the implementation demands it. (A fact I
hope will disappear at some point.)


What implementation demand? If Python's designers wanted mutable
strings or tuples, Python could have them. Python strings and tuples
are immutable by design, not by accident of implementation. Wanting
to make immutable class instances out of the same design
considerations is perfectly reasonable.
Nov 24 '05 #34

P: n/a
Bjrn Lindstrm wrote:
My feeling is that you're trying to get too much out of my words. I'm
not trying to handcuff anyone. You seem to concentrate on me trying
to avoid people adding attributes to my precious objects. It's not
that. If I write a class and want it to be immutable, it is because
it has to be so. If I write a queue class and I say that people
shouldn't call pop() if it's empty, I mean it. If I enforce it with a
RuntimeError, I'm not thinking I'm handcuffing someone. I don't see a
ImmutableError to be so different from it.
But why would you call it that, when the object isn't actually
implemented as immutable?


I think you misunderstood my message. I'm saying that an ImmutableError
wouldn't be a much different form of self-checking compared to the usual
TypeError/ValueError/RuntimeError you get when you pass wrong values/types to
methods/functions, or you violate invariants of objects. This has nothing to do
with dynamism, duck typing, dynamic binding and whatnot. Some objects have deep
invariants which can't be broken.

Why do you think we have a frozenset, for instance? By Mike's argument, we
shouldn't have it. And we should be able to use a regular mutable set as
dictionary key. Unittests will catch errors. Instead, we got two classes
instead of one, immutability is *enforced*, and sets can't be used as
dictionary keys. This is all good in my opinion, and follows the good rule of
"catch errors early".
Throw an exception that describes why it doesn't make sense to change
that particular object instead.
*How* can I do? There is no language construct which lets me specifies an
exception to throw whenever someone modifies my object. *Even* if I got partial
support for immutable types (like __new__ which can be used to initialize
immutable objects).
As I said before, I think you're confusing the (in Python pretty
non-existent) concept of encapsulation with Python's immutable types,
which are immutable because the implementation demands it. (A fact I
hope will disappear at some point.)


You seriously believe that strings, integers and tuples are immutable because
of implementation details? I believe they are part of a language design -- and
a good part of it.
--
Giovanni Bajo
Nov 25 '05 #35

P: n/a
Mike wrote:
There's a big difference. An immutable object has a totally different
semantic,
compared to a mutable object. If you document it to be immutable, and
maybe
even provide __eq__ /__hash__, adding attributes from it is surely
an user bug.
And surely a bug for which I'd expect an exception to be raised.
Why is it "surely" a bug? It is arguable whether adding new
attributes (vs. changing those that are already there) is, in fact,
mutation.


If we agree that *changing* attributes is a bug for those classes, we're
already a step beyond in this discussion :)

About adding attributes, I agree that it's kind of a grey area. Per-se, there
is nothing wrong. My experience is that they give the user a false expectation
that the object can be modified. It ends up with an object with attributes
which can't be modified because that'd break invariants, and others which are
freely modificable.

In fact, the only thing that you are adding an attribute to *that* instance,
and not to all the *equivalent* instances (by definition of __hash__/__eq__) is
questionable and bug-prone. You might end up *thinking* you have that very
instance around, while you don't. In fact, with immutable objects, you are not
supposed to think in terms of instances, but rather of values. When I see a
string like "foobar" I don't care if it's the same instance of a "foobar" I saw
before. If I could add an attribute to "foobar", I might end up believing that
whenever I see a "foobar" around, it will have that attribute.

As you said, Python has rich data structures which lets you still find good
ways to carry around additional information. So why trying so hard to get into
trouble?
It sounds like what you may want are opaque objects where you can
control access better


No that's a different issue. One example of my immutable classes is Point2D
(two attributes: x/y). Having it immutable gives it many useful properties,
such as a real value semantic.
--
Giovanni Bajo
Nov 25 '05 #36

P: n/a
"Giovanni Bajo" <no***@sorry.com> writes:
Mike Meyer wrote:
Note that this property of __slots__ is an implementation detail.
You
can't rely on it working in the future.
I don't "rely" on it. I just want to catch bugs in my code. I certainly hope you're not relying on it to catch bugs. You should do
proper testing instead. Not only will that catch pretty much all the
bugs you mention later - thus resolving you of the need to handcuff
clients of your class - it will catch lots of other bugs as well.

My feeling is that you're trying to get too much out of my words. I'm not
trying to handcuff anyone. You seem to concentrate on me trying to avoid people
adding attributes to my precious objects.


Because *that's* the use case that you're preventing that I have
problems with.
It's not that. If I write a class and want it to be immutable, it is
because it has to be so. If I write a queue class and I say that
people shouldn't call pop() if it's empty, I mean it. If I enforce
it with a RuntimeError, I'm not thinking I'm handcuffing someone. I
don't see a ImmutableError to be so different from it.
And I have no problems with that. If you believe your class should
throw an error if someone calls an instances pop() method when it's
empty, do so.

Likewise, if you want to make it so a client can't change your
attributes, feel free to do so.

However, when you prevent a client from adding an attribute, you're
not merely making your objects immutable, you're making them
static. Python isn't a static language, it's a dynamic language. I
consider parts of it that are static to be warts.
In my view, enforcing immutability is no different from other forms of
self-checks. Do you reckon all kind of asserts are useless then? Surely they
don't help for anything that a good unittest couldn't uncover. But they help
catching bugs such as breakage of invariants immediately as they happen.
Immutability can be such an invariant.
Adding an attribute can't break an invariant. The only way an
attribute can affect an invariant is if the invariant references
it. If it references it it, then it must exist - so I can't add it.
> If it's not a wart, why would it be a wart for user-defined types
> to
> have the same behaviour?

It's a wart because user-defined classes *don't* have the same
behavior.
Then *my* solution for this would be to give user-defined classes a
way to behave like builtins, eg. explicitally and fully implement
immutability.


Well, if you want to propose a change to the language, you need a good
use case to demonstrate the benefits of such a change. Do you have
such a use case? Catching bugs doesn't qualify, otherwise Python would
be radically different from what it is.


One good reason, in my opinion, is that there *are* immutable objects in
Python, among builtins. And people can easily build extension objects which are
immutable. So being impossible to write a regular object in Python which is
immutable is not orthogonal to me.


I didn't ask for a reason, I asked for a use case. Orthogonality is a
good thing, but so is generality. So I'll argue that the correct way
to make this situation orthogonal is to make builtin objects more
general by making it possible to add attributes to all of them.

On the other hand, practicality beats purity, and doing the above has
a significant cost in the current implementation, so leave it like it
is.
Now let me ask you a question. What is a good use case for "assert" that
justifies its introduction in the language? What is a good usecase for module
'unittest' which justifies its introduction in the standard library?
Unittesting doesn't change the language, and is part of any good
development methodology.

Assert is a shorthand for "if ... ; raise ...." that vanishes when you
turn on optimization. It's cleaner and more clearly expresses the
intent of the programmer, and saves a fair amount of boilerplate in
the best case.
Why do you think tuples are immutable and *enforced* to be so?


That you can't add attributes to a tuple is a detail of the
implementation; it's true for non-immutable types as well.
I'm not sure it's more important than
things like interned strings and the sharing of small integers. Most
of the discussion of immutables here seems to be caused by newcomers
wanting to copy an idiom from another language which doesn't have
immutable variables. Their real problem is usually with binding, not
immutability.

I'm not such a newcomer, but (how funny) Python is *the* language that
introduced me to the concept of immutable objects and their importance in
design :)


Well, that would explain why you think it's so important - it's where
you first encountered it. I'd argue that it's no more important than
identity - which is what I was searching for when I talked about
interned strings sharing small integers. There are builtin types that
preserve identity for equal instances, at least under some
conditions. There are no constructs for helping you do that with
user-defined objects. Should we add them for the sake of
orthogonality? I don't think so - not without a good use case.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Nov 25 '05 #37

P: n/a
"Giovanni Bajo" <no***@sorry.com> writes:
Bjrn Lindstrm wrote:
Why do you think we have a frozenset, for instance? By Mike's argument, we
shouldn't have it.


Not *my* arguments, certainly. Not unless you're seriously
misinterpreting them.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Nov 25 '05 #38

P: n/a
Giovanni Bajo <no***@sorry.com> wrote:
...
As I said before, I think you're confusing the (in Python pretty
non-existent) concept of encapsulation with Python's immutable types,
which are immutable because the implementation demands it. (A fact I
hope will disappear at some point.)


You seriously believe that strings, integers and tuples are immutable because
of implementation details? I believe they are part of a language design -- and
a good part of it.


Definitely. When I first designed gmpy, I wanted to make its number
types mutable, thinking this might probably enhance performance, but I
double checked with Python cognoscenti first -- and the result was a
plebiscite for IMmutable numbers (at the time, I was sort of new at
Python, and didn't really get it, but now I do;-).
Alex
Nov 25 '05 #39

P: n/a
Mike Meyer wrote:
And I have no problems with that. If you believe your class should
throw an error if someone calls an instances pop() method when it's
empty, do so.

Likewise, if you want to make it so a client can't change your
attributes, feel free to do so.

However, when you prevent a client from adding an attribute, you're
not merely making your objects immutable, you're making them
static. Python isn't a static language, it's a dynamic language. I
consider parts of it that are static to be warts.
I always thought that adding an attribute was just as bad as changing the
attributes, for an immutable object. But I now see your point (eventually!),
they are pretty different issues.

But, whatever attribute you add to the instance, it should *also* be immutable
(so that, in other words, wouldn't be so different than carrying around a tuple
with the original instance and the added attribute). This said, I think I
devise that a language support for enforcing immutability could allow adding
attributes to instance -- as long as those attributes then become immutable as
well.
I'm not sure it's more important than
things like interned strings and the sharing of small integers.
Most
of the discussion of immutables here seems to be caused by newcomers
wanting to copy an idiom from another language which doesn't have
immutable variables. Their real problem is usually with binding, not
immutability.

I'm not such a newcomer, but (how funny) Python is *the* language
that introduced me to the concept of immutable objects and their
importance in design :)


Well, that would explain why you think it's so important - it's where
you first encountered it.


Yes. But I'm familiar with different object semantics, and I found the
immutable objects to be a pretty good replacement of value semantics, and to
implement a kind-of pass-by-value convention in a language which only has
references.
I'd argue that it's no more important than
identity - which is what I was searching for when I talked about
interned strings sharing small integers. There are builtin types that
preserve identity for equal instances, at least under some
conditions. There are no constructs for helping you do that with
user-defined objects. Should we add them for the sake of
orthogonality? I don't think so - not without a good use case.


I don't think identity is important for immutable objects (as I wrote
elsewhere), so I don't think adding language constucts for this would prove
useful. Instead, immutable objects *are* common, and we still miss a way to
mark them as such.
--
Giovanni Bajo
Nov 25 '05 #40

P: n/a
"Giovanni Bajo" <no***@sorry.com> writes:
However, when you prevent a client from adding an attribute, you're
not merely making your objects immutable, you're making them
static.


No I don't believe that. If an object is immutable, then
obj.serialize() should return the same string every time. If you can
add attributes then the serialization output will become different.
Nov 25 '05 #41

P: n/a
Paul Rubin wrote:
"Giovanni Bajo" <no***@sorry.com> writes:


[pay attention to the quoting, I didn't write that :) ]
Mike Meyer wrote:

However, when you prevent a client from adding an attribute, you're
not merely making your objects immutable, you're making them
static.


No I don't believe that. If an object is immutable, then
obj.serialize() should return the same string every time. If you can
add attributes then the serialization output will become different.

I guess it might be argued that the method serialize() could return whatever
value it returned before, and that the added attribute could be "optional" (eg.
think of it as a cache that can be recomputed from the immutable attributes at
any time).

It's kind of a grey area. Surely, I would *not* mind if language support for
immutability prohibited this :)
--
Giovanni Bajo
Nov 25 '05 #42

P: n/a
Mike Meyer wrote:
Bjrn Lindstrm wrote:
Why do you think we have a frozenset, for instance? By Mike's
argument, we shouldn't have it.


Not *my* arguments, certainly. Not unless you're seriously
misinterpreting them.

Sorry then, I probably am. There must be a misunderstanding somewhere.

What is your position about frozenset? By my understanding of your arguments,
it is a hand-cuffed version of set, which just prevents bugs that could still
be caught by testing. The same applies for the arbitrary restriction of not
allowing sets to be key dictionaries (with their hash value being their id).
--
Giovanni Bajo
Nov 25 '05 #43

P: n/a
"Giovanni Bajo" <no***@sorry.com> writes:
Mike Meyer wrote:
And I have no problems with that. If you believe your class should
throw an error if someone calls an instances pop() method when it's
empty, do so.
Likewise, if you want to make it so a client can't change your
attributes, feel free to do so.
However, when you prevent a client from adding an attribute, you're
not merely making your objects immutable, you're making them
static. Python isn't a static language, it's a dynamic language. I
consider parts of it that are static to be warts.

I always thought that adding an attribute was just as bad as changing the
attributes, for an immutable object. But I now see your point (eventually!),
they are pretty different issues.

But, whatever attribute you add to the instance, it should *also* be immutable
(so that, in other words, wouldn't be so different than carrying around a tuple
with the original instance and the added attribute). This said, I think I
devise that a language support for enforcing immutability could allow adding
attributes to instance -- as long as those attributes then become immutable as
well.


That's cool, but only because immutability is such a slippery concept
in Python. We both agree that tuplee are immutable, right? So consider
this:
x = f()
type(x) <type 'tuple'> id(x) 136810980 y = copy.deepcopy(x)
y is x False y == x True f2(x)
id(x) 136810980 y == x False
So I'm perfectly willing to let your class declare that my attributes
be immutable, just so long as you mean the same thing by that as you
mean when you refer to tuples as immutable.
I'm not sure it's more important than
things like interned strings and the sharing of small integers.
Most
of the discussion of immutables here seems to be caused by newcomers
wanting to copy an idiom from another language which doesn't have
immutable variables. Their real problem is usually with binding, not
immutability.
I'm not such a newcomer, but (how funny) Python is *the* language
that introduced me to the concept of immutable objects and their
importance in design :)

Well, that would explain why you think it's so important - it's where
you first encountered it.

Yes. But I'm familiar with different object semantics, and I found the
immutable objects to be a pretty good replacement of value semantics, and to
implement a kind-of pass-by-value convention in a language which only has
references.


Like I said, I don't have a problem with immutable objects per
se. It's taking away my ability to extend the objects in all the ways
that Python allows that bothers me.

Personally, I haven't found much use for immutable *objects*, as for
immutable *attributes*. Python allows the latter. In Python, you
create an immutable object by creating an object with no mutable
attributes.
I'd argue that it's no more important than
identity - which is what I was searching for when I talked about
interned strings sharing small integers. There are builtin types that
preserve identity for equal instances, at least under some
conditions. There are no constructs for helping you do that with
user-defined objects. Should we add them for the sake of
orthogonality? I don't think so - not without a good use case.


I don't think identity is important for immutable objects (as I wrote
elsewhere), so I don't think adding language constucts for this would prove
useful. Instead, immutable objects *are* common, and we still miss a way to
mark them as such.


I think identity is important from an implementation point of
view. Implementation is important - so having constructs that let
you deal with this is useful. Python has those constructs.

What Python doesn't have in general is the ability to "mark"
objects. You have the ability to create attributes that are
immutable. You can create immutable objects by creating objects which
have no mutable attributes. What more do you need?

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Nov 25 '05 #44

P: n/a
Paul Rubin <http://ph****@NOSPAM.invalid> writes:
"Giovanni Bajo" <no***@sorry.com> writes:
> However, when you prevent a client from adding an attribute, you're
> not merely making your objects immutable, you're making them
> static.

No I don't believe that. If an object is immutable, then
obj.serialize() should return the same string every time. If you can
add attributes then the serialization output will become different.


There isn't a standard serialize method in Python, so I don't know how
you want to define it. I can think of perfectly reasonable definitions
of serialize where obj.serialize() won't always return the same string
on an immutable object, even if you don't allow adding attributes.

Personally, I'd argue that serialize shouldn't return the extra
attribute. If you want to add an attribute that gets serialized, you
need to subclass the immutable class, add the attribute there, and
extend serialize to include it. Whether or not that's reasonable
depends on how you want to define serialize.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Nov 25 '05 #45

P: n/a
"Giovanni Bajo" <no***@sorry.com> writes:
Mike Meyer wrote:
Bjrn Lindstrm wrote:
Why do you think we have a frozenset, for instance? By Mike's
argument, we shouldn't have it. Not *my* arguments, certainly. Not unless you're seriously
misinterpreting them.

Sorry then, I probably am. There must be a misunderstanding somewhere.


I'm seeing posts from you attribute to "Mike Meyer" (me) and "Mike" -
some of which definitely weren't me. So maybe it wasn't mine.
What is your position about frozenset? By my understanding of your arguments,
it is a hand-cuffed version of set, which just prevents bugs that could still
be caught by testing.
I have exactly the same problem with frozensets as I do with sets - I
can't add attributes to either one. That frozenset can't be changed
doesn't bother me particularly.
The same applies for the arbitrary restriction of not allowing sets
to be key dictionaries (with their hash value being their id).


I can't parse that. What do you mean by "key dictionaries"?

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Nov 25 '05 #46

P: n/a
Mike Meyer <mw*@mired.org> writes:
There isn't a standard serialize method in Python, so I don't know how
you want to define it.
Well, consider pickle, for example.
I can think of perfectly reasonable definitions
of serialize where obj.serialize() won't always return the same string
on an immutable object, even if you don't allow adding attributes.


Fair enough. How's this:

a = ImmutableObject()
b = deepcopy(a)
assert a == b # a and b start out equal
.... do stuff ....
# since a and b are immutable, they should still be equal
# no matter what has happened above
assert a == b

If you've added attributes to a but not to b, they should compare
unequal, breaking immutability.
Nov 25 '05 #47

P: n/a

Paul Rubin wrote:
Fair enough. How's this:

a = ImmutableObject()
b = deepcopy(a)
assert a == b # a and b start out equal
.... do stuff ....
# since a and b are immutable, they should still be equal
# no matter what has happened above
assert a == b

If you've added attributes to a but not to b, they should compare
unequal, breaking immutability.


How about this ?

a=(1,[])
b=copy.deepcopy(a)
assert a==b # True
a[1].append(1)
assert a!=b

Nov 25 '05 #48

P: n/a
Paul Rubin <http://ph****@NOSPAM.invalid> writes:
Mike Meyer <mw*@mired.org> writes:
There isn't a standard serialize method in Python, so I don't know how
you want to define it.
I can think of perfectly reasonable definitions
of serialize where obj.serialize() won't always return the same string
on an immutable object, even if you don't allow adding attributes.

Fair enough. How's this:

a = ImmutableObject()
b = deepcopy(a)
assert a == b # a and b start out equal
.... do stuff ....
# since a and b are immutable, they should still be equal
# no matter what has happened above
assert a == b

If you've added attributes to a but not to b, they should compare
unequal, breaking immutability.


Why should they compare unequal just because you add an attribute?
Nothing says all attributes have to be involved in an equality
comparison. In fact, Python classes by default ignore all attributes
when doing an equality comparison. In order to compare attributes, you
have to provide an __eq__ method (or __cmp__, but we'll ignore
that). It can't mention your new attribute, because it doesn't exist
unless you add it. So your final assertion will be true even after
adding a new attribute.

Of course, there's a fundamental flaw in your definition of
"immutable", in that there are immutable objects - tuples - for which
the condition t1 == t2 is *not* a constant. Tuples can hold mutable
objects, meaning you can change those. Doing so will make a tuple not
compare equal to a copy of the state prior to changing the contents of
the tuple.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Nov 25 '05 #49

P: n/a
On Thu, 24 Nov 2005 12:55:07 +0000, Antoon Pardon wrote:
Suppose I have the following code.

from module import __take_care__

__private_detail__ = ...

I now have two variable that are flaged the same way, but they are not.
No, you have two names written using a poor naming convention.

__name__ should be used only for Python's special methods.
__take_care__ is a private variable from an other module which I should
use with extreme care not to break the other package.
Python doesn't do any special treatment of __name or __name__ from
modules. The only information hiding techniques Python enforces are that
module._name (single leading underscore) is not imported by "from module
import *", and class.__name (double leading underscore) is mangled to
class._Class__name.

Both techniques are done in order to let the module creator protect users
from *accidentally* shooting themselves in the foot, while still allowing
the module users to *deliberately* shoot themselves in the foot if that is
what they need or want to do. Deliberately breaking these information
hiding techniques are features, not bugs.

__private_detail__ on the other hand is just keeping private data for my
own module, which I should care about as just any other variable in my
module.
If you care about keeping __private_detail__ no more than you care about
public_detail, what makes one private and one public?

It are other modules that should take special care if they
should choose to import this variable.


I'm not sure what the difference is. If there is a difference, why are you
using the same naming convention for different sorts of names ("private
module variable" and "private module data"). If there is no difference, I
don't understand the point of your example.
--
Steven.

Nov 26 '05 #50

90 Replies

This discussion thread is closed

Replies have been disabled for this discussion.