Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Ruby blocks in Python, a suggestion

Reply
Thread Tools

Ruby blocks in Python, a suggestion

 
 
Jim Jewett
Guest
Posts: n/a
 
      04-09-2004
"John Roth" <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...

> The typical use of a block in Ruby is to inject some code
> into a predefined routine. The code will be executed with
> a yield statement. In general, that block has access to the
> routine's variables, and vice versa. The routine is normally
> some kind of loop over a collection. The block itself is
> placed after the calling parameter list.


What do you mean by inject? Are you saying that you can
inherit from any code object, and insert into the middle?

For instance could I do something like this:

class A(object):
def m1(self):
func1()
func2()

class B(object):
def m1(self):
func1()
func1a()
func2()

without having to retype func1 and func2, or even having to worry
about them, so that class B will be robust against changes to class A?

If so, how does func1a find it's place? pattern matching?

If not, what is the point? Just a function which *can* modify its
enclosing scope? (or a macro, depending on your perspective)? Or
am I still missing something?

-jJ
 
Reply With Quote
 
 
 
 
John Roth
Guest
Posts: n/a
 
      04-09-2004

"Jim Jewett" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) m...
> "John Roth" <(E-Mail Removed)> wrote in message

news:<(E-Mail Removed)>...
>
> > The typical use of a block in Ruby is to inject some code
> > into a predefined routine. The code will be executed with
> > a yield statement. In general, that block has access to the
> > routine's variables, and vice versa. The routine is normally
> > some kind of loop over a collection. The block itself is
> > placed after the calling parameter list.

>
> What do you mean by inject? Are you saying that you can
> inherit from any code object, and insert into the middle?


"The code will be executed with a yield statement."

