Re: Another try at Python's selfishness

2006-02-04 Thread n . estner
Donn Cave wrote:

 Quoth [EMAIL PROTECTED]:
 |  Still see no problem.  Of course, it goes without saying that
 |  Python 2.4 doesn't work this way, but given that it's theoretically
 |  possible for f(a) to be resolved similarly to a.f, then I really
 |  do not see what you're seeing here.  The kwargs parameter appears
 |  irrelevant from where I'm sitting.
 |
 | Then either you didn't understand my answers, or I didn't understand
 | your idea. Could you summarize how exactly f(x,y=z) should be
 | resolved, i.e. where it should look for f?

 a.f == f(a)

So, if the compiler recognizes the tokens a.f, it should treat them
as if it found the tokens f(a). But that wouldn't do what you want.
You want it to do something different if it found the tokens f(a).

 I would agree that I didn't understand your answers, but they weren't
 really answers so much as questions, along the lines of ``well then,
 how would this work?''  I seem to have missed what you were driving at,
 but maybe if you were to just came out and explain the point?

You do know what a rethorical question is?

The first point is: Python has global functions, as well as methods. If
f(a) should look up f inside a first, that would shadow any global or
local f. That's bad, because python is dynamically typed, and you
sometimes down' know what a is. Things like open(filename) or
tuple(a,b,c) could behave completely unexpected, if filename had an
open or a a tuple attribute.

The other point is: Python supports named arguments. The algorithm to
put positional and named arguments into the right parameters is rather
tricky, and it _must_ know the function that's being called to work.
So, you simply can't make function lookup depend on the parameters,
it's a hen-egg problem.

 Of course the whole business is kind of a joke, since there is no way
 anyone in their right mind would wish to change Python's notation for
 such trivial reasons, but there actually are languages that resolve
 functions based on argument types.  Overloading in C++ is somewhat
 like this, Haskell's typeclass mechanism, and there is a ``multiple
 dispatch'' model that I have no experience with but is not without its
 supporters.

Yes, but both C++ and Haskell are statically typed, and neither
supports named arguments.
(We're talking about one function operating on one object, so I don't
see what multiple dispatch has to do with this)

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Another try at Python's selfishness

2006-02-03 Thread n . estner
 That usage (self is second parameter to B.test) is bound
 to cause trouble in general, but in this case doesn't have
 any effect I can see.  The function call test would be
 resolved from its first parameter, instance of A, and that
 function would return 1.  One of us is missing something
 here, could be me.

Probably my example wasn't clear, let's try another:

  class A:
def test(a, **kwargs): return 1
  class B:
def test(b, **kwargs): return 2
  test(a=A(), b=B())

self isn't a keyword, so nothing should forbid this code. What is the
interpreter to do if it stumbles across this test call? I mean,
named-argument lookup is a tricky thing even if you do know what
function you're calling. If this would depend on one of the parameters,
I think it would become completely unintelligible. (you can think of
more complex examples yourself)

 That's exactly the problem, it doesn't read from left to right,
 because we swap back and forth between function(parameter and
 parameter.function notation.

That's because they're doing two different things: object.method() does
an attribute lookup, while function(parameter) looks for the function
in the current scope.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Another try at Python's selfishness

2006-02-03 Thread n . estner
Yes, that's what I had in mind when I said it could be made
recursion-safe. It's still not thread-safe, but I think that could be
done too, using thread-local-variables instead of globals.

 class TestB:
 @memberFunction
 def do(x):
 z = __  # lambda's shouldn't directly reference '__'
 x.do(lambda : z)

Yes, that's what I meant when I said it wasn't lambda-safe. That means
a completely legal and (in my code) common expression can behave
totally unexpected. Would be a no-go for me.

But I think it gets worse:

class TestA:
@memberFunction
def do():
yield 1
yield 2
yield __


class TestB:
@memberFunction
def bar():
for x in TestA().do():
print x

TestB().bar()

Doesn't behave as expected, and the only way I can see to fix it would
be to declare a local function inside TestA's do function...

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Another try at Python's selfishness

2006-02-03 Thread n . estner
 First of all, you are using a really poor example of a method,
 since it doesn't use any attributes of the Foo instance.

Agreed. I tried to post a short example, and it obviously was to short
to make my point clear. lets take a longer one. Current syntax:

class Pair:
def __init__(self, a,b):
self.a = a
self.b = b

def sum(self):
return self.a + self.b

def product (this):
return this.a + this.b

My alternative syntax suggestion would be this one:

class Pair:
def self.__init__(a,b):
self.a = a
self.b = b

def self.sum():
return self.a + self.b

def this.product ():
return this.a + this.b

 You are really giving self a magic meaning with your suggestion
 which isn't needed at all.

No. I hope this is clearer in the example above. self shouldn't be a
keyword. It's a special kind of argument now, so why shouldn't we
explicitly _declare_ that it's a special kind of argument? (as explicit
is better than implicit)

 So far, the existence of x.y somewhere
 in Python always implied that x was already introduced explicitly
 in the program,

Yes, but y(x) also implies that x and y have been introduced explicitly
before, unless it's in a def statement. The def statement always
introduces new variables.

 and you suggest that we violate that both in the
 def self.x-row, and inside the methods when we access attributes.

  def x(self):
declares two new identifiers, x and self

Why shouldn't
  def self.x():
declare two new identifiers (x and self), too?

Attribute acces wouldn't change.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Another try at Python's selfishness

2006-02-03 Thread n . estner
 I still see newbie-friendliness as a
 MAJOR plus for Python -- it increases the chance that users
 of your software will become contributors.

