
There are some signs :-) that Python's object model is going to be revised even _before_ Python 3000. Is someone willing to join me fighting for class methods (I mean 'real' class-methods in the Smalltalk style here, _not_ static methods like in Java or C++). Thomas

"TH" == Thomas Heller <thomas.heller@ion-tof.com> writes:
TH> There are some signs :-) that Python's object model is going to TH> be revised even _before_ Python 3000. TH> Is someone willing to join me fighting for class methods (I mean TH> 'real' class-methods in the Smalltalk style here, _not_ static TH> methods like in Java or C++). The idea sounds good in the abstract. Class are objects and objects ought to have methods that implement their behavior. How does that very vague idea turn into something real? No clue. You start fighting and let's see where it goes :-). Jeremy

Jeremy Hylton wrote:
Here's something to start the fight ;-) ... 1) What would you do with class methods that you cannot do with e.g. globals and functions ? 2) How would you determine which methods are class-only methods and which are one usable by instances ? 3) If you don't like globals (see 1), wouldn't it be possible to store the state you want to manipulate using class methods in some other context object ? My impression is that class methods are not really needed and would only make optimizing Python harder... but that's maybe just me ;-) -- Marc-Andre Lemburg ______________________________________________________________________ Company & Consulting: http://www.egenix.com/ Python Pages: http://www.lemburg.com/python/

I will write up a concrete example I have and post it later. Look into the motivation for the Prototype Pattern in the GOF book, or even better in the discussion of this pattern in the 'Design Pattern Smalltalk Companion' book. This pattern is not needed if classes are 'first class' objects.
2) How would you determine which methods are class-only methods and which are one usable by instances ?
This is one of the issues which has to be resolved. I have no proposal at the moment. (Maybe function attributes can help here?)
I want the class methods (for example) to create and manipulate this 'context object'. This object, however, belongs into the class... What I want to avoid is class X(...): .... initialize(X)
Unfortunately not, I fear. Thomas

I imagine many of us (including yours truly :-) don't recall that in enough detail and/or don't have the book handy to look it up, so would you please do us a favor and explain this in a bit more detail?
This pattern is not needed if classes are 'first class' objects.
Depending on what you mean by the 'first class' phrase (which means something different to everyone), Python classes are already as first class as they get. E.g. they are tangible objects and you can pass them around and store them in variables.
What would initialize(X) do that you can't write in the class body? --Guido van Rossum (home page: http://www.python.org/~guido/)

This is a valid request, but please wait for my larger example. I'm referring to this because I have not been good at explaining the things I want... All in all: I'm not really ready to start the fight _now_, I was just looking for some help... Thomas PS: I find it strange that everyone so far seems to be against it.

[Thomas Heller]
... PS: I find it strange that everyone so far seems to be against it.
I didn't get that sense yet. I did get the sense they're not actively *for* it yet, and the questions asked so far explain why: What does it buy us? What are the current alternatives? What are the costs (not least of all in terms of breaking existing code)? It's a bunch of tradeoffs, and it appears that few who aren't steeped in Smalltalk's view of the world understand what the practical *attraction* is. The same questions get asked even for wholly non-controversial changes, like, say, adding an optional ">> file" clause to "print" <wink>. by-default-it's-best-to-resist-everything-ly y'rs - tim

On Fri, 20 Apr 2001, Thomas Heller wrote:
There are a number of reasons why I'm all for Class attributes in general. For example, right now a class object cannot assert an interface. Sure, a class can say: class Foo: __implements__ = Bar # instances implement Bar but that is an assertion for the instances, not the *class itself*. Currently, you have to do the ugly hack: class Foo: __class_implements__ = FooFactory # the class implements # FooFactory. We've done things like the above in several places in our underground component elaboration. Not having class methods introduces many little wrinkles in the Python object model that have to be worked around. I can imagine, for example, wanting to define an __reduce__, or __init__ for a class object, which is not possible now.
I always thought along the lines of saying Class.instanceAttribute('foo') in the place of what is now said Class.foo. This would, of course, break code, but the warning and back to the future features mitigate most of that risk.
Yes! We use this monstrosity a lot in Zope. -Michel

