Another Language Change for Debate

335 views
Skip to first unread message

Michael Chermside

unread,
Jan 11, 2002, 1:21:34 PM1/11/02
to
Okay, for some reason this newsgroup tends to get WAY more suggestions
for language changes than that for any other language that I know. I
suppose that there are a couple of reasons for this. One is cultural,
another is that Python definitely IS being improved and extended
(witness brilliant advances like iterators, generators, and the
beginnings of a fix for the type-class chasm). My conceit is that
another reason is that Python is so VERY nice already that it's the
language to which most people want to add their own pet idea. But I
suspect that the NUMBER ONE reason is that the people who read and write
on c.l.p are, on the whole, VERY GOOD at language design.

So I'll throw out an idea of my own for discussion. This is NOT a PEP...
and therefore NOT a serious proposal for a change in Python. I just want
to hear what other people think about it and compare your sense of
language design with my own.

One of the things that still throws me in Python is writing things like
this:

class MyClass(OtherClass):
def addItems( newItems ):
self.items += newItems

Of course what I've forgotten to do here is to declare 'self' as the
first parameter to addItems(). The reason I forgot is that when I CALL
the method it looks like this:
myObj.addItems( userItems )
so when I'm writing it I'm thinking of it as a function of one parameter.

Proposals for leaving off 'self' have been made many times, but that's a
bad idea... the fact that every variable reference is (1) local, (2)
nested scoped, or (3) global and can be found by a simple textual search
through the source code is a VERY ELEGANT thing about Python. But
writing the method one place with 2 arguments and another place with
just 1 is not elegant.

So here's my idea. Allow the following syntax:

class MyClass(OtherClass):
def self.addItems( newItems ):
self.items += newItems

So in method declarations where we normally permit only an identifier
for the method-name, we now allow also identifier '.' identifier. The
identifier before the dot simply becomes the first parameter of the
method. I don't think it would be good style to use this for non-methods
(ie, normal functions not belonging to a class), but I suppose there's
no reason to prohibit the syntax. There's no way to set default values
for this parameter, but you don't do that with 'self' anyhow, right?

As far as I can tell, there'd be no syntactic ambiguity (please correct
me if I've missed something). And it would make the DECLARATION of a
method look a whole lot more like the USE of the method, without
removing the elegance of declaring 'self' like any other variable.

So... what do you folks think?

-- Michael Chermside


bru...@tbye.com

unread,
Jan 11, 2002, 3:05:28 PM1/11/02
to
On Fri, 11 Jan 2002, Michael Chermside wrote:

> class MyClass(OtherClass):
> def addItems( newItems ):
> self.items += newItems
>
> Of course what I've forgotten to do here is to declare 'self' as the
> first parameter to addItems(). The reason I forgot is that when I CALL
> the method it looks like this:
> myObj.addItems( userItems )

[snip]


> So here's my idea. Allow the following syntax:
>
> class MyClass(OtherClass):
> def self.addItems( newItems ):
> self.items += newItems

[snip]

I sometimes make this mistake, but it gets caught the very first time the
function is run, so it causes no real pain. If it happens a lot, use your
editor's macro capabilities to generate skeleton method code for you.

-Dave


IB

unread,
Jan 11, 2002, 4:54:52 PM1/11/02
to
Hello, Michael:

My 2 cents are that we have to ask one more question - what other
benefits would there be if such syntax would be allowed?

I would agree that it would be a neat thing, but after few minutes of
thinking on the subject I could not come up with anything extra...

So I believe that just one small benefit is not worth the hassle of
changing syntax. To my experience,language design always balances in
between innovation and conservative stability. It seems that
conservative approach would probably win here...

--Igor


Michael Chermside <mch...@destiny.com> wrote in message news:<mailman.1010773286...@python.org>...

Matt

unread,
Jan 11, 2002, 6:04:42 PM1/11/02
to
In article <f3baf765.02011...@posting.google.com>, IB wrote:
> Hello, Michael:
>
> My 2 cents are that we have to ask one more question - what other
> benefits would there be if such syntax would be allowed?
>
> I would agree that it would be a neat thing, but after few minutes of
> thinking on the subject I could not come up with anything extra...

Actually, I thought up one neat thing after reading it...

> Michael Chermside <mch...@destiny.com> wrote in message news:<mailman.1010773286...@python.org>...

>> So here's my idea. Allow the following syntax:
>>
>> class MyClass(OtherClass):
>> def self.addItems( newItems ):
>> self.items += newItems

After using some staticmethod() (in python2.2), it popped out at
me how support for staticmethod/classmethod could be added without
new keywords:

class MyClass:
def self.foo(x):
#instance method
def bar(y):
#staticmethod
def class.baz(z):
#classmethod

(Of course, since this would break ALL old code, adding new
keywords would be probably be a better idea. ;)

