Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Unification of Methods and Functions

Reply
Thread Tools

Unification of Methods and Functions

 
 
David MacQuigg
Guest
Posts: n/a
 
      04-30-2004
I'm not getting any feedback on the most important benefit in my
proposed "Ideas for Python 3" thread - the unification of methods and
functions. Perhaps it was buried among too many other less important
changes, so in this thread I would like to focus on that issue alone.

I have edited the Proposed Syntax example below to take out the
changes unecessary to this discussion. I left in the change of
"instance variable" syntax ( self.sound --> .sound ) because that is
necessary for the unification of all method forms. ( Compare the
forms of the 'show' and 'talk' methods below.)

I believe these changes in syntax will make teaching OOP in Python
much easier. See "Prototypes.doc" at
http://ece.arizona.edu/~edatools/Python/ The first eight pages are a
basic, but complete presentation of the new OOP syntax. I expect this
to expand to about 30 pages with more examples and exercises. This
compares to about 60 pages in Learning Python 2nd ed.

If we measure complexity by the number of pages needed for a "textbook
explanation" of OOP, then I believe the new syntax has some real
benefits. At this point in the learning process, students already know
functions, modules, and global variables. The concept of using a
global variable __self__ is no surprise at all. The only thing new in
a class, compared to a module, is the instance variables, and they can
be explained in one paragraph. All methods look just like normal
functions. There is no need to explain "static methods" or any other
form of method. In fact, I use the term "function" rather than
"method" to emphasize the similarity.

I'm especially interested in feedback from users who are now learning
or have recently learned Python. I already know these changes seem
trivial to many experts. I've also heard plenty from the people who
think Python is so complex that we need to start a whole new language
( www.prothon.org ). I'm looking for a middle ground. I believe it
is possible to adopt what is good about Prothon, and not lose ten
years of software and community development.

======= Syntax Examples =============

## Proposed Syntax:
class Cat(Feline):
numCats = 0
def __init__( n = "unknown", s = "Meow" ):
Feline.__init__()
Cat.numCats += 1
.name = n # Set instance variables.
.sound = s
def show(): # Define a "static method".
Feline.show()
print " Cats:", Cat.numCats
def talk():
print "My name is ...", .name
print "I am a %s from %s" % (.genus, .home)
Mammal.talk() # Call an unbound function.
print __self__ ### Diagnostic check.

cat1 = Cat() # Create instance.
bf = cat1.talk # Make a bound function.


## Equivalent Python:
class Cat(Feline):
numCats = 0
def __init__(self, n = "unknown", s = "Meow" ):
Feline.__init__(self)
Cat.numCats += 1
self.name = n
self.sound = s
def show():
Feline.show()
print " Cats:", Cat.numCats
show = staticmethod(show)
def talk(self):
print "My name is ...", self.name
print "I am a %s from %s" % (self.genus, self.home)
Mammal.talk(self)
print self

cat1 = Cat() # Create instance.
bf = cat1.talk # Make a bound function.

========= End of Examples =======

Thanks for your help.

-- Dave

 
Reply With Quote
 
 
 
 
Nicolas Fleury
Guest
Posts: n/a
 
      04-30-2004
David MacQuigg wrote:
> I'm especially interested in feedback from users who are now learning
> or have recently learned Python. I already know these changes seem
> trivial to many experts. I've also heard plenty from the people who
> think Python is so complex that we need to start a whole new language
> ( www.prothon.org ). I'm looking for a middle ground. I believe it
> is possible to adopt what is good about Prothon, and not lose ten
> years of software and community development.


I don't think Python is too complex and to me your suggestion adds more
complexity rather than simplying. Your proposal is also not
backward-compatible at all, so I don't see it can ever be accepted. I
agree that avoiding self make code lighter, but I don't think it unify
things or simplify them. It adds a magic and hidden parameter. The
good thing about the current syntax is that it shows what is really
happening. Actually, I find the statu quo more unified.

I would prefer self to be a keyword and be used to determine if the
function is static, but I guess we have to live with things like that.
I have given some python courses and the self parameter seems to be
clear for everybody. I think it even helps comprehension.

Regards,

Nicolas
 
Reply With Quote
 
 
 
 
Michael Walter
Guest
Posts: n/a
 
      04-30-2004