On Fri, Apr 20, 2001 at 05:40:21PM +0200, Thomas Heller wrote: | I want the class methods (for example) to create and manipulate | this 'context object'. This object, however, belongs into the class... | | What I want to avoid is | | class X(...): | .... | initialize(X) Here is a different approach to consider : class X : def __class_init__( class_X ) : initialize( class_X ) The idea here is to provide a "magic" method in the class that the interpreter calls as soon as the class object exists. The first (only) argument is the class object, which can be named as desired (analogous to 'self'). The main problem here is clients aren't prevented from calling this method, and they really shouldn't. -D

Well, the official policy on this is now that Py3K is just a slogan, and that all the real work will be introduced gradually. :-)
I will fight class methods to the death. :-) Seriously, I think you'll find an ally in Jim Fulton, who basically told me (since he's sort of my boss :-) to get on with this work. I think it can work as follows: Let x be an object, C its class, and M C's class. So, x.__class__ is C C.__class__ is M Then x's methods are described in C.__dict__, and C's methods are described in M.__dict__. The problem is that if you write C.spam, there could be two spams: one in C.__dict__, one in M.__dict__. Which one to use? How does Smalltalk resolve this? The problem is that for backwards compatibility, at lease, C.spam must be the unbound version of x.spam, because currently x.spam(...) can always also be written as C.spam(x, ...). For regular methods it may be possible to avoid this simply by choosing non-conflicting names, but I seem to recall that Jim wanted to use class methods with certain special names (like __init__ or __getattr__?), and I have no idea how to do this without dropping the idea that x.spam(...) is C.spam(x, ...). So maybe that's the solution? --Guido van Rossum (home page: http://www.python.org/~guido/)

Seriously, I think you'll find an ally in Jim Fulton,
So there _is_ some hope.
who basically told me (since he's sort of my boss :-) to get on with this work.
This must be the reason that ExtensionClass provides them: You can implement them in C, and override them in python subclasses. Thomas

"GvR" == Guido van Rossum <guido@digicool.com> writes:
GvR> Let x be an object, C its class, and M C's class. So, | x.__class__ is C | C.__class__ is M GvR> Then x's methods are described in C.__dict__, and C's methods GvR> are described in M.__dict__. GvR> The problem is that if you write C.spam, there could be two GvR> spams: one in C.__dict__, one in M.__dict__. Which one to GvR> use? If you use naming to generally distinguish, and have a lookup chain that first found it in C.__dict__ and then looked in M.__dict__, you could control what happens when the name is in both dicts by using a more explicit lookup, e.g. C.__dict__['meth'] vs. C.__class__.__dict__['meth'] But maybe that's too ugly. GvR> How does Smalltalk resolve this? I don't remember, but I do remember that ObjC had the same concepts, and it used a distinguishing marker on the method definition to say whether the method was a class method (`+') or instance method (`-'), e.g. + void some_class_method ... - void an_instance_method Another question: presumably when I write class Foo: pass Foo is implicitly given the built-in metaclass M, but say I wanted to define a class Foo with a different metaclass, how would I spell this? I think at one point I suggested a semi-ugly syntactic hack, where `class' was actually a namespace and you could add new metaclasses to it. So you could write something like class.WeirdClass Foo: pass and now Foo's metaclass would be WeirdClass. waiting-for-the-bottom-turtle-to-burp-ly y'rs, -Barry

[Barry wrote]
Couldn't be C.__class__.meth be used?
self class method; or self method; that creating a class Point in Smalltalk _automatically_ creates two classes: Point and PointClass. The latter is normally hidden (but contains the class methods of Point as instance methods). Thomas

"Thomas Heller" <thomas.heller@ion-tof.com> wrote,
In my 'objectmodule' I adopted a concept which I refer to as the "unbound instance". That is, I invented an object which is used as a proxy for accessing instance attributes. It looks like an instance but only for the purposes of attribute access. Now, since this object will only return "unbound method objects" when accessing a method (as opposed to the "bound method object" you would get when accessing a method from a real instance) I thought the name was at least slightly appropriate. In short, each class defined by the objectmodule has a special attribute '_' which is the "unbound instance" for that class. This unbound instance is used to resolve the name ambiguity. Now, consider this: import object class foo(object.base): def frob(self): print "I've been frobbed", self class __class__: def frob(cl): print "No, I've been frobbed", cl >>> f = foo() >>> x = f.frob >>> # x is the instance frob method bound to f >>> y = foo.frob >>> # y is the class frob method bound to foo >>> z = foo._.frob >>> # z is the instance frob method but is not bound to any instance >>> huh = foo.__class__._.frob >>> # huh is the class frob method but is not bound to any class >>>
That's the way I remember it too. And, (if I recall correctly) in SmallTalk (unlike CLOS), you have no control over the meta-class. In the example above, like in SmallTalk, the name of foo.__class__ is determined automatically. In this case it is 'foo_class'. However, unlike SmallTalk, the above example could be extended to include a 'class __class__:' definition under the existing 'class __class__:'. The name generated by this construct would, of course, be 'foo_class_class'. Lather, Rinse, repeat... -- Donald Beaudry Ab Initio Software Corp. 201 Spring Street donb@init.com Lexington, MA 02421 ...Will hack for sushi...

On Fri, 20 Apr 2001, Guido van Rossum wrote:
I think, at the expense of breaking code, M.
This is the part that choosing M would break. To get at C's shared instance attributes you could say something like C.instanceAttribute('spam')(x, ...). Yes, it's ugly. Perhaps someone can think of a more elegant spelling?
I'm not sure which idea you are talking about dropping, the first argument binding behavior, or the spelling of getting shared instance attributes from a class (C.spam). Just asking to make sure, cuz I don't think the first needs to change, just the spelling. BTW, you sent me some comments on the Components and Interfaces chapter of the Zope Developer's Guide where you noted that attributes of interface objects are not the attributes described by the interface and that this is "unfamiliar to the typical python programmer", ie: interface Hello: def hello(name): """ say hello to a name """ does not create a 'Hello.hello'. Instead, you need to say "Hello.getDescriptionFor('hello')". If we chose the more familiar 'Hello.hello' then the interface interface would be seriously limited, and any added functionality would need to be imported from an external module or be a builtin like isinstance(). Interfaces, like classes, wouldn't be able to have their own methods. -Michel

On Fri, 20 Apr 2001 11:26:01 -0500, Guido van Rossum <guido@digicool.com> wrote:
class A: def __init__(self): self.spam = 1 class B: def __init__(self): A.__init__(self) self.eggs = 2 -- "I'll be ex-DPL soon anyway so I'm |LUKE: Is Perl better than Python? looking for someplace else to grab power."|YODA: No...no... no. Quicker, -- Wichert Akkerman (on debian-private)| easier, more seductive. For public key, finger moshez@debian.org |http://www.{python,debian,gnu}.org

Guido:
The problem doesn't arise in Smalltalk, because method calls and instance variable accesses are completely different things and are handled by quite separate syntaxes and mechanisms. Python creates problems for itself here by confusing instance variables of the class with metadata about the instance's methods, and keeping them both in the same namespace. Thomas Heller <thomas.heller@ion-tof.com>:
No, to call a class method in Smalltalk, you just send a message to the class itself rather than an instance. There's no difference in the message sending syntax.
Yes. You don't normally get a choice about what the metaclass is, although no doubt you could reach under the covers and manually construct your own metaclass and instantiate it if you wanted. Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg@cosc.canterbury.ac.nz +--------------------------------------+

"TH" == Thomas Heller <thomas.heller@ion-tof.com> writes:
TH> There are some signs :-) that Python's object model is going to TH> be revised even _before_ Python 3000. TH> Is someone willing to join me fighting for class methods (I mean TH> 'real' class-methods in the Smalltalk style here, _not_ static TH> methods like in Java or C++). The idea sounds good in the abstract. Class are objects and objects ought to have methods that implement their behavior. How does that very vague idea turn into something real? No clue. You start fighting and let's see where it goes :-). Jeremy

