Ruby blocks in Python, a suggestion

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Ville Vainio

    Ruby blocks in Python, a suggestion

    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(dbc onn) 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(e ntry * 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 :-).

    --
    Ville Vainio http://tinyurl.com/2prnb
  • Jeff Epler

    #2
    Re: Ruby blocks in Python, a suggestion

    I'm not convinced this will fly.

    First, of your examples, two are better expressed as loops or listcomps:[color=blue]
    >
    > foreach([(1,2), (2,4), (3,6)]) block(x,y):
    > assert y == X*2[/color]
    for x, y in [(1,2), (2,4), (3, 6)]:
    assert y == x*2
    [color=blue]
    > mapseq(seq) block(entry, result):
    > result.append(e ntry * 2)[/color]

    result += [entry*2 for entry in seq]

    Every block that is executed N times should be expressed today as a
    "for" loop or listcomp with the appropriate generator.

    [color=blue]
    > transaction(dbc onn) block(t): # commit/rollback t based on exception status
    > t.dostuff()[/color]

    I would swear there was a pep for a "with" statement, taking an object
    with special methods called at the top and the bottom of the statement.
    I can't find it, though. It would look something like this:
    t = transaction(dbc onn)
    with transaction(dbc onn):
    t.dostuff()

    Eery block that is executed exactly 1 time should be expressed today as
    t.acquire()
    try:
    block
    finally:
    t.release()
    or
    t.acquire()
    try:
    block
    except:
    t.rollback()
    raise
    else:
    t.commit()


    The second problem is that I don't know if the Python parser can
    accomodate your syntax. Your proposal doesn't mention the exact
    production(s) you would add or change to add your block statement.

    One way would be to make compound_stmt include a block_stmt alternative
    compound_stmt: block_stmt | if_stmt | ...
    block_stmt: test 'block' ['(' arglist ')'] ':' suite
    can you tell me if this is the way you imagined defining the new rule,
    and show me that this does not create a conflicting or ambiguous
    grammar? (the fact that Python prints "XXX ambiguity!" over and over
    again when I try to build the modified grammar doesn't bode well, but
    maybe it's just been too long since I toyed with the Python grammar..)

    Finally, what do "break" and "continue" do in blocks?

    Jeff

    Comment

    • John Roth

      #3
      Re: Ruby blocks in Python, a suggestion

      "Ville Vainio" <ville@spammers .com> wrote in message
      news:du7hdvwfiq t.fsf@lehtori.c c.tut.fi...[color=blue]
      > 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 :).[/color]

      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
      }

      The trick is that on encountering the opening brace the current
      indentation environment is suspended (stacked) and a new
      indentation environment is created. The left boundary of the
      new environment is the first non white-space character on the
      next non-comment line. The new indentation environment is
      released when the closing brace is encountered, and the prior
      one is reinstated.

      I'd like this form of function definition for interactive fiction (IF)
      games, since it allows me to create a function and put it into
      an instance with one operation, rather than having to create
      the function at the module level, and then bind it into the instance
      with another function call after the definition is complete.

      John Roth


      Comment

      • Hung Jung Lu

        #4
        Re: Ruby blocks in Python, a suggestion

        Ville Vainio <ville@spammers .com> wrote in message news:<du7hdvwfi qt.fsf@lehtori. cc.tut.fi>...[color=blue]
        > 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 :).
        > ...
        > foreach([(1,2), (2,4), (3,6)]) block(x,y):
        > assert y == X*2[/color]

        Ruby's block is quite a bizarre animal. It's amazing how people can
        make a big mess out of something so simple and so fundamental. A more
        useful concept is plain-vanilla codeblock. I have mentioned before
        syntax like:

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

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

        Which you actually can do in Python, if you replace the def statement
        with:

        my_codeblock = compile('assert (y == x*2)', '<string>', 'exec')

        ------------------

        Python's lack of compile-time, easily-debuggable codeblock is one of
        the obvious major shortcomings/mistakes of the language. Codeblocks
        are absolutely wonderful for metaprogramming , to the point of being
        essential. This topic has been discussed before, and I am not going
        back there. When people are short-sighted, there is no cure. :) Other
        people can take over the issue.

        regards,

        Hung Jung

        Comment

        • Hung Jung Lu

          #5
          Re: Ruby blocks in Python, a suggestion

          fnord@u.washing ton.edu (Lonnie Princehouse) wrote in message news:<f70e3538. 0404150929.2a66 2b0d@posting.go ogle.com>...[color=blue]
          >
          > # But now it's an idee fixe. Here we go again!
          > import inspect, re
          >
          > def block(f):
          > # won't work from stdin, function code must be in a file
          > # decompyle could help?
          > source = inspect.getsour ce(f)
          > source = source[source.index('\ n')+1:]
          > indent = re.search('^(\s +)\S',source).g roup(1)
          > source = re.sub('(?m)^%s ' % indent, '', source)
          > return compile(source, '<string>', 'exec')
          >
          > def my_codeblock():
          > z = x + y
          >
          > my_codeblock = block(my_codebl ock)
          >
          > for (x,y) in [(1,2), (2,4), (3,6)]:
          > exec my_codeblock[/color]

          Man, it's a hack all right, but what a brilliant one! :) Never ever
          seen anyone coming up with it.

          Sure, it's not debuggable in the sense that you can't place break
          points, and when there is an exception you won't see the exact line.
          However, this part can be solved by generating small files in the
          block() function, one per codeblock. Then, instead of '<string>', pass
          the file name. Not only you will be able to see the line where error
          happened, but you will also be able to put break points, or to step
          through the code lines. The only thing to remember is to know where
          you need to make the changes: not in the codeblock files, but in the
          original place of definition. :) This can be helped by pre-pending
          some explanatory messages in the codeblock files (pointing out the
          location of the original file, i.e., via inspect.getsour cefile() and
          inspect.getsour cefilelines()). Of course, in shipped products you'll
          suppress the generation of the codeblock files.

          It's functional. It's usable. It's compiler-checked. The refined
          version should be published as a recipe!

          Man! Wow! Triple Wow!

          regards,

          Hung Jung

          Comment

          • Michele Simionato

            #6
            Re: Ruby blocks in Python, a suggestion

            hungjunglu@yaho o.com (Hung Jung Lu) wrote in message news:<8ef9bea6. 0404071127.3c0b 263c@posting.go ogle.com>...[color=blue]
            > Python's lack of compile-time, easily-debuggable codeblock is one of
            > the obvious major shortcomings/mistakes of the language.[/color]

            Why ??
            [color=blue]
            > Codeblocks are absolutely wonderful for metaprogramming , to the point of
            > being essential.[/color]

            Why ??
            [color=blue]
            > This topic has been discussed before, and I am not going
            > back there. When people are short-sighted, there is no cure. :) Other
            > people can take over the issue.[/color]

            I have not followed in detail your discussion about code blocks, scattered
            in different threads in different times, so please point out to me the posts
            where your substain your claims.

            My experience with code blocks has been the following:

            1. At least one year ago I discovered on my own that Python has already
            run time code blocks.

            2. More or less at the same time I discovered the hack proposed by
            Lonnie Princehouse which I used to implement macros in Python as
            a proof of concept.

            3. I didn't find any compelling use case for both 1 and 2; actually I
            thought they were confusing and un-needed constructs, so after having
            implemented them, I forgot them.

            I may have been wrong about point 3. If so, please tell me why.
            Otherwise, please stop making unsubstained claims and give
            explanations and/or references to previous posts.


            Michele Simionato

            Comment

            Working...