mailRe: Vote for the design of the relax data storage object singleton.


Others Months | Index by Date | Thread Index
>>   [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Header


Content

Posted by Edward d'Auvergne on March 17, 2007 - 02:28:
The attached file is a Python module, try importing it and then
playing with its contents.  The module contains two singletons -
'Singleton' and 'NewSingleton'.  Both are instantiated in the same
manner as new relax data storage object (implementation B which we
voted for), the class name being masked by the instance reference.
NewSingleton is derived from the Singleton base class demonstrating
inheritance.  QID!

These singletons are two completely different objects (in different
memory space) which can be used for completely different tasks and can
be used by completely different parts of the program all while being
true singletons - only one instance of each will ever exist in the
program.  If you cannot see this, I challenge you to write a counter
example module demonstrating that what this extremely basic module is
doing cannot be done.  On the other-hand if you cannot understand the
utility of this inheritance, behavioural modifications and code reuse
for objects with different stated purposes yet similar basic
behaviours, then there is nothing else I can argue.

Edward


On 3/16/07, Gary S. Thompson <garyt@xxxxxxxxxxxxxxx> wrote:
Edward d'Auvergne wrote:

> On 3/16/07, Chris MacRaild <c.a.macraild@xxxxxxxxxxx> wrote:
>
>> On Fri, 2007-03-16 at 01:50 +1100, Edward d'Auvergne wrote:
>> > On 3/16/07, Chris MacRaild <c.a.macraild@xxxxxxxxxxx> wrote:
>> > > On Fri, 2007-03-16 at 01:00 +1100, Edward d'Auvergne wrote:
>> > > > On 3/15/07, Chris MacRaild <c.a.macraild@xxxxxxxxxxx> wrote:
>> > > > > On Thu, 2007-03-15 at 00:09 +1100, Edward d'Auvergne wrote:
>> > > > > > On 3/14/07, Chris MacRaild <c.a.macraild@xxxxxxxxxxx> wrote:
>> > > > > > > On Tue, 2007-03-13 at 19:51 +1100, Edward d'Auvergne wrote:
>> > > > > > > > Gary,
>> > > > > > > >
>> > > > > > > > I've written some unit tests which are located in the file
>> > > > > > > > 'test_suite/unit_tests/data/__init__.py'.  Would you
>> know what
>> > > > > > > > modifications I need to apply to make these tests run?
>> These tests
>> > > > > > > > are for the methods of the Data singleton class (the
>> relax data
>> > > > > > > > storage object) which is located in
>> 'data/__init__.py'.  I haven't
>> > > > > > > > used the statement 'from x import Data' for this class
>> so it is the
>> > > > > > > > legal and ubiquitous usage of an __init__.py file.  Would
>> > > > > > > > 'unit_test_runner.py' handle this code?
>> > > > > > > >
>> > > > > > > > Thanks,
>> > > > > > > >
>> > > > > > > > Edward
>> > > > > > > >
>> > > > > > > >
>> > > > > > > > P.S.  These tests demonstrate the utility of
>> subclassing the singleton
>> > > > > > > > and is one reason I was arguing for the use of the
>> class import rather
>> > > > > > > > than reference import.
>> > > > > > > >
>> > > > > > >
>> > > > > > > It is of course correct that the Singleton implimentation
>> I proposed
>> > > > > > > does not allow for subclassing. This however might well
>> be seen as a
>> > > > > > > design feature, given the well known conceptual problems
>> with
>> > > > > > > subclassing Singleton. Essentially, subclassing violates
>> the Singleton
>> > > > > > > Design Pattern:
>> > > > > > >
>> > > > > > > class Singleton:
>> > > > > > >     def __new__(self):
>> > > > > > >         ...
>> > > > > > >
>> > > > > > > class Sub(Singleton): pass
>> > > > > > >
>> > > > > > > >>> a = Singleton()
>> > > > > > > >>> b = Sub()
>> > > > > > > >>> isinstance(a,Singleton)
>> > > > > > > True
>> > > > > > > >>> isinstance(b,Singleton)
>> > > > > > > True
>> > > > > > > >>> a is b
>> > > > > > > False
>> > > > > > > >>> a == b
>> > > > > > > False
>> > > > > > >
>> > > > > > > ie. we have 2 instances of Singleton that are not the
>> same thing, and
>> > > > > > > not even equal! If this is the behaviour you want, then
>> you need
>> > > > > > > something other than Singleton. On the other hand, if you
>> really want
>> > > > > > > Singleton, then you can't also hope for subclassability.
>> > > > > >
>> > > > > > Actually one is an instance of Singleton and the other is
>> an instance
>> > > > > > of Sub.
>> > > > >
>> > > > > The definition of inheritance is that an instance of the
>> subclass is
>> > > > > also an instance of the parent class. ie. b is an instance of
>> both Sub
>> > > > > and Singleton. Inheritance from a Singleton class is
>> therefore a logical
>> > > > > contradiction.
>> > > >
>> > > > That is actually incorrect!
>> > >
>> > > Sorry to drag this on, but I'm not incorrect here, and its a fairly
>> > > fundamental point of OO philosophy and practice that is well worth
>> > > getting right. This is pasted directly from my Python command
>> line (the
>> > > interpreter does not lie!):
>> > >
>> > > >>> class A: pass
>> > > ...
>> > > >>> class B(A): pass
>> > > ...
>> > > >>> a= A()
>> > > >>> b = B()
>> > > >>> isinstance(a,A)
>> > > True
>> > > >>> isinstance(a,B)
>> > > False
>> > > >>> isinstance(b,B)
>> > > True
>> > > >>> isinstance(b,A)
>> > > True
>> > >
>> > > Because B is a subclass of A, all instances of B are also
>> instances of A
>> >
>> > The 'isinstance()' built-in function will return true if object x is
>> > an instance of the supplied class or, importantly, a subclass.  This
>> > is what it's docstring says.  Try the following instead (after
>> > reissuing the above statements):
>> >
>> > >>> a is b
>> > False
>> > >>> hash(a)
>> > -1217311764
>> > >>> hash(b)
>> > -1214788020
>> > >>> id(a)
>> > -1217311764
>> > >>> id(b)
>> > -1214788020
>> >
>> > If b was the same instance as a, then the first statement would return
>> > true.  The two hash() statements show that a and b are different.  The
>> > two id() statements show that they occupy different locations in
>> > memory - the number is the object's memory address.  Another test is
>> > populating the empty containers:
>> >
>> > >>> a.x = 1
>> > >>> b.y = 2
>> > >>> dir(a)
>> > ['__doc__', '__module__', 'x']
>> > >>> dir(b)
>> > ['__doc__', '__module__', 'y']
>> >
>> > The instances a and b are very much different!
>>
>> This is all true, but misses the point. a and b are different objects,
>> but they are of the same type:
>>
>> >>> type(a) is type(b)
>> True
>
>
> They are necessarily the same type, both are <type 'instance'>.