I guess that wasn't clear. In order to execute a block,
the function has to have a yield statement. That yield
statement is what calls the block, and passes it any
parameters it requires. (It's quite different from a Python
yield statement.) That's part of Ruby's "one block per function"
semantics. (The other part is that the block is placed after
the function's parameter list in a syntactically distinct place.
It's not a parameter in the normal sense.)

The reason for saying "inject" is that, under some
circumstances, the block can access the host function's
locals, which you wouldn't expect from a normal function
that's passed as a parameter.

John Roth


 
Reply With Quote
 
 
 
 
David MacQuigg
Guest
Posts: n/a
 
      04-10-2004
On Wed, 7 Apr 2004 14:55:13 -0400, "John Roth"
<(E-Mail Removed)> wrote:
[snip]
>Ruby's blocks are part of a larger feature that most Ruby
>afficianados think is well worth the price of admission.
>
>The typical use of a block in Ruby is to inject some code
>into a predefined routine. The code will be executed with
>a yield statement. In general, that block has access to the
>routine's variables, and vice versa. The routine is normally
>some kind of loop over a collection. The block itself is
>placed after the calling parameter list.
>
>After a lot of pondering, I think that it wouldn't be that hard
>to add anonomous functions to Python, but without the other
>features it would be somewhat less than overwhelmingly
>useful, as it is in Ruby.
>
>A lot of people have tried to get a nice syntax over the years,
>and have failed to find anything persuasive. So I conclude that
>there isn't a "nice" syntax that will get universal acclaim.
>Therefore, the following will work, and might even be
>relatively easy to implement.
>
>foobar = {def (...):
> suite
> }
>


This to me looks not much better than:

def f(...):
suite
foobar = f

I recently put together a page for the UserLinux project, attempting
to show any fundamental advantages of Ruby over Python.
http://userlinux.com/cgi-bin/wiki.pl?RubyPython

After much discussion, I concluded that 90% of the differences are
just personal preference, and the other 10% are so complex that an
ordinary Python programmer can't understand :>). I did find that
string methods were a bit easier in Ruby ( see the page above ).

Code blocks were a topic we never resolved. There are some examples
on the page above, and on a page with a link you will see at the
bottom of that page. If you can come up with a good example,
something that has a little more detail that your example above, but
not so much that we can't follow it, I will post that example on our
page.

-- Dave


 
Reply With Quote
 
Daniel Ehrenberg
Guest
Posts: n/a
 
      04-11-2004
While I like the idea of blocks in Python, that's very bad syntax for
it. I think something better would be

def run_with_args(**args, &block):
block(**args)
run_with_args(something, somethingelse) as this, that:
assert something == this
assert somethingelse == that

This is contrived, but I think this shows the basic syntax. Also, you
miss the point of why we need blocks: they allow for more abstraction,
especially syntactic abstraction. This is important, but it seems to
have missed the designers of Python. Part of the Python philosophy is
that if some syntax was needed, it should already be in the language.
Although that works most of the time, it fails for things like GUIs.
It seems like every GUI library has its own idea of how to respond to
events. Almost always, they rely on named functions sent as arguments
for this, but the functions are only used once. To me, it seems better
to do what Ruby and Smalltalk do: use anonymous blocks. These make for
cleaner and more consistent code.

Daniel Ehrenberg

Ville Vainio <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
> I participated in a short thread on c.l.ruby, and had myself convinced
> that "blocks" might be a good idea. For bragging rights, if nothing
> else .
>
> What I'm talking about is:
>
> <callable> block [<block args>]:
> suite
>
>
> <callable> would be called with one argument, 'block', which it could
> execute via normal calling (or call, or execute, or whatever).
>
> i.e.
>
> class with_open_file:
> def __init__(self, *args):
> self.args = args
> def __call__(self, block):
> f = open(*self.args)
> try:
> block.call(f) # f is passed to the "block argument"
> finally:
> f.close()
>
> def somefunc():
> x = 10
> with_open_file("a.txt","r") block(f): # assigns f to the opened file
> x = len(f.read()) # rebinds x!
>
> Note that block would be executed with the same bindings as
> somefunc(), not its lexically closed bindings that would be the case
> if the actions within block were in a normal function.
>
> Other examples:
>
> transaction(dbconn) block(t): # commit/rollback t based on exception status
> t.dostuff()
>
>
> foreach([(1,2), (2,4), (3,6)]) block(x,y):
> assert y == X*2
>
> mapseq(seq) block(entry, result):
> result.append(entry * 2)
>
> Obviously this functionality could be quickly hacked by making the
> bindings of "block parameters" function-global just like the variable
> in for loops (and LC's in the current implementation). Even if only
> block-visible fucntionality would be so much cooler.
>
> And yes, I know this blocks issue has been hashed over previously. I'm
> just too busy to google for it right now, and just wanted to get this
> off my chest quickly .

 
Reply With Quote
 
John Roth
Guest
Posts: n/a
 
      04-11-2004
"Daniel Ehrenberg" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) om...
> While I like the idea of blocks in Python, that's very bad syntax for
> it. I think something better would be
>
> def run_with_args(**args, &block):
> block(**args)
> run_with_args(something, somethingelse) as this, that:
> assert something == this
> assert somethingelse == that
>
> This is contrived, but I think this shows the basic syntax. Also, you
> miss the point of why we need blocks: they allow for more abstraction,
> especially syntactic abstraction. This is important, but it seems to
> have missed the designers of Python. Part of the Python philosophy is
> that if some syntax was needed, it should already be in the language.
> Although that works most of the time, it fails for things like GUIs.
> It seems like every GUI library has its own idea of how to respond to
> events. Almost always, they rely on named functions sent as arguments
> for this, but the functions are only used once. To me, it seems better
> to do what Ruby and Smalltalk do: use anonymous blocks. These make for
> cleaner and more consistent code.


As it turns out, at least for the work I'm doing with Tkinter, Python
supports callbacks without any problem at all. The difficulty is that
the standard references don't describe what you need to do very
well.

What's the magic solution? Use bound methods. If you're doing
anything substantial with an interface you've encapsulated it in a
class anyway. Using an anonymous function is simply adding an
unnecessary level of indirection. That's only necessary if you're
using a procedural programming style.

Also, I think you may have missed two of my major points.

1. I like the notion of blocks myself. I'm certainly not arguing
against them, and if you think I am, you've misinterprered what
I've been saying.

2. The utility of blocks in Ruby is due to the intersection of
several different features. Just adding blocks to Python isn't
going to suddenly enable what you can do in Ruby with them.

John Roth


 
Reply With Quote
 
Dave Benjamin
Guest
Posts: n/a
 
      04-12-2004
In article <(E-Mail Removed)>, John Roth wrote:
> As it turns out, at least for the work I'm doing with Tkinter, Python
> supports callbacks without any problem at all. The difficulty is that
> the standard references don't describe what you need to do very
> well.
>
> What's the magic solution? Use bound methods. If you're doing
> anything substantial with an interface you've encapsulated it in a
> class anyway. Using an anonymous function is simply adding an
> unnecessary level of indirection. That's only necessary if you're
> using a procedural programming style.


From my experience, this is very accurate. A bound method is usually a very
convenient way to set up a callback, since it carries the state of the
object you are wiring the GUI component to. In addition, it has by far the
cleanest syntax that Python has to offer for this situation.

I can think of a few situations where you might need an event callback that
does not wire the GUI component to an object, however. For instance, say you
had a text field and you wanted to make sure it contained no spaces. In this
case, it's arguably not a concern of any other object. Ie.:

def removeAllSpaces(tf):
tf.text = tf.text.replace(' ', '')

tf = TextField()
tf.onChange = removeAllSpaces

Now, with code blocks, it could be written this way:

tf = TextField()
tf.onChange = [ tf | tf.text = tf.text.replace(' ', '') ]

With a bound method, it would be:

tf.onChange = someOtherObject.removeAllSpaces

But is this really the concern of any other object than the TextField? It
might be, depending on the situation, but in many cases there is no object
that is clearly responsible for this type of behavior besides the TextField
itself. So, to be OO about it, I suppose you could inherit from TextField
(if the API allows you to do so) and create a SpaceRemovingTextField, but
this seems like unnecessary namespace clutter as well as a useless
abstraction (unless you need this feature in many places).

> 2. The utility of blocks in Ruby is due to the intersection of
> several different features. Just adding blocks to Python isn't
> going to suddenly enable what you can do in Ruby with them.


Excellent point.

--
..:[ dave benjamin: ramen/[sp00] -:- spoomusic.com -:- ramenfest.com ]:.
: please talk to your son or daughter about parametric polymorphism. :
 
Reply With Quote
 
John Roth
Guest
Posts: n/a
 
      04-12-2004

"Dave Benjamin" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> In article <(E-Mail Removed)>, John Roth wrote:
> > As it turns out, at least for the work I'm doing with Tkinter, Python
> > supports callbacks without any problem at all. The difficulty is that
> > the standard references don't describe what you need to do very
> > well.
> >
> > What's the magic solution? Use bound methods. If you're doing
> > anything substantial with an interface you've encapsulated it in a
> > class anyway. Using an anonymous function is simply adding an
> > unnecessary level of indirection. That's only necessary if you're
> > using a procedural programming style.

>
> From my experience, this is very accurate. A bound method is usually a

very
> convenient way to set up a callback, since it carries the state of the
> object you are wiring the GUI component to. In addition, it has by far the
> cleanest syntax that Python has to offer for this situation.
>
> I can think of a few situations where you might need an event callback

that
> does not wire the GUI component to an object, however. For instance, say

you
> had a text field and you wanted to make sure it contained no spaces. In

this
> case, it's arguably not a concern of any other object. Ie.:
>
> def removeAllSpaces(tf):
> tf.text = tf.text.replace(' ', '')
>
> tf = TextField()
> tf.onChange = removeAllSpaces
>
> Now, with code blocks, it could be written this way:
>
> tf = TextField()
> tf.onChange = [ tf | tf.text = tf.text.replace(' ', '') ]
>
> With a bound method, it would be:
>
> tf.onChange = someOtherObject.removeAllSpaces
>
> But is this really the concern of any other object than the TextField? It
> might be, depending on the situation, but in many cases there is no object
> that is clearly responsible for this type of behavior besides the

TextField
> itself. So, to be OO about it, I suppose you could inherit from TextField
> (if the API allows you to do so) and create a SpaceRemovingTextField, but
> this seems like unnecessary namespace clutter as well as a useless
> abstraction (unless you need this feature in many places).


That's a good point, but it only applies if you haven't
encapsulated the rest of the interaction with the TextField
widgit. If you have, making it a bound method of that
object is real cheap, and it's rather obvious that the field
edits are a responsibility of the encapsulating object.

John Roth

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



 
Reply With Quote
 
Ville Vainio
Guest
Posts: n/a
 
      04-13-2004
>>>>> "John" == John Roth <(E-Mail Removed)> writes:

John> The reason for saying "inject" is that, under some
John> circumstances, the block can access the host function's
John> locals, which you wouldn't expect from a normal function
John> that's passed as a parameter.

I think that's what they call 'dynamic scope', and it has been
generally considered a bad idea.

--
Ville Vainio http://tinyurl.com/2prnb
 
Reply With Quote
 
Ville Vainio
Guest
Posts: n/a
 
      04-13-2004
>>>>> "Daniel" == Daniel Ehrenberg <(E-Mail Removed)> writes:

Daniel> for this, but the functions are only used once. To me, it seems better
Daniel> to do what Ruby and Smalltalk do: use anonymous blocks. These make for
Daniel> cleaner and more consistent code.

But if you call the function something like B, it's 'almost'
anonymous. Actual anonymity doesn't buy you much, esp. if you can
reuse the same name over and over.

And speaking of syntax, perhaps something like this would do:

def func():
y = 12
defblock B(x,y):
print x+y
y = 4


print y # prints 4

do_stuff(B)

This way, the only difference b/w block and function would be the fact
that block has the same locals() (and free vars) as the enclosing
function.

--
Ville Vainio http://tinyurl.com/2prnb
 
Reply With Quote
 
Ville Vainio
Guest
Posts: n/a
 
      04-13-2004
>>>>> "John" == John Roth <(E-Mail Removed)> writes:

John> 2. The utility of blocks in Ruby is due to the intersection of
John> several different features. Just adding blocks to Python isn't
John> going to suddenly enable what you can do in Ruby with them.

Not suddenly, but give it a couple of months. Adding various wrappers
that use blocks instead of funcs is trivial, anyone can introduce the
wrappers in ther own code.

--
Ville Vainio http://tinyurl.com/2prnb
 
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
Methods and blocks - not that clear when blocks passed into Steven Taylor Ruby 9 04-27-2009 08:46 AM
Coexistency Problem: cygwin + Ruby for Window (and suggestion for improving the Ruby installer) Ronald Fischer Ruby 6 05-21-2007 08:32 AM
"Building Blocks" are "Application Blocks" Arjen ASP .Net 3 02-27-2005 01:06 AM
procs/blocks - blocks with procs, blocks with blocks? matt Ruby 1 08-06-2004 01:33 AM



Advertisments