Jeremy Hylton wrote:
Here's something to start the fight ;-) ... 1) What would you do with class methods that you cannot do with e.g. globals and functions ? 2) How would you determine which methods are class-only methods and which are one usable by instances ? 3) If you don't like globals (see 1), wouldn't it be possible to store the state you want to manipulate using class methods in some other context object ? My impression is that class methods are not really needed and would only make optimizing Python harder... but that's maybe just me ;-) -- Marc-Andre Lemburg ______________________________________________________________________ Company & Consulting: http://www.egenix.com/ Python Pages: http://www.lemburg.com/python/

I will write up a concrete example I have and post it later. Look into the motivation for the Prototype Pattern in the GOF book, or even better in the discussion of this pattern in the 'Design Pattern Smalltalk Companion' book. This pattern is not needed if classes are 'first class' objects.
2) How would you determine which methods are class-only methods and which are one usable by instances ?
This is one of the issues which has to be resolved. I have no proposal at the moment. (Maybe function attributes can help here?)
I want the class methods (for example) to create and manipulate this 'context object'. This object, however, belongs into the class... What I want to avoid is class X(...): .... initialize(X)
Unfortunately not, I fear. Thomas

I imagine many of us (including yours truly :-) don't recall that in enough detail and/or don't have the book handy to look it up, so would you please do us a favor and explain this in a bit more detail?
This pattern is not needed if classes are 'first class' objects.
Depending on what you mean by the 'first class' phrase (which means something different to everyone), Python classes are already as first class as they get. E.g. they are tangible objects and you can pass them around and store them in variables.
What would initialize(X) do that you can't write in the class body? --Guido van Rossum (home page: http://www.python.org/~guido/)

