Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #59099 > unrolled thread

'isimmutable' and 'ImmutableNester'

Started byFrank-Rene Schäfer <fschaef@gmail.com>
First post2013-11-11 21:47 +0100
Last post2013-11-12 01:38 +0000
Articles 6 — 5 participants

Back to article view | Back to comp.lang.python


Contents

  'isimmutable' and 'ImmutableNester' Frank-Rene Schäfer <fschaef@gmail.com> - 2013-11-11 21:47 +0100
    Re: 'isimmutable' and 'ImmutableNester' Ned Batchelder <ned@nedbatchelder.com> - 2013-11-11 12:55 -0800
      Re: 'isimmutable' and 'ImmutableNester' Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-11-12 00:17 +0000
        Re: 'isimmutable' and 'ImmutableNester' Mark Lawrence <breamoreboy@yahoo.co.uk> - 2013-11-12 00:30 +0000
        Re: 'isimmutable' and 'ImmutableNester' Chris Angelico <rosuav@gmail.com> - 2013-11-12 12:35 +1100
    Re: 'isimmutable' and 'ImmutableNester' Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-11-12 01:38 +0000

#59099 — 'isimmutable' and 'ImmutableNester'

FromFrank-Rene Schäfer <fschaef@gmail.com>
Date2013-11-11 21:47 +0100
Subject'isimmutable' and 'ImmutableNester'
Message-ID<mailman.2397.1384202874.18130.python-list@python.org>
I prepared a PEP and was wondering what your thoughts are about it:

  PEP:            <pep number>
  Title:          ``isimmutable(Obj)`` and/or ``ImmutableNester``
  Version:        <version string>
  Last-Modified:  <date string>
  Author:         Frank-Rene Schaefer, fschaef@users.sourceforge.net
* BDFL-Delegate:  <PEP czar's real name>
* Discussions-To: fschaef@users.sourceforge.net
  Status:         Draft
  Type:           <Standards Track | Informational | Process>
* Content-Type:   text/x-rst
* Requires:       <pep numbers>
  Created:        11-nov-2013
* Python-Version: 2.7.1
  Post-History:   <dates of postings to python-list and python-dev>
* Replaces:       <pep number>
* Superseded-By:  <pep number>
* Resolution:     <url>

General Idea
============

A built-in function 'isimmutable()' shall tell efficiently whether the object
of concern is mutable or not. That is it must reflect on the whole object tree
whether it contains mutable elements or not.  For example, in the code fragment

::
    verdict_0 = isimmutable(3.14)
    verdict_1 = isimmutable((1,2,3))
    verdict_2 = isimmutable(((1,2),(2,3),(3,4)))

all verdicts are 'True' because the tested objects consist of purely immutable
components. However, the ``x`` in

::
    x       = (1,(2,"abc", [1,2,3]))
    verdict = isimmutable(x)

triggers the verdict to be 'False' because ``x[1][2]`` is a list and therefore
mutable.

It may be conceivable to have a special class-type called ``ImmutableNester``
which has no write-access member functions and does not allow its derived
classes to have write-access member functions. Instead, any derived class
aggregates members at the time of construction. At this point in time, when
members are nested in the class, it is checked if the members are of subclasses
of ``ImmutableNester``.

The advantage of the ``isimmutable()`` function is that no extra class
functionality needs to be implemented. The disadvantage is that the
immutability must be checked manually and at each time the object is used. The
``ImmutableNester`` class type checks for immutability once, at construction
time and no further manual checks are necessary.

Rationale
=========

If an object is immutable then copying of it can be safely be replaced by a
setting of a reference. The principal scenario is when an instance A gives an
instance B access to some data D under the provision that B does not change it.
Therefore, B must either clone the data or it must be safe to assume that the
data cannot change, i.e. is immutable.

If the objects are large and/or many there a significant performance impact may
raise from a deepcopy or manual cloning of objects. Therefore, the
``isimmutable()`` built-in function is key for a safe implementation of
reference-instead-of-copying.

Ensuring immutability is also key for the so called 'Flyweight Design Pattern'.

[toc] | [next] | [standalone]


#59101

