Unification of Methods and Functions

David MacQuigg dmq at gain.com
Sat May 1 19:14:02 EDT 2004


On Fri, 30 Apr 2004 13:59:44 -0400, Jack Diederich
<jack at performancedrivers.com> 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/Python/PrototypeSyntax.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:
:x:x**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




More information about the Python-list mailing list