Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Python (http://www.velocityreviews.com/forums/f43-python.html)
-   -   Simple prototyping in Python (http://www.velocityreviews.com/forums/t330435-simple-prototyping-in-python.html)

Dave Benjamin 04-30-2004 12:43 AM

Simple prototyping in Python
 
The recent conversation on prototype-based OOP and the Prothon project has
been interesting. I've been playing around with the idea for awhile now,
actually, since I do a lot of programming in JavaScript/ActionScript. I feel
like people are focusing too much on the "prototype chain", which to me is
mainly an attempt at reintroducing inheritance. I almost never use
inheritance anymore, preferring delegation instead in most cases. What I
think is much more interesting about the prototype-based style is the
ability to create and pass around anonymous objects. JavaScript has a syntax
for this:

var o = {a: 5, b: 6}

which is roughly equivalent to Python's:

class Whatever: pass
o = Whatever()
o.a = 5
o.b = 6

If you can tolerate some Lispism, you can actually create anonymous objects
in straight Python. This is liable to get some adverse reactions, but I just
want to demonstrate that it *can* be done. Here's an example:

class obj:
def __init__(self, **kwds):
self.__dict__.update(kwds)

def set(self, name, value):
setattr(self, name, value)

def do(*args):
return args[-1]

def counter(start):
ref = obj(value=start)
return obj(
current = lambda: ref.value,
next = lambda: do(
ref.set('value', ref.value + 1),
ref.value))

c = counter(0)
print c.current()
print c.next()
print c.next()
print c.current()

This outputs:

0
1
2
2

--
..:[ dave benjamin: ramen/[sp00] -:- spoomusic.com -:- ramenfest.com ]:.
: please talk to your son or daughter about parametric polymorphism. :

has 04-30-2004 04:55 PM

Re: Simple prototyping in Python
 
Dave Benjamin <ramen@lackingtalent.com> wrote in message news:<slrnc938vm.1v0.ramen@lackingtalent.com>...
> The recent conversation on prototype-based OOP and the Prothon project has
> been interesting. I've been playing around with the idea for awhile now,
> actually, since I do a lot of programming in JavaScript/ActionScript. I feel
> like people are focusing too much on the "prototype chain", which to me is
> mainly an attempt at reintroducing inheritance.


It doesn't even do that; at least not in the sense that class-based OO
defines it, where inheritance merely describes the initial state for
every object created from a class.

To me, the way Prothon and Io do "prototypes" feels more like a leaky
abstraction, where a common internal optimisation for proto-OO systems
has somehow leaked out into user-space. See if I ever find that
Lieberman fellow, think I'll be having a word or two with 'im. ;)


> I almost never use
> inheritance anymore, preferring delegation instead in most cases. What I
> think is much more interesting about the prototype-based style is the
> ability to create and pass around anonymous objects.


In a proto-OO system all objects are _completely_ anonymous*, having
no 'class' and all being of the same type, 'object'. In this respect,
they're just like strings, lists, dicts, or any other 'anonymous'
type; a list is a list is a list, for example, regardless of how it is
used.


(* To the user, anyway. Of course, they still have internal ids so the
runtime can track 'em, but that's not something the user ever needs to
know about.)

> JavaScript has a syntax
> for this:
>
> var o = {a: 5, b: 6}


Looks on the surface like AppleScript's record type, which is roughly
analogous to C structs... and useless for anything more than
struct-style usage. While I did read about JS programming in the
dim-n-distant past - it was one of a number of languages I looked at
when learning proto-OO on AS, which lacked any decent learning
material on the topic - I've pretty much forgotten everything since.
So can I ask: is the JS structure more flexible; e.g. can one add
functions to it to operate like methods on the other data in the
structure? Or does it have to provide a second structure for proto-OO
use, as AS does?

Dave Benjamin 04-30-2004 05:52 PM

Re: Simple prototyping in Python
 
In article <69cbbef2.0404300855.20dd436b@posting.google.com >, has wrote:
> Dave Benjamin <ramen@lackingtalent.com> wrote in message news:<slrnc938vm.1v0.ramen@lackingtalent.com>...
>> The recent conversation on prototype-based OOP and the Prothon project has
>> been interesting. I've been playing around with the idea for awhile now,
>> actually, since I do a lot of programming in JavaScript/ActionScript. I feel
>> like people are focusing too much on the "prototype chain", which to me is
>> mainly an attempt at reintroducing inheritance.

>
> It doesn't even do that; at least not in the sense that class-based OO
> defines it, where inheritance merely describes the initial state for
> every object created from a class.


But that is how it is used, anyway. See any textbook describing OO
programming in JavaScript. The caveats are also typically described, and
other hacks like the "__proto__" attribute (which is the object's prototype
object, not to be confused with the constructor's prototype object,
"prototype") are used to exercise more control (or confusion) over the matter.

> In a proto-OO system all objects are _completely_ anonymous*, having
> no 'class' and all being of the same type, 'object'. In this respect,
> they're just like strings, lists, dicts, or any other 'anonymous'
> type; a list is a list is a list, for example, regardless of how it is
> used.


Not necessarily. In JavaScript, you can still do "instanceof", for example.

>> JavaScript has a syntax
>> for this:
>>
>> var o = {a: 5, b: 6}

>
> Looks on the surface like AppleScript's record type, which is roughly
> analogous to C structs... and useless for anything more than
> struct-style usage. While I did read about JS programming in the
> dim-n-distant past - it was one of a number of languages I looked at
> when learning proto-OO on AS, which lacked any decent learning
> material on the topic - I've pretty much forgotten everything since.
> So can I ask: is the JS structure more flexible; e.g. can one add
> functions to it to operate like methods on the other data in the
> structure? Or does it have to provide a second structure for proto-OO
> use, as AS does?


Sure! JavaScript supports function literals that are true closures. In fact,
this feature can be used to support private data, which has been described
in some detail by Douglas Crockford, here:

http://www.crockford.com/javascript/private.html

The same technique can be accomplished by Python, though it'd be really nice
to have code blocks or function literals that accept statements.

--
..:[ dave benjamin: ramen/[sp00] -:- spoomusic.com -:- ramenfest.com ]:.
: please talk to your son or daughter about parametric polymorphism. :

Michael Geary 04-30-2004 09:26 PM

Re: Simple prototyping in Python
 
> Dave Benjamin wrote:
> > JavaScript has a syntax for this:
> >
> > var o = {a: 5, b: 6}


has wrote:
> Looks on the surface like AppleScript's record type, which
> is roughly analogous to C structs... and useless for anything
> more than struct-style usage. While I did read about JS
> programming in the dim-n-distant past - it was one of a
> number of languages I looked at when learning proto-OO
> on AS, which lacked any decent learning material on the
> topic - I've pretty much forgotten everything since. So can
> I ask: is the JS structure more flexible; e.g. can one add
> functions to it to operate like methods on the other data in
> the structure? Or does it have to provide a second structure
> for proto-OO use, as AS does?


A JavaScript object literal is simply a convenient way to construct an
object. You can put anything in that object that you can put in any other
object.

This object literal:

var o = { a: 5, b: 6 }

is just a shorthand for:

var o = new Object
o.a = 5
o.b = 6

In fact, if you do o.toSource() after either of those, you'll get the same
result:

({a:5, b:6})

As with any other object, you can put functions as well as data in an object
literal, e.g.:

var o =
{
a: 5,
incr: function() { return ++this.a },
}

o.incr() will return 6, 7, 8, etc. if you call it repeatedly.

As Dave mentioned, you can also use closures, as in this example which uses
both a closure and a property in the object literal:

function F()
{
var c = 105;

return {
a: 5,
incr: function() { return [ ++this.a, ++c ] },
}
}

var x = new F
var y = new F
x.incr()
y.incr()

-Mike



Dave Benjamin 04-30-2004 09:55 PM

Re: Simple prototyping in Python
 
In article <1095h4vc89hmcf@corp.supernews.com>, Michael Geary wrote:
> As with any other object, you can put functions as well as data in an object
> literal, e.g.:
>
> var o =
> {
> a: 5,
> incr: function() { return ++this.a },
> }
>
> o.incr() will return 6, 7, 8, etc. if you call it repeatedly.


Hey, I never knew that "this" could be used inside of an anonymous object
in JavaScript. Thanks for pointing that out!

In Python, you'd have to give the object a name, since there's no "self" to
refer to. For instance (using the "obj" and "do" functions I defined earlier):

def f():
o = obj(a=5, incr=lambda: do(o.set('a', o.a + 1), o.a))
return o

>>> o = f()
>>> o.a

5
>>> o.incr()

6
>>> o.incr()

7

Not exactly elegant, but not totally atrocious either...

--
..:[ dave benjamin: ramen/[sp00] -:- spoomusic.com -:- ramenfest.com ]:.
: please talk to your son or daughter about parametric polymorphism. :

Greg Ewing 05-03-2004 01:42 AM

Re: Simple prototyping in Python
 
Dave Benjamin wrote:
> Hey, I never knew that "this" could be used inside of an anonymous object
> in JavaScript. Thanks for pointing that out!
>
> In Python, you'd have to give the object a name, since there's no "self" to
> refer to.


No, you wouldn't, because the Python equivalent would
be something like


def F():
c = [105]

class C:
a = 5

def incr(self):
self.a += 1
c[0] += 1
return [self.a, c[0]]

return C()


It's a bit more awkward in Python due to the inability to
directly rebind a name in an outer scope.

BTW, IMO this is a seriously warped technique that I
would never use, even in Javascript. I can't see any
benefit in it that's anywhere near worth the obfuscation.

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


Dave Benjamin 05-03-2004 02:31 AM

Re: Simple prototyping in Python
 
In article <c74830$hrfbu$1@ID-169208.news.uni-berlin.de>, Greg Ewing wrote:
> Dave Benjamin wrote:
>> Hey, I never knew that "this" could be used inside of an anonymous object
>> in JavaScript. Thanks for pointing that out!
>>
>> In Python, you'd have to give the object a name, since there's no "self" to
>> refer to.

>
> No, you wouldn't, because the Python equivalent would
> be something like
>
> def F():
> c = [105]
>
> class C:
> a = 5
>
> def incr(self):
> self.a += 1
> c[0] += 1
> return [self.a, c[0]]
>
> return C()


I don't know if I'd call it equivalent. Similar in effect, naybe, but the
idea was to create an anonymous, classless object.

> It's a bit more awkward in Python due to the inability to
> directly rebind a name in an outer scope.


This is an issue, but not a serious one. In my original example, I used a
pretty simple workaround (an anonymous object).

> BTW, IMO this is a seriously warped technique that I
> would never use, even in Javascript. I can't see any
> benefit in it that's anywhere near worth the obfuscation.


One benefit, which applies equally to both languages, is that this technique
gets you closer to enforced private attributes than the standard ways of
making objects. I'm sure you could hack frames or something, but "c" is
pretty much inaccessible to the casual programmer in your example above.

--
..:[ dave benjamin: ramen/[sp00] -:- spoomusic.com -:- ramenfest.com ]:.
: please talk to your son or daughter about parametric polymorphism. :

Bengt Richter 05-03-2004 03:57 AM

Re: Simple prototyping in Python
 
On Mon, 03 May 2004 02:31:53 -0000, Dave Benjamin <ramen@lackingtalent.com> wrote:

>In article <c74830$hrfbu$1@ID-169208.news.uni-berlin.de>, Greg Ewing wrote:
>> Dave Benjamin wrote:
>>> Hey, I never knew that "this" could be used inside of an anonymous object
>>> in JavaScript. Thanks for pointing that out!
>>>
>>> In Python, you'd have to give the object a name, since there's no "self" to
>>> refer to.

>>
>> No, you wouldn't, because the Python equivalent would
>> be something like
>>
>> def F():
>> c = [105]
>>
>> class C:
>> a = 5
>>
>> def incr(self):
>> self.a += 1
>> c[0] += 1
>> return [self.a, c[0]]
>>
>> return C()

>
>I don't know if I'd call it equivalent. Similar in effect, naybe, but the
>idea was to create an anonymous, classless object.


Anonymous follows, though not classless ;-)