FromNed Batchelder <ned@nedbatchelder.com>
Date2013-11-11 12:55 -0800
Message-ID<8e3da943-3ed5-49f1-a4f2-4836d0f435dd@googlegroups.com>
In reply to#59099
On Monday, November 11, 2013 3:47:45 PM UTC-5, Frank-Rene Schäfer wrote:
> I prepared a PEP and was wondering what your thoughts are about it:

The best place to discuss proposals for changes to the Python language and library is the Python-Ideas mailing list: https://mail.python.org/mailman/listinfo/python-ideas

There you will get in-depth discussion about the details of your proposal.  Fair warning: it's very unlikely that your proposal will be adopted (most are not), but you will learn a lot about how Python works in the process. :)

--Ned.

[toc] | [prev] | [next] | [standalone]


#59123

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-11-12 00:17 +0000
Message-ID<5281738d$0$6574$c3e8da3$5496439d@news.astraweb.com>
In reply to#59101
On Mon, 11 Nov 2013 12:55:56 -0800, Ned Batchelder wrote:

> On Monday, November 11, 2013 3:47:45 PM UTC-5, Frank-Rene Schäfer wrote:
>> I prepared a PEP and was wondering what your thoughts are about it:
> 
> The best place to discuss proposals for changes to the Python language
> and library is the Python-Ideas mailing list:
> https://mail.python.org/mailman/listinfo/python-ideas

Actually it is recommended to get at least initial feedback here first, 
to weed out proposals like:

"Python ought to allow function currying, like in Haskell."

"You mean like functools.partial?"

"Oh, never mind then."


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#59124

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2013-11-12 00:30 +0000
Message-ID<mailman.2413.1384216245.18130.python-list@python.org>
In reply to#59123
On 12/11/2013 00:17, Steven D'Aprano wrote:
> On Mon, 11 Nov 2013 12:55:56 -0800, Ned Batchelder wrote:
>
>> On Monday, November 11, 2013 3:47:45 PM UTC-5, Frank-Rene Schäfer wrote:
>>> I prepared a PEP and was wondering what your thoughts are about it:
>>
>> The best place to discuss proposals for changes to the Python language
>> and library is the Python-Ideas mailing list:
>> https://mail.python.org/mailman/listinfo/python-ideas
>
> Actually it is recommended to get at least initial feedback here first,
> to weed out proposals like:
>
> "Python ought to allow function currying, like in Haskell."
>
> "You mean like functools.partial?"
>

"But I don't want to do it like that, I want..."

-- 
Python is the second best programming language in the world.
But the best has yet to be invented.  Christian Tismer

Mark Lawrence

[toc] | [prev] | [next] | [standalone]


#59129

FromChris Angelico <rosuav@gmail.com>
Date2013-11-12 12:35 +1100
Message-ID<mailman.2414.1384220135.18130.python-list@python.org>
In reply to#59123
On Tue, Nov 12, 2013 at 11:17 AM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> On Mon, 11 Nov 2013 12:55:56 -0800, Ned Batchelder wrote:
>
>> On Monday, November 11, 2013 3:47:45 PM UTC-5, Frank-Rene Schäfer wrote:
>>> I prepared a PEP and was wondering what your thoughts are about it:
>>
>> The best place to discuss proposals for changes to the Python language
>> and library is the Python-Ideas mailing list:
>> https://mail.python.org/mailman/listinfo/python-ideas
>
> Actually it is recommended to get at least initial feedback here first,
> to weed out proposals like:
>
> "Python ought to allow function currying, like in Haskell."
>
> "You mean like functools.partial?"
>
> "Oh, never mind then."

aka "Guido's Time Machine" situations. I think this might be one of
them - I read the proposal and thought "Hashability should answer
that", and random832 also posted the same. Love that time machine!

ChrisA

[toc] | [prev] | [next] | [standalone]


#59130

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-11-12 01:38 +0000
Message-ID<5281867e$0$6574$c3e8da3$5496439d@news.astraweb.com>
In reply to#59099
Hi Frank-Rene, and welcome. Comments below.


On Mon, 11 Nov 2013 21:47:45 +0100, Frank-Rene Schäfer wrote:

> I prepared a PEP and was wondering what your thoughts are about it:
> 
>   PEP:            <pep number>
>   Title:          ``isimmutable(Obj)`` and/or ``ImmutableNester``
[...]
> * Python-Version: 2.7.1

That won't do. Python 2.7 is in maintenance mode, it will not gain any 
new functionality. There won't be a Python 2.8 either. If you want to 
propose new functionality, it will have to go into 3.5. (You've missed 
the opportunity for 3.4, since "feature-freeze" is only weeks away.)


> General Idea
> ============
> 
> A built-in function 'isimmutable()' shall tell efficiently whether the
> object of concern is mutable or not. That is it must reflect on the
> whole object tree whether it contains mutable elements or not.  For
> example, in the code fragment

This has been proposed before. It has failed because there is no way to 
tell in general whether an arbitrary object is immutable or not. If you 
only look at the common built-in types, it is quite trivial, e.g.:

- int, str, bytes, float, frozenset, bool, None are immutable;
- list, dict, set are not immutable;
- tuple is immutable if all of its elements are immutable.


But as soon as you allow arbitrary objects, you're in trouble. How do you 
tell whether an object is immutable?

I recommend that you start by writing a reference implementation:

def isimmutable(obj):
    ... # ?

Some obvious thoughts:

- It is not enough to include a big list of immutable classes:

    # don't do this
    if isinstance(obj, (float, int, frozenset, ...)): 
        return True

  because that list will never be complete and can become out-of-date.

- You could try writing to the object (how?), and if it succeeds, 
  you know it is mutable. But if it fails, that might just mean 
  that you haven't tried writing to it in the correct manner.

- But if the obj is mutable, you've just mutated it. That's bad.

- You can try hashing the object:

  hash(obj)

  If that fails, then the object *might as well* be mutable, since 
  you can't use it in sets or as dict keys. But if that's all 
  isimmutable() does, why not just call hash(obj) directly?


Anyway, I recommend you spend some time on this exercise. The PEP will 
not be accepted without a reference implementation, so you're going to 
have to do it at some point.


Another thing which your proto-PEP fails to cover in sufficient detail is 
why you think such a function and/all class would be useful. You do say 
this:

> If an object is immutable then copying of it can be safely be replaced
> by a setting of a reference. The principal scenario is when an instance
> A gives an instance B access to some data D under the provision that B
> does not change it. Therefore, B must either clone the data or it must
> be safe to assume that the data cannot change, i.e. is immutable.

but I really don't think much of this as the principle scenario. I don't 
think I've ever written code that matches this scenario. If possible, you 
should give a real example. If not real, at least a toy example. Either 
way, using code rather than just a vague description is better.


> If the objects are large and/or many there a significant performance
> impact may raise from a deepcopy or manual cloning of objects.
> Therefore, the ``isimmutable()`` built-in function is key for a safe
> implementation of reference-instead-of-copying.

I don't think this is true. deepcopy (at least sometimes) will avoid 
making a copy if the object is immutable:

py> import copy
py> x = (10001, 20002, 30003, (40004, 50005, (60006, 70007)), 80008)
py> copy.copy(x) is x
True
py> copy.deepcopy(x) is x
True

so what advantage does isimmutable give you?



> Ensuring immutability is also key for the so called 'Flyweight Design
> Pattern'.

More details please.


Ultimately, nothing knows whether an object is immutable or not better 
than the object itself. copy.copy and copy.deepcopy know this, and ask 
the object to copy itself rather than copy it from the outside. Since the 
object knows whether it is immutable, it knows whether or not to make a 
copy or just return itself. It seems to me that isimmutable() *appears* 
to be a useful function to have, but if you look into it in detail the 
apparently uses for it don't hold up. In practice, it would be almost 
impossible to implement (except as below) and even if you could you would 
never need it.

Really, it seems to me that the only way to implement isimmutable would 
be to delegate to the object:

def isimmutable(obj):
    return obj.__isimmutable__()

This gives you:

if isimmutable(obj):
    x = obj
else:
    x = copy.copy(obj)
function_that_might_modify(x)


but that gives you no advantage at all that the simpler:

function_that_might_modify(copy.copy(obj))

doesn't give. So what's the point?


-- 
Steven

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web