Yes, I 100% agree to that point!
But the point is, the current situation is not newbie-friendly (I can
tell, I am a newbie): I declare a method with 3 parameters but when I
call it I only pass 2 parameters. That's confusing. If I declare a
member variable, I write: self.x  = ValueForX, why can't I be equally
explicit for declaring member functions?

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Another try at Python's selfishness

2006-02-03 Thread n . estner
 You could try running it to see:

  class A:

 ... def test(a, **kwargs): return 1
 ...
  class B:

 ... def test(b, **kwargs): return 2
 ...
  test(a=A(), b=B())

 Traceback (most recent call last):
   File stdin, line 1, in ?
 NameError: name 'test' is not defined

 Oops! You have defined a name test in two namespaces, the class A and
 the class B, but there is no name test in the global namespace you are
 trying to run it in.

 Since namespaces are critical to Python, your test code is a problem that
 just cannot happen in Python. It is a non-issue. Python will not get
 confused between the two definitions of test.

I've been answering to Donn Cave's suggestion. Read it, and you will
understand what I mean.

 As near as I can tell, your original complaint might be solved simply: it
 seems to me that you are concerned about that extraneous self parameter
 for methods that don't need it:

No, I wasn't talking about functions that don't use the self
parameter. I rarely ever have such functions. I just tried to make the
example as short as possible.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Another try at Python's selfishness

2006-02-03 Thread n . estner
 ...
 Unfortunately, none of this suggests that it's reasonable to have

 def x.y(z): ...

 mean the same as

 def y(x, z): ...

Actually, it shouldn't. The idea was, that
def x.y(z): ...
(explicitly) introduces an unbound method. That's not introducing a new
conect to python, it's just making the difference between an unbound
method and a not-bindable function explicit.

Currently, def(x,y): ... can mean two different things: In the
context of a class, it introduces an unbound method, in global or local
contexts it introduces a function. I don't want to have a new syntax
for that, I want two different syntaxes for these two different
meanings.

 and I have no idea of how it would generalize to def x.y.z(t): ...

Nor do I. Is that a problem?

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Another try at Python's selfishness

2006-02-03 Thread n . estner
 Still see no problem.  Of course, it goes without saying that
 Python 2.4 doesn't work this way, but given that it's theoretically
 possible for f(a) to be resolved similarly to a.f, then I really
 do not see what you're seeing here.  The kwargs parameter appears
 irrelevant from where I'm sitting.

Then either you didn't understand my answers, or I didn't understand
your idea. Could you summarize how exactly f(x,y=z) should be
resolved, i.e. where it should look for f?

-- 
http://mail.python.org/mailman/listinfo/python-list


Another try at Python's selfishness

2006-02-02 Thread n . estner
Having read previous discussions on python-dev I think I'm not the only
Python programmer who doesn't particularly like python's self
parameter:

class Foo:
def bar(self, a,b):
return a+b
Foo().bar(1,2) = 3

The main reason (at least for me) is that there's simply too much
magic in it. Why does the expression left of the '.' get promoted to
the first parameter? It even goes further:

Foo.bar(Foo(), 1,2)

works, but:

Foo.bar(1,2,3)

doesn't, just because of the magical first parameter in a member
function. But:

Foo.__dict[bar]__(1,2,3)

Does work.

The point is, I _do_ think it's a good idea to explicitly write
self.SomeMember for member-access, so I thought: why can't we be
equally explicit about member function declaration? Wouldn't it be nice
if I could write (say, in Python 3k, or maybe later):

class Foo:
def self.bar(a,b):
return a+b
Foo().bar(1,2) = 3

That way, the declaration would match the invocation (at least
syntactically), and the magic-feeling is gone. In the long run, the
old-style syntax (i.e. if there's no '.' in the method name) could be
used for static methods.

What do you think?

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Another try at Python's selfishness

2006-02-02 Thread n . estner
write(sys.stdin, split(read(open(file, 'r')))[0])

So, if I got you right, the interpreter would have to interpret this
line like this:
1. Evaluate the first parameter of the first function (sys.stdin)
2. Look up the attribute write in this object
3. evaluate the first parameter of the split function -
4. evaluate the first parameter of the read function -
5. evaluate file (I guess this is a local string variable?)
6. try attribute lookup open on the string
7. fail - call the global open function
8. lookup read in that object, call it
9. attribute lookup split on the returned object
10. call __getitem__(0)
11. pass the parameters to the write function from (1)

Is this correct?
My main problems are that you have to guess at step 6/7, and that the
order of evaluation makes me a little dizzy ;-) Also, member functions
seem to shadow global ones, what if I wanted to use some global
split function I've written myself instead of the string's one. If I
was mean, I'd ask you what this one does:
  class A:
def test(self, this): return 1
  class B:
def test(this, self): return 2
  test(self=A(), this=B())

The current call syntax at least can be read from left-to-right, and
you always know whether you call a member function or a global one.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Another try at Python's selfishness

2006-02-02 Thread n . estner
Definitely looks interesting. I'd like it more if it was more explicit,
but still, it does look nice.

I guess you could make it recursion-safe if you saved/restored the
global __ variable before/after calling the actual function, and
probably there's a way to make it thread-safe, too. But how would you
make it generator-safe? Also, wouldn't lambda's you pass around from
object to object be bound to use the wrong instance? How would you fix
this code:

class TestA:
@memberFunction
def do(f):
print f()


class TestB:
@memberFunction
def do(x):
x.do(lambda : __)

TestB().do(TestA()) # should print out TestB, does print out TestA


There really should be something like a wiki for
selfishness-proposals with pros and cons, so I could have looked at
some before thinking about my own one...

-- 
http://mail.python.org/mailman/listinfo/python-list