>>> o=type('',(),{'incr':lambda s: setattr(s,'a',getattr(s,'a',5)+1) or getattr(s,'a')})()
>>> o.incr()

6
>>> o.incr()

7
>>> o.incr()

8

Or perhaps better, using the class variable as initial value as Greg is doing above:

>>> o=type('',(),{'a':5,'incr':lambda s: setattr(s,'a',getattr(s,'a')+1) or getattr(s,'a')})()
>>> o.incr()

6
>>> o.incr()

7
>>> o.incr()

8

You could also concoct a bound method operating on the variable held in a list

>>> oincr = (lambda s:s.__setitem__(0,s[0]+1) or s[0]).__get__([5], list)
>>> oincr()

6
>>> oincr()

7
>>> oincr()

8

Or perhaps more cleanly, just subclass list and instantiate with initial value:

>>> o = type('',(list,),{'incr':lambda s:s.__setitem__(0,s[0]+1) or s[0]})([5])
>>> o.incr()

6
>>> o.incr()

7

This stuff is fun for exploring ins and outs of the language, but
readable is best, if there's a readable alternative ;-)


>
>> It's a bit more awkward in Python due to the inability to
>> directly rebind a name in an outer scope.

>

Yes, I wouldn't mind more and cleaner control of binding and evaluation,
as to when and where (e.g. read time, def time, call time and
local binding vs find-and-rebind in lexically nested or mro name spaces).