--
Matthew Mueller
Noone likes spam in their email.

Alex Martelli

unread,
Jan 11, 2002, 6:05:53 PM1/11/02
to
IB wrote:

> Hello, Michael:
>
> My 2 cents are that we have to ask one more question - what other
> benefits would there be if such syntax would be allowed?

Playing devil's advocate:

class sic(object):
def sic.aclassmethod(): pass
def self.anormalmethod(): pass

Isn't this better than the current

class sic(object):
def aclassmethod(klass): pass
aclassmethod = classmethod(aclassmethod)
def anormalmethod(self): pass


Alex


Huaiyu Zhu

unread,
Jan 11, 2002, 8:17:58 PM1/11/02
to
On Fri, 11 Jan 2002 13:21:34 -0500, Michael Chermside <mch...@destiny.com>
wrote:
>
>So here's my idea. Allow the following syntax:
>
>class MyClass(OtherClass):
> def self.addItems( newItems ):
> self.items += newItems
[...]

>
>So... what do you folks think?

I like this a lot. It looks natural. In fact, I had on more than one
occassion typed this way without noticing it until a SyntaxError came up.
It reduces the amount of editing needed when doing copy-paste between usage
and implementation.

One minor problem is that the following might appear more cryptic (or maybe
not): TypeError: addItems() takes exactly 2 arguments (3 given).

Huaiyu

James_...@i2.com

unread,
Jan 11, 2002, 8:12:57 PM1/11/02
to

Alex Martelli wrote:
>Playing devil's advocate:
>
>class sic(object):
> def sic.aclassmethod(): pass
> def self.anormalmethod(): pass
>
>Isn't this better than the current
>
>class sic(object):
> def aclassmethod(klass): pass
> aclassmethod = classmethod(aclassmethod)
> def anormalmethod(self): pass

I can see some appeal. But since we need the 1st param in class methods it
probably should be (given that Guido seems to prefer "cls" for the
equivalent of "self" in class methods):

class sic(object):
def cls.aclassmethod(): pass
def self.anormalmethod(): pass

And since Python would then have to know about "cls" and "self", why not
add "static":

class sic(object):
def cls.aclassmethod(): pass
def self.anormalmethod(): pass
def static.astaticmethod(): pass

The meaning of "static.xxx():" is slightly different in that there is no
1st param named "static", but maybe that's not such a big concern.

In this scenario, if one wanted to use 1st param names other than "self"
and "cls", just revert to the current (more awkward mechanisms).

Jim


Dale Strickland-Clark

unread,
Jan 11, 2002, 9:10:50 PM1/11/02
to
I don't recall leaving 'self' off so it's really not an issue for me.


--
Dale Strickland-Clark
Riverhall Systems Ltd

Gareth McCaughan

unread,
Jan 11, 2002, 10:10:21 PM1/11/02
to
Matt Mueller wrote:
> After using some staticmethod() (in python2.2), it popped out at
> me how support for staticmethod/classmethod could be added without
> new keywords:
>
> class MyClass:
> def self.foo(x):
> #instance method
> def bar(y):
> #staticmethod
> def class.baz(z):
> #classmethod
>
> (Of course, since this would break ALL old code, adding new
> keywords would be probably be a better idea. ;)

I much prefer a different approach.

class MyClass:
def staticmethod bar(y):
blah()
stuff += stuff
def classmethod baz(z):
return 1

This generalizes in an obvious way:
def <name1> <name2>(<formals>): <body>
turns into
def <name2>(<formals>): <body>
<name2> = <name1>(<name2>)
which would make it possible, e.g., to define
a function called "memo" which memoizes its argument
and say (typical useless example follows):
def memo fib(n):
if n<2: return n
return fib(n-2)+fib(n-1)
and get only O(n) calls to "fib" on doing fib(n).

Perhaps there's an obvious reason why this doesn't
work, but I can't see what it might be right now.
Would it be difficult for the parser?

--
Gareth McCaughan Gareth.M...@pobox.com
.sig under construc

Tim Peters

unread,
Jan 11, 2002, 11:22:36 PM1/11/02
to
[Gareth McCaughan]

> I much prefer a different approach.
>
> class MyClass:
> def staticmethod bar(y):
> blah()
> stuff += stuff
> def classmethod baz(z):
> return 1
>
> This generalizes in an obvious way:
> def <name1> <name2>(<formals>): <body>
> turns into
> def <name2>(<formals>): <body>
> <name2> = <name1>(<name2>)
> which would make it possible, e.g., to define
> a function called "memo" which memoizes its argument
> and say (typical useless example follows):
> def memo fib(n):
> if n<2: return n
> return fib(n-2)+fib(n-1)
> and get only O(n) calls to "fib" on doing fib(n).
>
> Perhaps there's an obvious reason why this doesn't
> work, but I can't see what it might be right now.
> Would it be difficult for the parser?