yes but that isn't the class you need to look at object.__class__ and object.__bases__ and so on resursivley...

>
>> and both of them are instances of the parent class A. So to go back to
>> where we started: for almost any implimentation of Singleton
>
>
> Both are not instances of A.  The Python builtin function
> 'isinstance()' is poorly named.  It returns True if object b is an
> instance of class B.  But it also returns true if object b is an
> instance of class B which is subclassed from A (isinstance(b, A)).
> Note that there is no reference to an instance of A in this second
> test, either here or when typing 'help(isinstance)').

I beg to disagree, it isn't (however type is ;-)) It does exactly what
is says on the packet

if you have class A and class B(A)
and instances a and b thereof

a is an A
and b is an A and a B

>
>
>> >>> single = Singleton()
>> >>> class Sub(Singleton): pass
>> ...
>> >>> sub = Sub()
>> >>> isinstance(sub,Singleton)
>> True
>
>
> This is the second part of the isinstance test, seeing if sub is and
> instance of some class which is itself subclassed from Singleton.
>
>
>> >>> isinstance(single,Singleton)
>> True
>
>
> This is the first part of the isinstance test, the actual testing if
> it is an instance.
>
>
>> >>> sub is single
>> False
>>
>> This breaches the Singleton design because we have two *different*
>> objects that are both instances of the Singleton class.
>
>
> WRONG!!!  We now have two different singletons!  They occupy different
> memory addresses and will have different contents.  For example one
> dictionary type can be the relax data storage object and the other can
> be an object storing the various components used in the chi-squared
> equation, relaxation equations, spectral density values, and geometric
> components all calculated by the module 'maths_fns.mf'.  Both these
> two objects benefit by being singletons - the alternative currently
> used by 'maths_fns.mf' is to pass a single data object into the
> hundreds of functions which use that object.
>
NO... you have two object ot type Singleton i.e. sub.__base__==singleton
it is a singleton as is single.__class__ both can be accepted in the
sample place and behave the same way this breaks the contract for
anything that is is a singleton. There can only be one instance of
singleton  within the interpreter. You can never have  two singletons
which share the same  type other than being an object.

