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

 
 
John Roth
Guest
Posts: n/a
 
      04-13-2004

"Ville Vainio" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> >>>>> "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.


Like operator overloading, multiple inheritance and other
things, it depends on what you're using it for. There are very
few language features that can't be used to confuse rather
than clarify.

John Roth
>
> --
> Ville Vainio http://tinyurl.com/2prnb



 
Reply With Quote
 
 
 
 
Michael Walter
Guest
Posts: n/a
 
      04-13-2004
Ville Vainio wrote:
>>>>>>"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.
>

For instance, "global variables" in Common Lisp usually have dynamic
extent. This allows temporarily modifying a global variable/parameter
rather easily, as in:

(let ((*print-readably* nil))
<body>)

in contrast to:

(let ((old-value *print-readably*))
(unwind-protect
(progn
(setf *print-readably* nil)
<body>)
(setf *print-readably* old-value)))

(in python:
global print_readably
old_value = print_readably
try:
print_readably = 0
<body>
finally:
print_readably = old_value)

So, 'generally' could be not as 'generally' as one might think.

Cheers,
Michael

PS: my CL is rusty
 
Reply With Quote
 
 
 
 
Jim Weirich
Guest
Posts: n/a
 
      04-13-2004
Ville Vainio <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
> >>>>> "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.


Just to be clear: Ruby blocks can access locals declared in the same
scope that the block/closure is created in. This is static scoping.

Blocks do not access the locals of the function in which they are
executed. That would be dynamic scoping.

I think John is saying the first, although the meaning of "host
function" is a little vague to me.

--
-- Jim Weirich ((E-Mail Removed))
 
Reply With Quote
 
John Roth
Guest
Posts: n/a
 
      04-13-2004

"Jim Weirich" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) om...
> Ville Vainio <(E-Mail Removed)> wrote in message

news:<(E-Mail Removed)>...
> > >>>>> "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.

>
> Just to be clear: Ruby blocks can access locals declared in the same
> scope that the block/closure is created in. This is static scoping.
>
> Blocks do not access the locals of the function in which they are
> executed. That would be dynamic scoping.
>
> I think John is saying the first, although the meaning of "host
> function" is a little vague to me.


Actually, I was saying the second, and I stand (or rather, sit)
corrected.

John Roth
>
> --
> -- Jim Weirich ((E-Mail Removed))



 
Reply With Quote
 
Lonnie Princehouse
Guest
Posts: n/a
 
      04-13-2004
Yes!

http://www.velocityreviews.com/forums/(E-Mail Removed) (Hung Jung Lu) wrote:
> def my_codeblock:
> assert(y == x*2)
>
> for (x,y) in [(1,2), (2,4), (3,6)]:
> exec my_codeblock


This is by far the prettiest syntax for blocks presented thus far =)
A function really is just a special case of a code block that (a)
operates within its own scope and (b) defines a mapping between that
scope and the calling scope. This syntax preserves that relationship,
while also avoiding adding new keywords like "defblock" to the
language. I would go so far as to say the code block should be
callable just like a function that takes no arguments-

def my_codeblock:
assert(y == x*2)

for (x,y) in [(1,2), (2,4), (3,6)]:
my_codeblock()

Someone should put in a PEP for this... it seems like these code
blocks could also help to speed up execution in certain circumstances,
since the interpreter doesn't need to create and then dispose of a new
scope for their execution.

And now for something completely different-
Why not make "def" into an expression that returns a
function/block, instead of a statement? This could obviate lambda by
providing anonymous functions that aren't limited to one line.

e.g.

my_function = def (x,y):
return sqrt(x**2 + y**2)

my_codeblock = def:
assert(y == x*2)

(Note- I'm not advocating the replacement of the current syntax, just
an extension) Of course, the indentation requirement might be a
problem when one tries to embed these expressions inside of other
expressions. Not sure how that would work. Semicolons, perhaps, but
then we start to look like Perl



-ljp
 
Reply With Quote
 
Joe Mason
Guest
Posts: n/a
 
      04-13-2004
In article <(E-Mail Removed) >, Lonnie Princehouse wrote:
> This is by far the prettiest syntax for blocks presented thus far =)
> A function really is just a special case of a code block that (a)
> operates within its own scope and (b) defines a mapping between that
> scope and the calling scope. This syntax preserves that relationship,
> while also avoiding adding new keywords like "defblock" to the
> language. I would go so far as to say the code block should be
> callable just like a function that takes no arguments-
>
> def my_codeblock:
> assert(y == x*2)
>
> for (x,y) in [(1,2), (2,4), (3,6)]:
> my_codeblock()


What's the point? If you've got to make a named item before the for
loop anyway, why not just use a function? The point of code blocks is
to be anonymous, and declared inline.

Joe
 
Reply With Quote
 
Glenn Andreas
Guest
Posts: n/a
 
      04-14-2004
In article <(E-Mail Removed)>,
Joe Mason <(E-Mail Removed)> wrote:

> In article <(E-Mail Removed) >, Lonnie
> Princehouse wrote:
> > This is by far the prettiest syntax for blocks presented thus far =)
> > A function really is just a special case of a code block that (a)
> > operates within its own scope and (b) defines a mapping between that
> > scope and the calling scope. This syntax preserves that relationship,
> > while also avoiding adding new keywords like "defblock" to the
> > language. I would go so far as to say the code block should be
> > callable just like a function that takes no arguments-
> >
> > def my_codeblock:
> > assert(y == x*2)
> >
> > for (x,y) in [(1,2), (2,4), (3,6)]:
> > my_codeblock()

