How to adopt "Python Style" indentation for Ruby

Why do I get the impression that this thread is trying to develop a
new language called FrankenRuPy?


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On 5/22/07, M. Edward (Ed) Borasky [email protected] wrote:

I really want it to be “attribute_accessor person”
I assume you meant attr_accessor which is a method which takes one or
more symbols or strings and generates methods with names based on
those strings which reference instance variable names based on those
strings.

attr_accessor person

would use the VALUE of the variable person as the name, and since
person would likely not be defined yet, that value would be nil.

– the constant
mixing of the same name with and without a preceding colon in Ruby is as
confusing to me as Perl’s “$hash{‘key’}” referring to an entry in
“%hash” vs. another variable entirely called “$hash”.

I won’t comment on perl’s use of sigils in this regard.

  1. Both curly braces and begin / end pairs to define scope, with one
    variant having a higher binding priority than the other. The fact that I
    don’t even remember which one it is that has the higher binding priority
    is an added factor in my dislike.

I think there’s some misunderstanding here.

Curly braces are used to denote a proc, begin/end delimits a sequence
of expressions which are executed in sequence and whose value is the
last expression executed. Begin blocks are usually used with internal
rescue clauses for exception handling. The pickaxe classifies
begin/end as an operator with low precedence thus

a  * fred  + begin
    puts "Hi mom"
    5
end

is evaluated as

(a  * fred ) + (begin
    puts "Hi mom"
    5
end)

{} and do/end aren’t operators, but in almost all cases delimit procs
and so the question of their relative priority is moot as far as I can
tell since you can’t have two procs next to each other in ruby source.

As for the ‘binding priority’ of {} vs. begin/end, I’m not sure I can
think of a legal situation in which the sequence

{...} begin...

could even occur in ruby code with no line break before the begin.
But I could be wrong.

There are some others, but those are the two biggies. I’m slowly getting
used to semicolons as separators and open syntactic forms forcing a
continuation, but even those irritated me at first when I started
learning R after spending a number of years with Perl.

When learning a language, I think that it’s best to work with these
irritations until the logic of why they are there starts to reveal
itself with experience. Fighting it just inhibits learning how to
think in the new language.

I wouldn’t expect that English should be changed so that the order
natural of his nouns and his adjectives in her sentences would be
reversed; or that the articles before all of his nouns should be
required; or that the genders should be assigned to all his nouns, or
that the pronouns possesive should agree in the gender with the
possession instead of the possessor; to make her more natural to
speakers native French.

Language design involves a careful balancing of several factors. I
think that both Matz and Guido did admirable jobs in designing and
evolving Ruby and Python respectively, each with a different set of
principles.

Even Shakespeare stuck to the English rules when he wrote in English,
and the French rules when he wrote in French. unless he was trying for
comic effect as when Katharine’s lady-in-waiting, Alice was teaching
her English in Henry V.

Personally, I’d prefer to let Ruby be Ruby, and Python be Python, or
as the French say: Vive la difference!

Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

shows a partial solution to your challenge by overloading require. It is
a quick hack but shows you how to write your own pre-processor. The
new require checks to find files of type .pyrb and then coverts them
to .rb files before loading them.

Neat! So all you do is write .pyrb files and you’re good to go. And it
works basically by putting the tabs on a stack and using that to drive
the number of ends.


Giles B.

I’m running a time management experiment: I’m only checking e-mail
twice per day, at 11am and 5pm. If you need to get in touch quicker
than that, call me on my cell.

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org

Hi –

On Tue, 22 May 2007, Brad P. wrote:

                       pre do

which gives it a feel like a YAML file.