It's more that a gazillion "toy parser" tools out there (from Emacs
python-mode to Python's own pyclbr.py) would have to be changed too, lest
they all end up thinking you have an unbounded number of methods named
"staticmethod" (etc). You won't take this seriously until a dozen legacy
tools you don't even remember you're using break <wink>.


Gareth McCaughan

unread,
Jan 12, 2002, 10:06:48 AM1/12/02
to
Tim Peters wrote:

[I suggested the following:]


> >
> > class MyClass:
> > def staticmethod bar(y):
> > blah()
> > stuff += stuff
> > def classmethod baz(z):
> > return 1
> >
> > This generalizes in an obvious way:
> > def <name1> <name2>(<formals>): <body>
> > turns into
> > def <name2>(<formals>): <body>
> > <name2> = <name1>(<name2>)

[etc]


>
> It's more that a gazillion "toy parser" tools out there (from Emacs
> python-mode to Python's own pyclbr.py) would have to be changed too, lest
> they all end up thinking you have an unbounded number of methods named
> "staticmethod" (etc). You won't take this seriously until a dozen legacy
> tools you don't even remember you're using break <wink>.

Ah yes. That would be a shame. So here's a variant.

class MyClass:
def bar(y) [staticmethod]:
do_some_stuff()
return 123

By the way, if you define generator(x) to be the same
as iter(x) then that lets you say

def f(x) [generator]:
while 1:
yield x
x=x+1

after which f *is* a generator, not a function that returns
a generator. I don't think this is worth doing :-).

The manic generalizer in me wants to add that if you have
several modifiers you want to apply to a function or method,
you can say

def f(x) [memoized,classmethod,ignoring_errors]:
<stuff>

but I'm not sure whether that's elegant or gratuitous
just yet. By the way, for anyone who's curious, here are
rough approximations to the first and last of those
modifiers:

def memoized(f):
d = {}
def _(*args):
try: return d[args]
except KeyError:
result = f(*args)
d[args] = result
return result
return _

def ignoring_errors(f):
def _(*args):
try: return f(*args)
except: return None
return _

Note that "ignoring_errors" may be a misleading name,
since an error will still terminate execution of the
underlying function.

Courageous

unread,
Jan 12, 2002, 12:44:49 PM1/12/02
to

>So here's my idea. Allow the following syntax:
>
>class MyClass(OtherClass):
> def self.addItems( newItems ):
> self.items += newItems

I wouldn't really change Python in this particular
way, but it does have a certain appeal to it. For example, it
could also be written...