>
> What's the point? If you've got to make a named item before the for
> loop anyway, why not just use a function? The point of code blocks is
> to be anonymous, and declared inline.
>
> Joe


Is it?

Or is the point of the codeblock to execute in the same scope as where
it is called (i.e., dynamic scoping).

It's fairly easy to emulate the anonymous part (by not having it inline,
and just using a dummy name, which makes it less anonymous), but it's
much harder to emulate the dynamic scoping (though with some magic of
the stack frame it could probably be done, but it might be pretty ugly).

Dynamic scoping be partially simulated easily enough:

def block(b):
import sys
caller_frame = sys._getframe().f_back
exec b.func_code in caller_frame.f_locals

def test():
def my_codeblock():
assert(y == x * 2)

for (x,y) in [(1,2), (2,4), (3,6)]:
block(my_codeblock)


(note that this won't actually work since you can't exec a function with
"free variables", so obviously the "injection" in block would need to be
a bit more clever - perhaps building a code object dynamically).

It may be possible to use function decorater to achieve the dynamic
scoping nature (and thus achieving one of those goals without having to
make further changes to the python "core" like changing the grammar
would):

def test():
def my_codeblock() [block]:
assert(y == x * 2)

for (x,y) in [(1,2), (2,4), (3,6)]:
my_codeblock()
 
Reply With Quote
 
Joe Mason
Guest
Posts: n/a
 
      04-14-2004
In article <(E-Mail Removed)>, Glenn Andreas wrote:
> Or is the point of the codeblock to execute in the same scope as where
> it is called (i.e., dynamic scoping).


Why not just pass parameters? Dynamic scoping is a pain because it
introduces rules you need to remember. Ruby's already decided their
rules were wrong and they need to change them for version 2.0.

> def test():
> def my_codeblock() [block]:
> assert(y == x * 2)
>
> for (x,y) in [(1,2), (2,4), (3,6)]:
> my_codeblock()


I still don't see the advantage over

def test():
def my_func(x, y):
assert(y == x * 2)

for (x, y) in [(1,2), (2,4), (3,6)]:
my_func(x, y)

With more parameters it'd be more convenient, but also much easier to be
sloppy.

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

Joe> I still don't see the advantage over

Joe> def test():
Joe> def my_func(x, y):
Joe> assert(y == x * 2)

Joe> for (x, y) in [(1,2), (2,4), (3,6)]:
Joe> my_func(x, y)

Joe> With more parameters it'd be more convenient, but also much
Joe> easier to be sloppy.

Add z = 10 to the would-be block my_func, and you'll see the
difference. With statically scoped block semantics (instead of
function semantics), it would bind z as a local variable in test,
instead of local variable in my_func. It's not possible with functions
currently, because binding it in my_func makes it a local variable in
my_func.

Of course the cleanest option of all would be the ability to
explicitly specify variables as 'free variables' so that binding them
wouldn't make them local variables, i.e.:

def f():
x = 10
def inner():
freevar x
x = 4 # bind in f
y = 5 # bind in inner

def promiscuous(param):
freevar * # all vars except param are free - so this
# is essentially a "block"!
x = 45 # bind in f
y = 12 # bind in f
z = 12323 # bind in f

--
Ville Vainio http://tinyurl.com/2prnb
 
Reply With Quote
 
Glenn Andreas
Guest
Posts: n/a
 
      04-14-2004
In article <(E-Mail Removed)>,
Joe Mason <(E-Mail Removed)> wrote:

> In article <(E-Mail Removed)>, Glenn Andreas
> wrote:
> > Or is the point of the codeblock to execute in the same scope as where
> > it is called (i.e., dynamic scoping).

>
> Why not just pass parameters? Dynamic scoping is a pain because it
> introduces rules you need to remember. Ruby's already decided their
> rules were wrong and they need to change them for version 2.0.
>
> > def test():
> > def my_codeblock() [block]:
> > assert(y == x * 2)
> >
> > for (x,y) in [(1,2), (2,4), (3,6)]:
> > my_codeblock()

>
> I still don't see the advantage over
>
> def test():
> def my_func(x, y):
> assert(y == x * 2)
>
> for (x, y) in [(1,2), (2,4), (3,6)]:
> my_func(x, y)
>
> With more parameters it'd be more convenient, but also much easier to be
> sloppy.
>
> Joe


how about:


def test():
def my_codeblock() [block]:
z += x * y

z = 0
for (x,y) in [(1,2), (2,4), (3,6)]:
my_codeblock()
print z

In this way, code blocks can be used like macros (except not expanded at
compile time), in that they can change the context that they are called
in.

If one figured out a good, clean way to make anonymous code blocks that
could be passed as expressions, you could then make new control
structures (after all, in Smalltalk, all control structures are
implemented using codeblocks):

def switch(expr, cases, default = None):
if cases.has_key(expr):
cases[expr]()
elif default:
default()


z = 0
switch(x+y,
{ 4 : def[block]:
z = 4
5 : def[block]:
z = 10
}
default = def[block]:
z = 20
)
print z
 
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