>This is an issue, but not a serious one. In my original example, I used a
>pretty simple workaround (an anonymous object).
>

OTOH, if something strikes you as a workaround, it's not something you want
to be struck with regularly ;-)

>> BTW, IMO this is a seriously warped technique that I
>> would never use, even in Javascript. I can't see any
>> benefit in it that's anywhere near worth the obfuscation.

>
>One benefit, which applies equally to both languages, is that this technique
>gets you closer to enforced private attributes than the standard ways of
>making objects. I'm sure you could hack frames or something, but "c" is
>pretty much inaccessible to the casual programmer in your example above.
>

Gotta go.

Regards,
Bengt Richter

Michael Geary 05-04-2004 07:05 AM

Re: Simple prototyping in Python
 
Greg Ewing wrote:
> BTW, IMO [the closure] is a seriously warped technique
> that I would never use, even in Javascript. I can't see any
> benefit in it that's anywhere near worth the obfuscation.


I think part of the problem is the contrived examples that we all use to
illustrate closures. They show the technique, but the closure doesn't
provide any apparent benefit.

At the risk of overstaying my welcome, here is a real life example, a bit of
Acrobat 6 multimedia JavaScript code that uses closures. I may have posted
this before (or maybe I'm thinking of the Prothon list), but this time I
translated the closure code into a version that uses objects and no
closures, so we can compare the two.

Here's what the code does. The reportScriptEvents function opens a media
player and starts it playing, and it provides an event listener that handles
two events, onScript and afterClose. Each time a script event occurs in the
media clip, the onScript event method appends the script event's command
name and parameter to a log string. After the media clip finishes playing,
the afterClose event method takes that accumulated log string and passes it
to a reporter function which was provided in the call to reportScriptEvents.

The testReport function calls reportScriptEvents and provides a reporter
function which displays the accumulated log in an alert box. testReport has
a title parameter which is used for the title of the alert box.

Note that the media player opens and plays asynchronously.
reportScriptEvents and testReport return immediately upon opening the
player, and the event methods and reporter function are called later on, as
the media clip plays and closes.

Here is the code using closures:

function reportScriptEvents( reporter )
{
var log = "";

app.media.openPlayer(
{
events:
{
onScript: function( e )
{
log += e.media.command + ": " + e.media.param + "\n";
},

afterClose: function()
{
reporter( log );
},
},
});
}

function testReport( title )
{
reportScriptEvents( function( log )
{
app.alert({ cTitle: title, cMsg: log });
});
}

Now for a version with no closures, using object properties to hold the
persistent state instead. I had to change the definition of
reportScriptEvents slightly. Instead of using a reporter function, it takes
a reporter object with a report method. In this version, the events object
has reporter and log properties which replace the closure variables in the
previous version, and the testReport function creates a reporter object with
a title property which it passes in to reportScriptEvents.

function reportScriptEvents( reporter )
{
app.media.openPlayer(
{
events:
{
reporter: reporter,
log: "",

onScript: function( e )
{
this.log +=
e.media.command + ": " + e.media.param + "\n";
},

afterClose: function()
{
this.reporter.report( this.log );
},
},
});
}

function testReport( title )
{
reportScriptEvents(
{
title: title,

report: function( log )
{
app.alert({ cTitle: this.title, cMsg: log });
},
});
}

The two versions are fairly similar, but the closure version of the code is
shorter and simpler, and to me it's easier to understand as well. I don't
have to create any objects or properties to hold persistent state. I just
use ordinary variables, and I don't have to think about the fact that the
event methods and reporter function are called long after the
reportScriptEvents and testReport return. The variables just work.

In the object version, I have to create the machinery to hold persistent
state myself, setting up the reporter and log properties in the events
object and the title property in the reporter object.

Sometimes objects and properties are a better solution, but to my eyes the
closure version is the winner in this particular case.

(Sorry to be posting so much JavaScript code in the Python group! :-) But
it's a good example of real world code that benefits from using closures.)

-Mike



Greg Ewing 05-05-2004 02:48 AM

Re: Simple prototyping in Python
 
Michael Geary wrote:
> Greg Ewing wrote:
>
>>BTW, IMO [the closure] is a seriously warped technique
>>that I would never use, even in Javascript. I can't see any
>>benefit in it that's anywhere near worth the obfuscation.

>
> I think part of the problem is the contrived examples that we all use to
> illustrate closures.


Just in case it wasn't clear, I was talking about that
particular use of a closure, i.e. simulating an object
with a private instance variable. I'm well aware that
there are other, better uses for closures.

The example you posted is a reasonable use of
closures (although the in-line-constructed object
passed as an argument to a function made my brain
hurt a bit while trying to parse it!)

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



All times are GMT. The time now is 07:52 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.