David MacQuigg wrote:
> [...]

Pardon my ignorance, but I'm not quite sure how this unificates methods
and functions at all.

In my eyes, unification would remove method definitions from the "class"
scope or make it simply syntactic sugar for:

def my_method(SomeClass self):
...

(instead of:
class SomeClass:
def my_method(self):
...)

This would also add the possibility to provide multiple dispatch by
simply allowing a "type hint" for every parameter at every position.

Cheers,
Michael
 
Reply With Quote
 
Jack Diederich
Guest
Posts: n/a
 
      04-30-2004
On Fri, Apr 30, 2004 at 09:47:05AM -0700, David MacQuigg wrote:
> I'm not getting any feedback on the most important benefit in my
> proposed "Ideas for Python 3" thread - the unification of methods and
> functions. Perhaps it was buried among too many other less important
> changes, so in this thread I would like to focus on that issue alone.
> ======= Syntax Examples =============
>
> ## Proposed Syntax:
> class Cat(Feline):
> numCats = 0
> def __init__( n = "unknown", s = "Meow" ):
> Feline.__init__()
> Cat.numCats += 1
> .name = n # Set instance variables.
> .sound = s
> def show(): # Define a "static method".
> Feline.show()
> print " Cats:", Cat.numCats
> def talk():
> print "My name is ...", .name
> print "I am a %s from %s" % (.genus, .home)
> Mammal.talk() # Call an unbound function.
> print __self__ ### Diagnostic check.
>
> cat1 = Cat() # Create instance.
> bf = cat1.talk # Make a bound function.
>
>
> ## Equivalent Python:
> class Cat(Feline):
> numCats = 0
> def __init__(self, n = "unknown", s = "Meow" ):
> Feline.__init__(self)
> Cat.numCats += 1
> self.name = n
> self.sound = s
> def show():
> Feline.show()
> print " Cats:", Cat.numCats
> show = staticmethod(show)
> def talk(self):
> print "My name is ...", self.name
> print "I am a %s from %s" % (self.genus, self.home)
> Mammal.talk(self)
> print self
>
> cat1 = Cat() # Create instance.
> bf = cat1.talk # Make a bound function.
>
> ========= End of Examples =======
>


Explicit is better than implicit.
or
Magic BAAAAAAAAD [Phil Hartman as Frankenstein]

I suggest you check out perl to see mixing instance/class/static methods
in practice. Becuase perl is weakly typed this 'makes sense' in perl, even if
it causes problems[1]. What happens in practice is bad, people write functions
that can be used in two or more ways. This makes type checking hard, and
makes code unreadable. Functions frequently do slightly different things when
called one way or another.

For a python version you could do type checking on the function by doing
static analysis of the code, but that would be unpythonic. I like it when
a static function breaks badly when some yahoo tries to use self -- it breaks
early and loudly. Your way might only break on a certain code path that
tries to access '.name' and turns the method from static to instance.
If you re-added staticmethod/classmethod to clear up the distinction then
the above example just becomes a new syntax for implicit 'self'.

A version of the ':vars: expression' lambda replacement gets suggested every
so often (and that exact syntax once by me). It ain't going to happnen, labmda
is more likely to be dropped than enhanced.

-jackdied

[1] standard perl interview question, what is the difference between these
calls? All of these end up calling meow() with one argument, but they all
behave differently - sometimes very subtly.

$ob = new Cat;
$ob->meow(); # intsance method
Cat->meow(); # class method
Cat::meow($ob); # static method with first argument a Cat instance

 
Reply With Quote
 
David MacQuigg
Guest
Posts: n/a
 
      05-01-2004
On Fri, 30 Apr 2004 13:59:44 -0400, Jack Diederich
<(E-Mail Removed)> wrote:

>On Fri, Apr 30, 2004 at 09:47:05AM -0700, David MacQuigg wrote:
>> I'm not getting any feedback on the most important benefit in my
>> proposed "Ideas for Python 3" thread - the unification of methods and
>> functions. Perhaps it was buried among too many other less important
>> changes, so in this thread I would like to focus on that issue alone.
>> ======= Syntax Examples =============
>>
>> ## Proposed Syntax:
>> class Cat(Feline):
>> numCats = 0
>> def __init__( n = "unknown", s = "Meow" ):
>> Feline.__init__()
>> Cat.numCats += 1
>> .name = n # Set instance variables.
>> .sound = s
>> def show(): # Define a "static method".
>> Feline.show()
>> print " Cats:", Cat.numCats
>> def talk():
>> print "My name is ...", .name
>> print "I am a %s from %s" % (.genus, .home)
>> Mammal.talk() # Call an unbound function.
>> print __self__ ### Diagnostic check.
>>
>> cat1 = Cat() # Create instance.
>> bf = cat1.talk # Make a bound function.
>>
>>
>> ## Equivalent Python:
>> class Cat(Feline):
>> numCats = 0
>> def __init__(self, n = "unknown", s = "Meow" ):
>> Feline.__init__(self)
>> Cat.numCats += 1
>> self.name = n
>> self.sound = s
>> def show():
>> Feline.show()
>> print " Cats:", Cat.numCats
>> show = staticmethod(show)
>> def talk(self):
>> print "My name is ...", self.name
>> print "I am a %s from %s" % (self.genus, self.home)
>> Mammal.talk(self)
>> print self
>>
>> cat1 = Cat() # Create instance.
>> bf = cat1.talk # Make a bound function.
>>
>> ========= End of Examples =======
>>

>
>Explicit is better than implicit.
>or
>Magic BAAAAAAAAD [Phil Hartman as Frankenstein]


I agree that magic is bad, but I disagree that the magically inserted
first argument on *some* function calls is less than the magic of
setting the current instance to a global variable __self__. Students
at this point already understand global variables. Yet they
frequently stumble on the different calling sequences for bound and
unbound functions. ( cat1.talk() vs Cat.talk(cat1) )

Using a global __self__ puts the current instance in a much more
convenient place, always available, but never in your way. This
"out-of-your-way" aspect of the proposed __self__ is the key to
getting a consistent calling sequence for all functions and methods.
If you want to call a method, but you don't have a current instance,
no problem. Just call it like any other function. We don't need
special syntax for a "static method".

It is hard to judge the complexity of a proposed syntax by looking
with a microscope at something as small as setting a global variable.
The way I would make the comparison is by looking at the length of a
"textbook" explanation of instance variables. I believe the proposed
syntax will take about half the number of lines to write a good
explanation. See the examples at the end of
http://ece.arizona.edu/~edatools/Pyt...typeSyntax.htm

There is a discussion of this question under the subject "Explanation
of Instance Variables in Python". Greg Ewing wrote a shorter
explanation than the one I prefer or the one that is in the Python
tutorial. I would like to get some more opinions, especially from
users who remember their first encounter with instance variables in
Python.

>I suggest you check out perl to see mixing instance/class/static methods
>in practice. Becuase perl is weakly typed this 'makes sense' in perl, even if
>it causes problems[1]. What happens in practice is bad, people write functions
>that can be used in two or more ways. This makes type checking hard, and
>makes code unreadable. Functions frequently do slightly different things when
>called one way or another.


You seem to be saying that there is a lot of confusion in Perl due to
mixing instance/class/static methods. I'm not familiar with Perl, but
this doesn't surprise me. It seems to *support* my proposal that we
do away with these variations in method calls. They serve no purpose
other than patching holes in the syntax which arose only because we
have this special first argument in *some* cases.

>For a python version you could do type checking on the function by doing
>static analysis of the code, but that would be unpythonic. I like it when
>a static function breaks badly when some yahoo tries to use self -- it breaks
>early and loudly. Your way might only break on a certain code path that
>tries to access '.name' and turns the method from static to instance.
>If you re-added staticmethod/classmethod to clear up the distinction then
>the above example just becomes a new syntax for implicit 'self'.


I'm not following this. In the proposed syntax, there is no
distinction between static and class or instance methods. All methods
are called the same way. If you call a method that has instance
variables, it will look for __self__ to resolve those variables. If
__self__ is set to None, or to some inappropriate type, you will get
the same error message you get now from Python:
TypeError: unbound method talk() must be called with Cat instance as
__self__ (got Mammal instance instead)

>A version of the ':vars: expression' lambda replacement gets suggested every
>so often (and that exact syntax once by me). It ain't going to happnen, labmda
>is more likely to be dropped than enhanced.