This is a valid request, but please wait for my larger example. I'm referring to this because I have not been good at explaining the things I want... All in all: I'm not really ready to start the fight _now_, I was just looking for some help... Thomas PS: I find it strange that everyone so far seems to be against it.

[Thomas Heller]
... PS: I find it strange that everyone so far seems to be against it.
I didn't get that sense yet. I did get the sense they're not actively *for* it yet, and the questions asked so far explain why: What does it buy us? What are the current alternatives? What are the costs (not least of all in terms of breaking existing code)? It's a bunch of tradeoffs, and it appears that few who aren't steeped in Smalltalk's view of the world understand what the practical *attraction* is. The same questions get asked even for wholly non-controversial changes, like, say, adding an optional ">> file" clause to "print" <wink>. by-default-it's-best-to-resist-everything-ly y'rs - tim

On Fri, 20 Apr 2001, Thomas Heller wrote:
There are a number of reasons why I'm all for Class attributes in general. For example, right now a class object cannot assert an interface. Sure, a class can say: class Foo: __implements__ = Bar # instances implement Bar but that is an assertion for the instances, not the *class itself*. Currently, you have to do the ugly hack: class Foo: __class_implements__ = FooFactory # the class implements # FooFactory. We've done things like the above in several places in our underground component elaboration. Not having class methods introduces many little wrinkles in the Python object model that have to be worked around. I can imagine, for example, wanting to define an __reduce__, or __init__ for a class object, which is not possible now.
I always thought along the lines of saying Class.instanceAttribute('foo') in the place of what is now said Class.foo. This would, of course, break code, but the warning and back to the future features mitigate most of that risk.
Yes! We use this monstrosity a lot in Zope. -Michel