...
def MyClass.addItems ( ...
...

...to define a static function.

Face it, though, one way or another all of these various
kinds of things are just different kinds of syntactic sugar.

*shrug*

C//

Joseph A Knapka

unread,
Jan 13, 2002, 12:39:50 AM1/13/02
to
Courageous wrote:

> Face it, though, one way or another all of these various
> kinds of things are just different kinds of syntactic sugar.

And what is a high-level language but syntactic sugar for
ones and zeros? <g>

Personally, I like the "One Obvious Way, or Maybe A Couple,
But Only If They're Orthogonal" philosophy embodied in Python.
If there's not a real /need/ to add an additional Way To
Do something, I can happily live with the existing way. The
"self" thing is totally obvious, occasionally irritating,
and just fine the way it is, IMO.

(Hmm... "Our chief means of constructing lists is the
append() method, and list comprehensions... Our TWO chief
means of constructing lists: append() and list comprehensions,
and list += list.... AMONG OUR METHODS of constructing
lists...")

and-an-almost-fanatical-devotion-to-the-bdf-ly y'rs,

Cheers,

-- Joe
"I should like to close this book by sticking out any part of my neck
which is not yet exposed, and making a few predictions about how the
problem of quantum gravity will in the end be solved."
--- Physicist Lee Smolin, "Three Roads to Quantum Gravity"

Courageous

unread,
Jan 13, 2002, 1:08:13 AM1/13/02
to

>Personally, I like the "One Obvious Way, or Maybe A Couple,
>But Only If They're Orthogonal" philosophy embodied in Python.

For me, this is the most compelling reason to use Python.

>If there's not a real /need/ to add an additional Way To
>Do something, I can happily live with the existing way. The
>"self" thing is totally obvious, occasionally irritating,
>and just fine the way it is, IMO.

Erm, okay. I think we agree. I liked this new notation and
think it's good. I just don't think Python needs it. Which
isn't to say that our would-be language designer can't come
up with a language of his own. I'm currently doing just that,
simply as a hobby (and as an exercise is performance
optimization and as a way to test certain beliefs I have
about the implementation of Python; don't hold your breath,
quite probably no news later, ha ha).

>and-an-almost-fanatical-devotion-to-the-bdf-ly y'rs,

guidos-a-nice-enough-fellow-most-probably-but-pardon-me-while-
I-puke-ly y'rs

:)

C//

Ben Wolfson

unread,
Jan 13, 2002, 2:43:39 AM1/13/02
to
On Fri, 11 Jan 2002 21:10:21 -0600, Gareth McCaughan wrote:

> I much prefer a different approach.
>
> class MyClass:
> def staticmethod bar(y):
> blah()
> stuff += stuff
> def classmethod baz(z):
> return 1
>
> This generalizes in an obvious way:
> def <name1> <name2>(<formals>): <body>
> turns into
> def <name2>(<formals>): <body>
> <name2> = <name1>(<name2>)
> which would make it possible, e.g., to define
> a function called "memo" which memoizes its argument
> and say (typical useless example follows):
> def memo fib(n):
> if n<2: return n
> return fib(n-2)+fib(n-1)
> and get only O(n) calls to "fib" on doing fib(n).

You can achieve something similar with a metaclass:

class funcmodifier(type):
def __init__(cls, name, bases, dict):
super(funcmodifier, cls).__init__(name, bases, dict)
replace = {}
for name,value in dict.iteritems():
if callable(value) and cls._isvalidname(name):
modname, funcname = name.split('_',1)
try:
f = sys._getframe(1) #caller's frame
mod = eval(modname, f.f_globals, f.f_locals)
except NameError: continue
if not callable(mod): continue
func = mod(value)
replace[name] = (funcname, func)
for name, (newname, func) in replace.iteritems():
delattr(cls, name)
setattr(cls, newname, func)
def _isvalidname(name):
if name.startswith('_'): return 0
has_uscore = name.count('_')
if has_uscore == 1 and name.endswith('_'): return 0
return has_uscore
_isvalidname = staticmethod(_isvalidname)

>>> class Hungarian:
__metaclass__ = funcmodifier
def classmethod_hovercraft(*a): print a
def staticmethod_eels(*a): print a


>>> h = Hungarian()
>>> h.hovercraft('blah')
(<class '__main__.Hungarian'>, 'blah')
>>> h.eels('la','dee','da')
('la', 'dee', 'da')
>>>

--
BTR
BEN WOLFSON HAS RUINED ROCK MUSIC FOR A GENERATION
-- Crgre Jvyyneq

Nils Kassube

unread,
Jan 13, 2002, 12:29:19 PM1/13/02
to
Michael Chermside <mch...@destiny.com> writes:

> Okay, for some reason this newsgroup tends to get WAY more suggestions
> for language changes than that for any other language that I know. I

Yes, "suggestions" because the Common Lisp folks simply write a
macro to improve their language and don't whi^H^H^Hhave to ask
someone else to do it :-)

> So in method declarations where we normally permit only an identifier
> for the method-name, we now allow also identifier '.' identifier. The
> identifier before the dot simply becomes the first parameter of the
> method. I don't think it would be good style to use this for

This looks like change to fit someones personal taste for syntax
without providing a substantial improvement over the previous way.

I don't think it's worth the effort to change the Python interpreter,
Jython, the Python parsers in Vim, Emacs, and whatever else that's
currently supporting Python.

Michael Hudson

unread,
Jan 15, 2002, 7:16:00 AM1/15/02
to
Gareth.M...@pobox.com (Gareth McCaughan) writes:

> Ah yes. That would be a shame. So here's a variant.
>
> class MyClass:
> def bar(y) [staticmethod]:
> do_some_stuff()
> return 123
>
> By the way, if you define generator(x) to be the same
> as iter(x) then that lets you say
>
> def f(x) [generator]:
> while 1:
> yield x
> x=x+1
>
> after which f *is* a generator, not a function that returns
> a generator. I don't think this is worth doing :-).
>
> The manic generalizer in me wants to add that if you have
> several modifiers you want to apply to a function or method,
> you can say
>
> def f(x) [memoized,classmethod,ignoring_errors]:
> <stuff>
>
> but I'm not sure whether that's elegant or gratuitous
> just yet.

Hmm, that's quite a neat idea. Dons hacking hat...

Cheers,
M.

--
As it seems to me, in Perl you have to be an expert to correctly make
a nested data structure like, say, a list of hashes of instances. In
Python, you have to be an idiot not to be able to do it, because you
just write it down. -- Peter Norvig, comp.lang.functional

Thomas Heller

unread,
Jan 15, 2002, 7:32:00 AM1/15/02
to

"Alex Martelli" <al...@aleax.it> wrote in message news:ldK%7.5660$sW5.2...@news2.tin.it...
I prefer to write classmethods in this way, but maybe I'm just weird ;-)
(and I don't use staticmethods)

class sic(object):
class __metaclass__(type):
def aclassmethods(self): pass
def anormalmethod(self): pass

Thomas

Reply all
Reply to author
Forward
0 new messages