I think there is some value in having an anonymous function syntax,
not enough to justify a keyword, but certainly enough if it can be
done with a standard function definition, just leaving off the name.
Here is my latest favorite function definition syntax:

f(x):
return x**2

Lambda form:
**2

The lambda form is close enough to the standard form that it is
self-explanatory. So we can drop three more pages from the standard
introductory text.

>
>-jackdied
>
>[1] standard perl interview question, what is the difference between these
>calls? All of these end up calling meow() with one argument, but they all
>behave differently - sometimes very subtly.
>
>$ob = new Cat;
>$ob->meow(); # intsance method
>Cat->meow(); # class method
>Cat::meow($ob); # static method with first argument a Cat instance


The equivalent question in Python is -- explain the difference in
these uses of the talk method:

cat1.talk()
Mammal.talk(cat1)
bound_func = cat1.talk
unbound_func = Mammal.talk

This is a clear violation of the "explicit" rule. Yet it is one that
is justified, and one that I decided to keep in the prposed syntax.
The alternative is a special syntax to provide explicit binding in all
situations. After weeks of debate on the Prothon list, we were not
able to come up with anything better than Python's syntax.

So I have decided to accept the simple implicit rule -- you get a
bound function from an instance and the equivalent unbound function
from its parent class. Practicality beats purity.

-- Dave

 
Reply With Quote
 
Greg Ewing
Guest
Posts: n/a
 
      05-03-2004
David MacQuigg wrote:
> The concept of using a
> global variable __self__ is no surprise at all.


Except that __self__ can't be a global variable.
Implementing it that way would be a disaster.

--
Greg Ewing, Computer Science Dept,
University of Canterbury,
Christchurch, New Zealand
http://www.cosc.canterbury.ac.nz/~greg

 
Reply With Quote
 
David MacQuigg
Guest
Posts: n/a
 
      05-03-2004
On Mon, 03 May 2004 13:11:17 +1200, Greg Ewing
<(E-Mail Removed)> wrote:

>David MacQuigg wrote:
>> The concept of using a
>> global variable __self__ is no surprise at all.

>
>Except that __self__ can't be a global variable.
>Implementing it that way would be a disaster.


It seems to work in Michele Simionato's 'prototype' module.
{ comp.lang.python, 4/28/04, "Prototypes in Python"} It is global
only to the called function, but the key requirement is met -- no
alteration of the standard function calling sequence.

Why can't it be a true global?

-- Dave
 
Reply With Quote
 
Greg Chapman
Guest
Posts: n/a
 
      05-04-2004
On Mon, 03 May 2004 11:44:06 -0700, David MacQuigg <(E-Mail Removed)> wrote:

>It seems to work in Michele Simionato's 'prototype' module.
>{ comp.lang.python, 4/28/04, "Prototypes in Python"} It is global
>only to the called function, but the key requirement is met -- no
>alteration of the standard function calling sequence.
>
>Why can't it be a true global?


If I understand correctly, one drawback of his approach is that methods cannot
rebind globals. A STORE_GLOBAL opcode will store its value into the globs
dictionary created when the method was fetched; this dictionary is not the same
as the module's dictionary, so the changed global will only be visible within
that method (and within that method call: the next time the method is fetched, a
new globs will be created).

---
Greg Chapman

 
Reply With Quote
 
Michele Simionato
Guest
Posts: n/a
 
      05-05-2004
Greg Chapman <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>. ..
> On Mon, 03 May 2004 11:44:06 -0700, David MacQuigg <(E-Mail Removed)> wrote:
>
> >It seems to work in Michele Simionato's 'prototype' module.
> >{ comp.lang.python, 4/28/04, "Prototypes in Python"} It is global
> >only to the called function, but the key requirement is met -- no
> >alteration of the standard function calling sequence.
> >
> >Why can't it be a true global?

>
> If I understand correctly, one drawback of his approach is that methods cannot
> rebind globals. A STORE_GLOBAL opcode will store its value into the globs
> dictionary created when the method was fetched; this dictionary is not the same
> as the module's dictionary, so the changed global will only be visible within
> that method (and within that method call: the next time the method is fetched, a
> new globs will be created).
>
> ---
> Greg Chapman