On Fri, Apr 20, 2001 at 05:40:21PM +0200, Thomas Heller wrote: | I want the class methods (for example) to create and manipulate | this 'context object'. This object, however, belongs into the class... | | What I want to avoid is | | class X(...): | .... | initialize(X) Here is a different approach to consider : class X : def __class_init__( class_X ) : initialize( class_X ) The idea here is to provide a "magic" method in the class that the interpreter calls as soon as the class object exists. The first (only) argument is the class object, which can be named as desired (analogous to 'self'). The main problem here is clients aren't prevented from calling this method, and they really shouldn't. -D

Well, the official policy on this is now that Py3K is just a slogan, and that all the real work will be introduced gradually. :-)
I will fight class methods to the death. :-) Seriously, I think you'll find an ally in Jim Fulton, who basically told me (since he's sort of my boss :-) to get on with this work. I think it can work as follows: Let x be an object, C its class, and M C's class. So, x.__class__ is C C.__class__ is M Then x's methods are described in C.__dict__, and C's methods are described in M.__dict__. The problem is that if you write C.spam, there could be two spams: one in C.__dict__, one in M.__dict__. Which one to use? How does Smalltalk resolve this? The problem is that for backwards compatibility, at lease, C.spam must be the unbound version of x.spam, because currently x.spam(...) can always also be written as C.spam(x, ...). For regular methods it may be possible to avoid this simply by choosing non-conflicting names, but I seem to recall that Jim wanted to use class methods with certain special names (like __init__ or __getattr__?), and I have no idea how to do this without dropping the idea that x.spam(...) is C.spam(x, ...). So maybe that's the solution? --Guido van Rossum (home page: http://www.python.org/~guido/)

Seriously, I think you'll find an ally in Jim Fulton,
So there _is_ some hope.
who basically told me (since he's sort of my boss :-) to get on with this work.
This must be the reason that ExtensionClass provides them: You can implement them in C, and override them in python subclasses. Thomas

"GvR" == Guido van Rossum <guido@digicool.com> writes:
GvR> Let x be an object, C its class, and M C's class. So, | x.__class__ is C | C.__class__ is M GvR> Then x's methods are described in C.__dict__, and C's methods GvR> are described in M.__dict__. GvR> The problem is that if you write C.spam, there could be two GvR> spams: one in C.__dict__, one in M.__dict__. Which one to GvR> use? If you use naming to generally distinguish, and have a lookup chain that first found it in C.__dict__ and then looked in M.__dict__, you could control what happens when the name is in both dicts by using a more explicit lookup, e.g. C.__dict__['meth'] vs. C.__class__.__dict__['meth'] But maybe that's too ugly. GvR> How does Smalltalk resolve this? I don't remember, but I do remember that ObjC had the same concepts, and it used a distinguishing marker on the method definition to say whether the method was a class method (`+') or instance method (`-'), e.g. + void some_class_method ... - void an_instance_method Another question: presumably when I write class Foo: pass Foo is implicitly given the built-in metaclass M, but say I wanted to define a class Foo with a different metaclass, how would I spell this? I think at one point I suggested a semi-ugly syntactic hack, where `class' was actually a namespace and you could add new metaclasses to it. So you could write something like class.WeirdClass Foo: pass and now Foo's metaclass would be WeirdClass. waiting-for-the-bottom-turtle-to-burp-ly y'rs, -Barry

[Barry wrote]
Couldn't be C.__class__.meth be used?
self class method; or self method; that creating a class Point in Smalltalk _automatically_ creates two classes: Point and PointClass. The latter is normally hidden (but contains the class methods of Point as instance methods). Thomas

"Thomas Heller" <thomas.heller@ion-tof.com> wrote,
In my 'objectmodule' I adopted a concept which I refer to as the "unbound instance". That is, I invented an object which is used as a proxy for accessing instance attributes. It looks like an instance but only for the purposes of attribute access. Now, since this object will only return "unbound method objects" when accessing a method (as opposed to the "bound method object" you would get when accessing a method from a real instance) I thought the name was at least slightly appropriate. In short, each class defined by the objectmodule has a special attribute '_' which is the "unbound instance" for that class. This unbound instance is used to resolve the name ambiguity. Now, consider this: import object class foo(object.base): def frob(self): print "I've been frobbed", self class __class__: def frob(cl): print "No, I've been frobbed", cl >>> f = foo() >>> x = f.frob >>> # x is the instance frob method bound to f >>> y = foo.frob >>> # y is the class frob method bound to foo >>> z = foo._.frob >>> # z is the instance frob method but is not bound to any instance >>> huh = foo.__class__._.frob >>> # huh is the class frob method but is not bound to any class >>>
That's the way I remember it too. And, (if I recall correctly) in SmallTalk (unlike CLOS), you have no control over the meta-class. In the example above, like in SmallTalk, the name of foo.__class__ is determined automatically. In this case it is 'foo_class'. However, unlike SmallTalk, the above example could be extended to include a 'class __class__:' definition under the existing 'class __class__:'. The name generated by this construct would, of course, be 'foo_class_class'. Lather, Rinse, repeat... -- Donald Beaudry Ab Initio Software Corp. 201 Spring Street donb@init.com Lexington, MA 02421 ...Will hack for sushi...

On Fri, 20 Apr 2001, Guido van Rossum wrote:
I think, at the expense of breaking code, M.
This is the part that choosing M would break. To get at C's shared instance attributes you could say something like C.instanceAttribute('spam')(x, ...). Yes, it's ugly. Perhaps someone can think of a more elegant spelling?
I'm not sure which idea you are talking about dropping, the first argument binding behavior, or the spelling of getting shared instance attributes from a class (C.spam). Just asking to make sure, cuz I don't think the first needs to change, just the spelling. BTW, you sent me some comments on the Components and Interfaces chapter of the Zope Developer's Guide where you noted that attributes of interface objects are not the attributes described by the interface and that this is "unfamiliar to the typical python programmer", ie: interface Hello: def hello(name): """ say hello to a name """ does not create a 'Hello.hello'. Instead, you need to say "Hello.getDescriptionFor('hello')". If we chose the more familiar 'Hello.hello' then the interface interface would be seriously limited, and any added functionality would need to be imported from an external module or be a builtin like isinstance(). Interfaces, like classes, wouldn't be able to have their own methods. -Michel

On Fri, 20 Apr 2001 11:26:01 -0500, Guido van Rossum <guido@digicool.com> wrote:
class A: def __init__(self): self.spam = 1 class B: def __init__(self): A.__init__(self) self.eggs = 2 -- "I'll be ex-DPL soon anyway so I'm |LUKE: Is Perl better than Python? looking for someplace else to grab power."|YODA: No...no... no. Quicker, -- Wichert Akkerman (on debian-private)| easier, more seductive. For public key, finger moshez@debian.org |http://www.{python,debian,gnu}.org

Guido:
The problem doesn't arise in Smalltalk, because method calls and instance variable accesses are completely different things and are handled by quite separate syntaxes and mechanisms. Python creates problems for itself here by confusing instance variables of the class with metadata about the instance's methods, and keeping them both in the same namespace. Thomas Heller <thomas.heller@ion-tof.com>:
No, to call a class method in Smalltalk, you just send a message to the class itself rather than an instance. There's no difference in the message sending syntax.
Yes. You don't normally get a choice about what the metaclass is, although no doubt you could reach under the covers and manually construct your own metaclass and instantiate it if you wanted. Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg@cosc.canterbury.ac.nz +--------------------------------------+
participants (12)
-
barry@digicool.com
-
D-Man
-
Donald Beaudry
-
Fred L. Drake, Jr.
-
Greg Ewing
-
Guido van Rossum
-
Jeremy Hylton
-
M.-A. Lemburg
-
Michel Pelletier
-
Moshe Zadka
-
Thomas Heller
-
Tim Peters