How to adopt "Python Style" indentation for Ruby

D

dblack

Hi --

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".

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

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
R

Rick DeNatale

But I want a *blue* bike shed next to *my* nuclear power plant. <ducking>

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"

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.
2. 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!
 
J

Joel VanderWerf

Rick said:
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.

Ed probably meant do...end, not begin...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.

This is the precedence issue:

def foo(*)
puts "FOO" if block_given?
end

def bar(*)
puts "BAR" if block_given?
end

foo bar do end
foo bar { }

__END__

Output:

FOO
BAR
 
B

Brad Phelan

Hi --



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 :) 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
 
R

Rick DeNatale

This is the precedence issue:

def foo(*)
puts "FOO" if block_given?
end

def bar(*)
puts "BAR" if block_given?
end

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!
 
E

Eric Mahurin

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.

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

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.
 
G

Giles Bowkett

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.

As the OP in this thread, but not the one it spawned from, I just
wanted to turn the question from whether or not Ruby should be Python
to **how** to make Ruby Python if one so chose. I wouldn't really do
it myself, but the question of how is a pretty interesting question
(and also one which has less risk of generating flame wars).

A few months back, during the Fizzbuzz craze, I saw a Fizzbuzz solver
which worked by defining a algorithm in Haskell which ran in a Haskell
interpreter which ran inside a Lisp interpreter which ran inside
another Lisp interpreter which was written in Ruby. Sometimes the
question of how to do something is interesting for its own sake,
whether the thing is worth doing or not.

--
Giles Bowkett

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
 
B

Brad Phelan

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

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.

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.
 
C

Chad Perrin

And with the judicious use of {} vs. do end there are other
alternatives which may suit individual tastes depending on how tightly
you like to see the code:

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

or the ultra tight:

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

or if you aren't religious about reserving brackets for one-line
blocks (I'm not):

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

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.
 
C

Chad Perrin

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.
 
B

Brad Phelan

Giles said:
Obviously based on the earlier thread. I think this is actually an
utterly terrible idea. Haven't you heard that song by Loverboy? "Pig
and elephant DNA just don't mix"? But I think the **implementation**
would be fascinating.

What would it take to write a Ruby pre-processor which parsed Ruby
written in a Pythonic style and turned it into actual valid Ruby? Or
even a Ruby library like Xavier's Perl example, which allows you to
code Ruby as if it were Python after just requiring the library? The
original post's main argument was that indentation is a stable,
consistent shorthand for Ruby's end statements. If all you're looking
to do is use tabs as syntactic sugar, then it should be pretty easy to
just write something which knows how to translate a sequence of tabs
in and tabs out into a series of end statements at the end.

Is this only doable in Perl, because Perl has source filtering? Would
you have to encase the Pythonic "Ruby" in a string and then run that
string through a processor after the fact, or could it "just work"
without any obvious prep on the user's part? If you did it as a
string, it should be as easy as counting tabs. But source filtering,
that sounds like the better way.

Another version of pyrb.rb has been written that allows proper
multilevel dedenting and removes the requirement for a separate
..pyrb file

You can now do in test.rb


#####################################
require 'pyrb.rb'
__END__

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"


foo
#####################################

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

Disclaimer : The above library in no way whatsoever should be taken as a
suggestion that the author thinks Python is better than Ruby or
vice versa. All suggestions to that effect are purely fictional and
the author is in no way responsible for flame wars that may ensue
from use or misuse of the library. The author wrote the library
because it could be done and for no other reason.
 
G

Giles Bowkett

Obviously based on the earlier thread. I think this is actually an
Another version of pyrb.rb has been written that allows proper
multilevel dedenting and removes the requirement for a separate
.pyrb file

This is absurdly cool. How does it work?

Oh I get it:
The trick to the new version is to use the __END__ keyword
to block the Ruby scanner and then reload the current file after
doing the preprocessing.

That's awesome! Sick and wrong in the best possible way. And **simple!**
 
B

Brad Phelan

This is absurdly cool. How does it work?

Oh I get it:


That's awesome! Sick and wrong in the best possible way. And **simple!**

Sick, wrong and simple but unfortunately not my idea. There is a library
hanging around called hyphen-ruby which showed me the dark path.

B
 
T

Trans

Sick, wrong and simple but unfortunately not my idea. There is a library
hanging around called hyphen-ruby which showed me the dark path.

B

Actually you can do this without even using the __END__. pyrb.rb can
exit the process so it will never reach the rest of the original file.

T.
 
T

Trans

Actually you can do this without even using the __END__. pyrb.rb can
exit the process so it will never reach the rest of the original file.

But then again, why bother? Just make a new executable called
'pyruby'. And use that to run your .pyrb scripts.

T.
 
B

Brad Phelan

Trans said:
Actually you can do this without even using the __END__. pyrb.rb can
exit the process so it will never reach the rest of the original file.

T.


I don't think that will work. I believe that Ruby will syntax check the
entire file before trying to execute any of it.
 
T

Trans

I don't think that will work. I believe that Ruby will syntax check the
entire file before trying to execute any of it.

Ah, right. Did something like this myself once but I had overlooked
the fact that my variant code still passed for valid ruby. In any
case, using a separate 'pyruby' runner would be the best way
regardless.

T.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top