I prefer Ruby files that feel like Ruby files (why is everyone so
concerned with trying to figure what, other than Ruby, Ruby should
look like?), but meanwhile if you use standard indentation (and get
rid of the extraneous end in your example :slight_smile: it looks a lot nicer to
start with:

 table do
   @components.each do |row|
     tr do
       row.each do |col|
         td do
           pre do
             text col
           end
         end
       end
     end
   end
 end

David

Eric M. wrote:

If you change this:
stack.push indent
Unfortunately, this isn’t too easy to implement in a formal parser
puts i

In this example, you get rid of 3 lines and 9 symbols/identifiers (and
add the 3 ":"s) compared to the original ruby.

All of these “:” solutions would have potential incompatibilities with
the ? : operator and :symbol.

I think I would prefer the leaving the ‘do’ in and keeping the rubish
syntax. It will avoid the potential for the conflicts that you describe.

though I do like the economy of

def foo :
[1,2,3,4].each : i
puts i
[1,2,3,4].each : i
puts i

Perhapps another symbol other than :

On Wed, May 23, 2007 at 04:28:45AM +0900, Eric M. wrote:

On 5/22/07, Brad P. [email protected] wrote:

I am not concerned really either way with the indentation thingie. I
don’t think that is the main difference between python and Ruby. In my
op’ the fact that Python does not do generic blocks is the main arguing
point. I am not sure why the indentation issue raises so much heat.

Agreed. Indentation vs. other ways of delimiting code blocks is just
a surface issue. For the most part, it is just a preference thing.

That’s why it draws so much heat: it’s a preference thing. People foo
don’t like finding a language that suits their preferences, getting into
it and really getting familiar with it, then having someone bar come
from another language’s norms to start suggesting it should be changed
to suit their (foo’s) preferences less well. Meanwhile, other people
bar who find a language that suits their preferences really well start
wanting to go around to all other languages they use and start
recommending those languages be modified to suit their preferences,
regardless of the fact that these other languages probably suit the
preferences of other people foo who already use them. It relates to the
fact that everyone wants to believe his or her preferences are “right”
and others’ are “wrong”.

The term “religious war” or “holy war” in relation to programming
languages, vi/emacs/VisualStudio, et cetera, is disturbingly appropriate
because of the root psychological causes in common between these
arguments over preferences and those over religious observance
preferences, I think.

The lack of a real lambda (and its verbose syntax compared to ruby
blocks) in python is a much bigger issue. I still think python’s
crippling of the lambda has to do with the indentation thing. The way
they did it, indented code blocks (“suites”) are only part of
statements (not more generic expressions). Since a lambda is an
expression (probably used in an enclosing statment), it doesn’t get to
have generic code blocks. With some rework, blocks delimited by
indentation don’t have to be so limited.

I remember reading that Guido just flat-out stated once that lambdas
would never be allowed to have more than one line, as though he simply
felt that multi-line lambdas were “bad” somehow. I don’t know if the
reasoning you suggest might have been behind it, but the way I read it,
it seemed like Guido is interested in mandating certain restrictions to
enforce his ideas of good programming practice. The assumption there
would be that he believes multi-line lambdas interfere with some aspect
of good programming practice – probably something to do with human
readability. He might also simply want to discourage people from using
lambdas where objects “should” be used instead. I could just be
misinterpreting the motivation, of course.

[email protected] wrote:

   table do
       end
                   td do :

rid of the extraneous end in your example :slight_smile: it looks a lot nicer to
start with:

I am not concerned really either way with the indentation thingie. I
don’t think that is the main difference between python and Ruby. In my
op’ the fact that Python does not do generic blocks is the main arguing
point. I am not sure why the indentation issue raises so much heat.

What interests me about this thread is that, if you wish,
you can transparently add your own dialect to ruby by overloading
require. I’ve done the same thing before to load ERB files as if
they were real ruby files on the path. I jumped in at the challenge
of the OP as to whether transparent preprocessing is possible. The fact
that it is and so simply is a nice sign of the power of the ruby
language.

B

Chad P. wrote:

scientist that created it, and attract the attention of the townsfolk
who will come with torches and pitchforks to kill the beast! Oh noes!

Oh, wait, that’s the plot of an old book. Never mind.

I upgraded the little library so that it has better error detection
and can handle else, end and rescue dedents even if the colon : eol
operator has been used.

http://xtargets.com/snippets/posts/show/68

def foo:
[1,2,3,4].each do |i|:
puts i
[1,2,3,4].each do |j|:
puts i
if i == 2 :
puts “foo”
else:
puts “bar”

is now possible. BTW if this triggers a rubyforge project I do like
the name “Frankenrupy”, Rick!

On May 21, 6:42 pm, “Giles B.” [email protected] wrote:

Giles B.

I’m running a time management experiment: I’m only checking e-mail
twice per day, at 11am and 5pm. If you need to get in touch quicker
than that, call me on my cell.

Blog:http://gilesbowkett.blogspot.com
Portfolio:http://www.gilesgoatboy.org

Google groups seems to be broken. My posts do not appear. Just seeing
if this gets throught. My other post was via a different news agent.

Hi –

On Wed, 23 May 2007, M. Edward (Ed) Borasky wrote:

variable entirely called “$hash”.
That’s not a syntax vagary, though. Consider:

class C
x = “y”
attr_accessor x
end

C.new.y = 1

You only get the “inert” identifier behavior with keywords

x = 1
def x # not 1, of course
end

alias old_x x # ditto

attr_accessor is just using normal method-argument syntax/semantics.

David

On Wed, May 23, 2007 at 12:27:21AM +0900, Rick DeNatale wrote:

 end

Or anywhere in-between.
For the sake of readability, I’d probably lean more toward:

table do
@components.each do |row|
tr do
row.each {|col| td { pre { text col } } }
end
end
end

. . . or something like that. Up to three layers of any one type of
delimiter and up to sixty characters or so width seem to be fine for
parsing by eye, and splitting brace-delimited lines over several lines
in Ruby just looks wrong somehow. Maybe that’s just me, though.

On 5/21/07, Brad P. [email protected] wrote:

I’ve tried posting several times without success … here again.

http://xtargets.com/snippets/posts/show/68

shows a partial solution to your challenge by overloading require. It is
a quick hack but shows you how to write your own pre-processor. The
new require checks to find files of type .pyrb and then coverts them
to .rb files before loading them.

If you change this:

            if l =~ /:\s*$/
                stack.push indent
                l.gsub! /:\s*$/,''
            end

to this:

            if l.sub!(/(\|[^\|]*\|)\s*:\s*$/,' do \1') or 

l.sub!(/:\s*$/,‘’)
stack.push indent
end

your example won’t need the do’s:

def foo:
[1,2,3,4].each |i|:
puts i
[1,2,3,4].each |i|:
puts i

Unfortunately, this isn’t too easy to implement in a formal parser
though, since the “|” after each initially looks ambiguous with the
“|” operator. The “:” to start the indentation style block should
probaly be where the “do” or “{” used to. You could even get rid of
the || by using “:” to start the args and “\n” to end the args (you’d
need an exlicit * to mean don’t care about the args):

def foo :
[1,2,3,4].each : i
puts i
[1,2,3,4].each : i
puts i

In this example, you get rid of 3 lines and 9 symbols/identifiers (and
add the 3 ":"s) compared to the original ruby.

All of these “:” solutions would have potential incompatibilities with
the ? : operator and :symbol.

Brad P. wrote:

What if it does? It might accidentally cause the death of the mad

        puts "bar"

is now possible. BTW if this triggers a rubyforge project I do like
the name “Frankenrupy”, Rick!


Brad P.
http://xtargets.com

In general I think that above is not a good idea for Ruby. However it
does look good when dealing with libraries like Markaby where the number
of closing ends starts to look very scary From some of my own templates

     table do
         @components.each do |row|
             tr do
                 row.each do |col|
                     td do
                         pre do
                             text col
                         end
                     end
                 end
             end
         end
     end
 end

whereas it could look like

     table do :
         @components.each do |row| :
             tr do
                 row.each do |col| :
                     td do :
                         pre do :
                             text col

which gives it a feel like a YAML file.

On 5/21/07, Brad P. [email protected] wrote:

though I do like the economy of

def foo :
[1,2,3,4].each : i
puts i
[1,2,3,4].each : i
puts i

Perhaps another symbol other than :

:: could work. As long as it is not followed by an identifier
character it shouldn’t collide. You could use this code for starting
the block:

            if l.sub!(/::\s*$/,'') or l.sub!(/::\s+(.*)$/,' do 

|\1|')
stack.push indent
end

and then this should work:

def foo ::
[1,2,3,4].each :: i
puts i
[1,2,3,4].each :: i
puts i

With this code, to do the equivalent of do…end w/o args you’d need
an explicit do before the :: . This could be fixed in a real parser
since it would know whether the block is for a builtin
def/while/if/class statement versus a standard lambda block. In the
lambda block context maybe you’d want “::\n” to mean “do ||” and use
“:: \n" to mean "do ||” (which is equivalent to a block without
args). Otherwise you couldn’t get the equivalent of “do ||”.

On 5/22/07, Joel VanderWerf [email protected] wrote:

foo bar do end
foo bar { }

END

Output:

FOO
BAR

Fair enough, I’ll file that in the “you learn something new every day”
file. Actually the more I learn the better the day.

I haven’t run into this since my preference is to parenthesize
arguments unless it’s part of a DSL. So I would have coded:

foo(bar) {}
foo(bar) do…end
or
foo(bar {})
foo(bar do…end)

Thanks!


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Eric M. wrote:

of the OP as to whether transparent preprocessing is possible. The fact
statements (not more generic expressions). Since a lambda is an
expression (probably used in an enclosing statment), it doesn’t get to
have generic code blocks. With some rework, blocks delimited by
indentation don’t have to be so limited.

Recently python allowed it’s yield statement to be an expression
and return a value.

a = ( yield b )

However I cannot see a useful way to use that from within python
as there is no intuiative way for the code block to return a value.
The only way to take advantage of it is the nonintuitve
coroutine syntax ala generator.send ( … )

http://docs.python.org/whatsnew/pep-342.html

I don’t see a fundamental reason that Python could not be extended
to have generic blocks ala Ruby but from reading some of the PEP’s
it seems to be a deliberate design decision to avoid generic blocks.
The rationale as I have understood it is that generic blocks hide
looping constructs which should be explicit ( foreach ).

 http://www.python.org/dev/peps/pep-0343/
 """
 PEP 340, Anonymous Block Statements, combined many powerful ideas:
 using generators as block templates, adding exception handling and
 finalization to generators, and more.  Besides praise it received
 a lot of opposition from people who didn't like the fact that it
 was, under the covers, a (potential) looping construct.  This
 meant that break and continue in a block-statement would break or
 continue the block-statement, even if it was used as a non-looping
 resource management tool.
 """

Read the full PEP 343 to see the lengths that are gone to to implement
this. However I am curious to see some more knowledgeable Ruby people
explain how Ruby deals with the concerns raised by the Python guys. Some
of the issues are the usage of break and continue within blocks. Does
continue/break used from within a block continue/break the block or the
most local for loop. I haven’t tried myself to see what happens.

[email protected] wrote:

        td do

David

But I want a blue bike shed next to my nuclear power plant.

Anyhow, here’s a couple of examples of things pretty much “standard
Ruby” that I still find confusing coming from other descendants of Algol
60 syntax:

  1. attribute_accessor :person

    self.person = “Ed”

I really want it to be “attribute_accessor person” – the constant
mixing of the same name with and without a preceding colon in Ruby is as
confusing to me as Perl’s “$hash{‘key’}” referring to an entry in
“%hash” vs. another variable entirely called “$hash”.

  1. Both curly braces and begin / end pairs to define scope, with one
    variant having a higher binding priority than the other. The fact that I
    don’t even remember which one it is that has the higher binding priority
    is an added factor in my dislike.

There are some others, but those are the two biggies. I’m slowly getting
used to semicolons as separators and open syntactic forms forcing a
continuation, but even those irritated me at first when I started
learning R after spending a number of years with Perl.

On Tue, May 22, 2007 at 07:05:04AM +0900, Brad P. wrote:

Rick DeNatale wrote:

Why do I get the impression that this thread is trying to develop a
new language called FrankenRuPy?

Now, now! It’s just a sweet little creation. It couldn’t hurt anyone
could it ?

What if it does? It might accidentally cause the death of the mad
scientist that created it, and attract the attention of the townsfolk
who will come with torches and pitchforks to kill the beast! Oh noes!

Oh, wait, that’s the plot of an old book. Never mind.