I believe you are right (haven't checked yet) but I guess I can always
change the globals from inside the method with something like

currentmodule=sys.modules["__name__"]
currentmodule.myglobal="something"

Not that changing globals from a method is good style.

BTW, I do agree that my hack is an evil hack, the interesting thing
about it (for me) was the fact that inside the method I could use
"super.method(*args)" instead of the ugly
"super(cls,self).method(*args)" syntax. I didn't think that was
possible at all.

I just wonder if it would be technically possible to implement
something
like that in C with a decent performance (maybe caching the method
access).
What do you think?

Michele Simionato
 
Reply With Quote
 
David MacQuigg
Guest
Posts: n/a
 
      05-05-2004
On 4 May 2004 21:19:23 -0700, http://www.velocityreviews.com/forums/(E-Mail Removed) (Michele
Simionato) wrote:

>Greg Chapman <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>. ..
>> On Mon, 03 May 2004 11:44:06 -0700, David MacQuigg <(E-Mail Removed)> wrote:
>>
>> >It seems to work in Michele Simionato's 'prototype' module.
>> >{ comp.lang.python, 4/28/04, "Prototypes in Python"} It is global
>> >only to the called function, but the key requirement is met -- no
>> >alteration of the standard function calling sequence.
>> >
>> >Why can't it be a true global?

>>
>> If I understand correctly, one drawback of his approach is that methods cannot
>> rebind globals. A STORE_GLOBAL opcode will store its value into the globs
>> dictionary created when the method was fetched; this dictionary is not the same
>> as the module's dictionary, so the changed global will only be visible within
>> that method (and within that method call: the next time the method is fetched, a
>> new globs will be created).
>>
>> ---
>> Greg Chapman

>
>I believe you are right (haven't checked yet) but I guess I can always
>change the globals from inside the method with something like
>
>currentmodule=sys.modules["__name__"]
>currentmodule.myglobal="something"
>
>Not that changing globals from a method is good style.


The one limitation I see in the prototype module is that I can't save
an unbound function and later call it with my choice of bind object.
A global __self__ might help in this situation. e.g.

## This works:
bf = cat2.talk # Save a bound function.
def func(bf): # Pass it to another scope.
bf()
func(bf) # Call it.

## This does not:
uf = Cat.talk # Save an unbound function.
uf() #=>
# AttributeError: type object 'Cat' has no attribute 'name'

I would like to be able to do something like:
__self__ = cat2
uf()

Maybe there is some other trick to get this to work. It doesn't have
to be pretty. This is a seldom-needed call, mostly for debugging.

>BTW, I do agree that my hack is an evil hack, the interesting thing
>about it (for me) was the fact that inside the method I could use
>"super.method(*args)" instead of the ugly
>"super(cls,self).method(*args)" syntax. I didn't think that was
>possible at all.


I don't care how evil the underlying machinery is. It works nicely at
the user level. This is something the prototype advocates have
missed. They see metaclasses or descriptors and they freak. If the
module had been written in C, they would not be complaining.

super.func() is cool. I would not bother my students with
super(cls,self).func(), but the way super is used, it looks simple,
and it is simple. I can have a hierarchy of classes, each one calling
a function from its parent, and without modifying anything but the
class headers, insert a new class in the middle of the hierarchy.

## New class:
class Feline(Animal):
....
def show():
super.show()
print "Felines:", Feline.numFelines
....

>>> cat2.show()

Animals: 2
Felines: 2 <== Line added to previous output.
Cats: 2

My interest in this "prototype" module is not the ability to clone
prototypes, but the simplification and unification of all function and
method calling styles. If we leave out the cloning stuff, does it
make the implementation problems simpler?

-- Dave

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Unification of variables and methods Charles Lowe Ruby 0 02-17-2007 05:16 AM
Fun with decorators and unification dispatch talin at acm dot org Python 3 09-11-2005 09:32 PM
RE: Unification of Methods and Functions Delaney, Timothy C (Timothy) Python 6 05-12-2004 05:00 PM
Re: Unification of logging in Python's Standard Library Skip Montanaro Python 2 08-19-2003 07:38 PM
Identity inconsistency and unification of types and classes Rim Python 3 07-14-2003 11:41 AM



Advertisments