>
>> To put this in terms of the favourite metaphore, because apple is a
>> subclass of fruit, all apples are also fruits (ie. all instances of
>> class Apple in also instances of class Fruit). Even if you have several
>> different apples, this does not make them any less fruity.
>
>
[snip to the chase]

I don't know where to start quite. Chris's explanation is clear (and
correct).

If one class derives from another it has an is a or inheritance contract.

An apple is a fruit, a fruit is a fruit and a pear is a fruit. any where
you accept a fruit you have to accpet apples pears or straight fruit.

Now the singleton pattern is behavioural not inheritance based. For each
class you call a singleton there can only be one instance of that type
in memory. So if you can have a print queue singleton there can only
ever be __one__ instance of a print queue singleton in memory. i.e. only
one memory address is associated with the class print queue. if you
subclass print queue to give you say an advanced print queue any object
is of type advanced print queue  is a  print queue and and an advanced
print queue all at the same time. now print queue was a singleton and so
must advanced print queue be. so again there can only be one memory
location associated with type advanced print queue and print queue. If
you make an instance of print queue which is not and advanced print
queue while you have an instance of advanced print queue in memory you
have broken the contract.

Lets take it one step further.  Now consider if you sub class print
queue again to give a dumb print queue. That object is a print queue and
a dumb print queue all at the same time.  A print queue is a singleton
and so must be a dumb print queue. If you create an object of dumb print
queue no other memory location other than that __instance__ may be
associated with a print queue or an advanced print queue (which by its
inheritance relationsship to print queue has __to be a print queue__) .
As soon as you create another isntance  of either of these you break the
singleton contract because otf the inheritance contract. Except under
very strict conditions  there is a  very big impedance mismatch between
singleton and inheritance (which I can go into if need be).

I am pretty secure with my undertanding of inheritance and this pattern
and it is just one of those unavoidable thing. If you label something as
a  singleton and there can only ever be one instance of that type in
memory. Anything you call a singleton  must be the only instance of that
type in memory whehter it is of that type directly or because you can
follow an  ineritance relationhsip to it.

It would somethimes be nice two have to fermions that could both
occupied the same space (ever wanted to walk through a wall when someone
was cross at you) but they can't (tip you hat to mr pauli) they just are
not made that way and the same goes here!


regards gary

>
>
> Edward
>
>
> P.S.  For those still following this thread, this argument is not
> related to what was voted upon :)
>
> _______________________________________________
> relax (http://nmr-relax.com)
>
> This is the relax-devel mailing list
> relax-devel@xxxxxxx
>
> To unsubscribe from this list, get a password
> reminder, or change your subscription options,
> visit the list information page at
> https://mail.gna.org/listinfo/relax-devel
>
> .
>


-- ------------------------------------------------------------------- Dr Gary Thompson Astbury Centre for Structural Molecular Biology, University of Leeds, Astbury Building, Leeds, LS2 9JT, West-Yorkshire, UK Tel. +44-113-3433024 email: garyt@xxxxxxxxxxxxxxx Fax +44-113-2331407 -------------------------------------------------------------------



class Singleton:
    def __init__(self):
        self.a = 1

    def base_fn(self):
        print "Hello"

# Inheritance (create a new singleton extending/modifying the properties of 
the old).
class NewSingleton(Singleton):
    def __init__(self):
        self.a = -1

    def new_fn(self):
        print "Bye"

# Instantiate the singletons.
Singleton = Singleton()
NewSingleton = NewSingleton()

# Add some new objects.
Singleton.x = 2
NewSingleton.x = 3
NewSingleton.y = 2000

# Printouts.
print
print "Singleton is NewSingleton: " + `Singleton is NewSingleton`
print "Contents of Singleton:    " + `dir(Singleton)`
print "Contents of NewSingleton: " + `dir(NewSingleton)`
print "Singleton.base_fn is NewSingleton.base_fn: " + `Singleton.base_fn is 
NewSingleton.base_fn`
print
print "Singleton.a:    " + `Singleton.a`
print "NewSingleton.a: " + `NewSingleton.a`
print "Singleton.x:    " + `Singleton.x`
print "NewSingleton.x: " + `NewSingleton.x`
print

# Execute the methods.
print "Singleton.base_fn():"
Singleton.base_fn()
print "NewSingleton.base_fn():"
NewSingleton.base_fn()
print "NewSingleton.new_fn():"
NewSingleton.new_fn()

Related Messages


Powered by MHonArc, Updated Wed Mar 21 20:00:20 2007