Pythonic indentation (or: beating a dead horse)

R

Roger Pack

print 3
Nifty! Thanks.

Appears I went too far--this is enough:

class Object
def print *args
super *(args + [" :)"])
end
end3 :)=> nil

This works because
=> [A, Object, Kernel]

when it searches for the print it first looks in the current class, then
in Object, then in Kernel. Object now defines it, then "supers" to
Kernel.
Aside from the fact that this wouldn't solve the problem that I'd
still have to _write_ the damned things, this is possibly the
kludgiest solution imaginable.

Whoa turbo we're all trying to be respectful.

So this could be:
arra.collect do |a|:
pass
.reject do |b|:
true


gotcha. That looks nice in terms of return values. I guess the actual
problem was better described by Tony in his other post, I misled you.
The other concern is that "the allure of magic indentation wears thin
for large docs" which fact "worked to ensure you kept your methods
short."[1]

Well, all I can say is, that's his opinion. Hasn't lost its allure for
me. And if it did lose its allure, I would think that it wouldn't be
for large docs, it would be for deeply _nested_ docs. I definitely
sympathize with his mockery of the notion that this limitation is a
blessing in disguise because it encourages you to keep your methods
short... it reminds me of how I felt when I first heard that Java's
lack of pointers meant you couldn't write any pointer bugs. But my
employer imposes a strict 80-column limit on source files including
Python, we have a lot of Python code, and it all works out.

How well does it work out? Any drawbacks?
You keep on saying this, yet I have not seen one example of code that
demonstrates that using dedent couldn't work. Basically, we're looking
for some code which, if you removed the all ends, a script following
simple deterministic rules would not be able to unambigiously decide
where to put them back. I agree that "put an end wherever you see a
dedent" is naive and wouldn't work... but "put an end wherever you see
a dedent which isn't followed by a keyword which extends the current
expression, such as elsif or rescue or ensure" might.

Sounds good--code it up and I'll give it a try (as Joshua said).
Persuade via code! :)

Make sure you write it in Ruby though no cross contamination! <said
tongue in cheek>

It will be interesting to code some ruby that looks like Python.
Anybody else know of projects that allow for this? (pre processors)

Thanks.
-=r
 
T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

You keep on saying this, yet I have not seen one example of code that
demonstrates that using dedent couldn't work. Basically, we're looking
for some code which, if you removed the all ends, a script following
simple deterministic rules would not be able to unambigiously decide
where to put them back. I agree that "put an end wherever you see a
dedent" is naive and wouldn't work... but "put an end wherever you see
a dedent which isn't followed by a keyword which extends the current
expression, such as elsif or rescue or ensure" might.

Okay, you just want an example I guess. Code speaks louder than words!

Here is an example Ruby program:

foo = [1,2,3]
x = foo.map do |n|
n += 1
n *= 2
end
result = case x
when Array
x.map! do |n|
n *= 3
n += 4
end
when NilClass
x
end
result = if result.size > 10
result[0..2]
else
result
end
p result

The output of this program is:

[16, 22, 28]

Show me how you would parse the equivalent program in an
indentation-sensitive Ruby, e.g.:

foo = [1,2,3]
x = foo.map do |n|
n += 1
n *= 2
result = case x
when Array
x.map! do |n|
n *= 3
n += 4
when NilClass
x
result = if result.size > 10
result[0..2]
else
result
puts result

I'd be particularly interested in solutions which can be parsed with a LALR,
LL*, or PEG parser. The approach you're describing does not sound like it
could be expressed as a CFG, not that there isn't a CFG solution for this,
just that the one you're proposing is not.
 
G

Gregory Brown

editor.

But, the amount of meaningful code displayed in a single screenshot
still suffers. =A0A screenful is a chunk of code
you can see without scrolling or jumping. =A0The more meaning it
contains, the better you understand the code (as long as the meaning
is cleanly laid out, of course).

I still think this is a straw man. I'm rarely concerned with the
'readability' of a whole page of code.
I feel like there is something wrong with my design when I have to
think at that level.

For what it's worth, I actually can care less whether whitespace is
significant or not. Significant whitespace doesn't bother me in Haml.
The lack of significant whitespace doesn't bother me in Ruby.

What does bother me is that people somehow think this issue is so
important and dire, yet they think it's someone else's job to fix it.
If you want Ruby with significant whitespace, build it. Don't try to
convince folks who don't care about the issue.

-greg
 
J

Juan Zanos

I didn't accidentally illustrate anything. And everything has a
cost. Why don't you list for yourself the cost of editing code with
significant white space?
Maybe for you, those costs are irrelevant. For me, the costs of ends
in Ruby code are irrelevant.

But your point was about *readability* not maintainability. I don't
think that good project organization is a 'cost' to readability.


I'm saying that when all other factors are held constant more lines is
less readable. Your arguments ignore that and only place value on
editors and project management when the extra lines exist and
not when they don't. That's not a level playing field.

Thinking about ways to reduce this overhead in the language is good.
 
G

Gregory Brown

I'm saying that when all other factors are held =A0constant more lines is
less readable. =A0Your arguments ignore that and only place value on
editors and project management when the extra lines exist and
not when they don't. =A0 That's not a level playing field.

You're right. I should note that better design also mitigates most
of the concerns about the problems of whitespace significance (for
me).
But that doesn't invalidate my feeling that this whole stirrup about
'readability' is a straw man at best, and an indication of a poor
ability to write clean code without extra help at worst.
Thinking about ways to reduce this overhead in the language is good.

And implementing them is great. Because it solves your problem for
you, and does not require convincing others that it is a problem.
Those who do find this desirable will use it. So what's stopping you?

-greg
 
G

Gary Wright

The obvious solution is for us to find some red matter, form a black
hole, toss in Matz and Guido, have them confront their younger selves,
and see who wins in the Language Wars 2.0 timeline.

Gary Wright
 
T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

I'd be particularly interested in solutions which can be parsed with a
LALR,
LL*, or PEG parser. The approach you're describing does not sound like it
could be expressed as a CFG, not that there isn't a CFG solution for this,
just that the one you're proposing is not.

And here's what exacerbates the problem in a CFG: in a grammar like Ruby,
things like case statements, if statements, and method calls with blocks are
among what I believe is the lowest precedence set of operations. In Python,
statements with indent blocks are among the highest precedence operations.

So we can do things where expressions with indent blocks need to be lower
precedence, and that's where the proverbial shit really starts to hit the
fan. How would you parse this, for example?

n = 2 * -[1,2,3,4,5].inject(0) do |a, b|
c = a * 2
a * c + b
result = 8 * -if n > 0
-n += 10000
else
n + 500000
puts result

And just as a matter of personal preference, I find the above with end
statements more readable:

n = 2 * -[1,2,3,4,5].inject(0) do |a, b|
c = a * 2
a * c + b
end
result = 8 * -if n > 0
-n += 10000
else
n + 500000
end
puts result
 
T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

I'd be particularly interested in solutions which can be parsed with a
LALR,
LL*, or PEG parser. The approach you're describing does not sound like it
could be expressed as a CFG, not that there isn't a CFG solution for this,
just that the one you're proposing is not.

And I guess I just can't shut up about this: your solution would require a
scanner with some degree of grammatical awareness for every expression which
contains an indent block. When you start talking about a solution like
that, I really think you're going down a rabbit hole.

I'll refer to Guido van Rossum on this one:
The unspoken, right brain <http://en.wikipedia.org/wiki/Right_brain>constraint here is that the complexity introduced by a solution to a design
problem must be somehow proportional to the problem's importance. In my
mind, the inability of lambda to contain a print statement or a while-loop
etc. is only a minor flaw; after all instead of a lambda you can just use a
named function nested in the current scope.

But the complexity of any proposed solution for this puzzle is immense, to
me: it requires the parser (or more precisely, the lexer) to be able to
switch back and forth between indent-sensitive and indent-insensitive modes,
keeping a stack of previous modes and indentation level. Technically that
can all be solved (there's already a stack of indentation levels that could
be generalized). But none of that takes away my gut feeling that it is all
an elaborate Rube Goldberg contraption<http://www.rube-goldberg.com/html/gallery.htm>
.
You are proposing a Rube Goldberg contraption whereby the scanner would
require some degree of grammatical awareness. This is a complex solution.
The minor flaw is that you don't like "end" statements. Is the minor flaw
of having repeated end statements really worth the level of complexity the
solution would require?
 
J

Juan Zanos

You're right. I should note that better design also mitigates most
of the concerns about the problems of whitespace significance (for
me).
But that doesn't invalidate my feeling that this whole stirrup about
'readability' is a straw man at best, and an indication of a poor
ability to write clean code without extra help at worst.

So you have better designs compared to those who seek further
conciseness in a language. If only those folks of poor ability could
design so well as you.
 
G

Gregory Brown

On May 20, 2009, at 5:41 PM, Gregory Brown wrote:

So you have better designs compared to those who seek further conciseness= in
a language. =A0If only those folks of poor ability could design so well a= s
you.

That's right. I'm pretty awesome. Maybe RubyTalk can throw a party
in honor of me!

(But seriously, I'm just saying that design is multi-faceted, and
conciseness isn't a single pointed goal one can optimize for to any
great effect)

-greg
 
S

Steven Arnold

And you're on a mailing list full of people who find that the Ruby-way
makes sense to them. Don't knock it until you've tried it.

Just to kick in on this, I am a long-time Ruby programmer and Ruby is
my favorite language. I'd rather see full-strength macros than
optional removal of 'end' keywords. Having said that, let me admit I
do not know how complex it would be to implement a solution in Ruby
that optionally omits ends. Some have argued, with what seem like
plausible reasons, that it might be hard. Others have attempted to
rebut those reasons. I agree with the calculus that if it is very
difficult, it is not worth the benefit. If it is easy, I'd like to be
able to omit the 'end' statements. They are line noise to me
visually. They just get in the way.

Another concern I have about this idea, though, is having essentially
two forks of Ruby lexically speaking. It's not much of an obstacle,
but it is a minor difference that someone who comes along later to
maintain your code might find confusing or off-putting. And even
though this particular change might be relatively minor, where do we
draw the line? What makes us decide whether another optional syntax
change should be integrated into the language? Even many small
changes add up to a big difference in the way the code looks and the
ease of maintainability.

I guess, however, this is no more serious than the positioning-of-
brackets debate in C or even whether bracketless 'if' statements
should ever be used, e.g.:

if (foo)
bar();
baz();

The 'baz' function will execute regardless of the value of foo; this
code is therefore visually confusing.

Macros, as I suggested above, would _really_ move in the direction of
potential Ruby code that looks radically different. But the payoff
would be enormous expressive power, the ability to mold the language
to suit the application domain in a very comprehensive way. The
removal of 'end', by contrast, would be only a slight improvement. It
would remove some visual noise and might attract a few Python
programmers. As I said, I think it's worth it if it's easy to
implement, but not if it's more difficult.

steven
 
B

Bill Kelly

From: "Tony Arcieri said:
I'll refer to Guido van Rossum on this one:

I think this helps illustrate the degree of subjectivity
involved in how varying people regard this issue.

For me, I've written sufficient Python code in years past
to have concluded that significant indentation adds too
much rigidity to the language for it to feel like an
acceptable trade-off for what it accomplishes.
(The mere existence of the 'pass' keyword is slightly
eye-rolling to me.... presumably similar to how others
may feel about a raft of closing 'end' statments.)

My preferences are opposite to Guido's, above. A flexible
lambda, for instance, is *far* more important to me than
what I consider to be a minor nuisance of nested 'end'
statements. (And non-nested 'end' statements don't bother
me at all. Some percentage of extra scrolling in the
editor isn't of any relative importance to me.)

As far as nested 'end' statements, one thing I've been
trying lately is to define the module hierarchy at the top
of the file, then qualify the class name so that nesting
is avoided. Like,

module CILA end
module CILA::SVC end

class CILA::SVC::Hub

# ........ methods here as usual ........

end

class CILA::SVC::HubClientConn

# ........ methods here as usual ........

end

So far I'm pretty happy with this approach.


Regards,

Bill
 
T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

My preferences are opposite to Guido's, above. A flexible
lambda, for instance, is *far* more important to me than
what I consider to be a minor nuisance of nested 'end'
statements. (And non-nested 'end' statements don't bother
me at all. Some percentage of extra scrolling in the
editor isn't of any relative importance to me.)


Well, to be fair to Guido, in the case of Python it already has indent-based
syntax. The language is already structured in a way that precludes indent
blocks in expressions, and to him the problem of adding multi-line indented
expressions is a far more difficult tradeoff as compared to changing some
fundamental assumptions of the language.

However, to a Rubyist, taking away multi-line blocks would be a cardinal
sin...
 
R

Roger Pack

Another concern I have about this idea, though, is having essentially
two forks of Ruby lexically speaking. It's not much of an obstacle,
but it is a minor difference that someone who comes along later to
maintain your code might find confusing or off-putting. And even
though this particular change might be relatively minor, where do we
draw the line? What makes us decide whether another optional syntax
change should be integrated into the language? Even many small
changes add up to a big difference in the way the code looks and the
ease of maintainability.

Good point. There might be a way to go back and forth between the two,
though,if that were any help.
i.e.
a = proc { 3+3 }.
a.to_ruby_indented.to_ruby or what not (viz ruby2ruby).

And the authors of gems using this syntax could require them
transparently, i.e.
some method like require_indented 'filename' or what not.
Macros, as I suggested above, would _really_ move in the direction of
potential Ruby code that looks radically different. But the payoff
would be enormous expressive power, the ability to mold the language
to suit the application domain in a very comprehensive way. The
removal of 'end', by contrast, would be only a slight improvement. It
would remove some visual noise and might attract a few Python
programmers. As I said, I think it's worth it if it's easy to
implement, but not if it's more difficult.

Interesting--it's been awhile since I used C...what would
macros...essentially do? An example of them?

Tgarding the OP suggestion: I think it's an interesting idea. Start
something for it on github and I'd be happy to help out. Here's some
resources for it:
http://ruby-toolbox.com/ "testing frameworks"


The only real concern with it is that there is may be ambiguity if
someone were to use the "a ? b : c" syntax (whatever it's called) and
split that onto multiple lines just the "perfectly wrong way"

a ? b :
c

Then that would break a naive pre processor. But not many people I know
split those constructs across multiple lines, and they definitely
wouldn't within a file they know to be using "ruby indented blocks" or
whatever you want to call it. There's also the possible collision with
1.9's new symbol
b: == :b
but again, if you disallow that on end of line's then you're good to go.

Best of luck.
-=r
 
J

J Haas

Okay, you just want an example I guess.  Code speaks louder than words!

Here is an example Ruby program:

foo = [1,2,3]
x = foo.map do |n|
  n += 1
  n *= 2
end
result = case x
when Array
  x.map! do |n|
    n *= 3
    n += 4
  end
when NilClass
  x
end
result = if result.size > 10
  result[0..2]
else
  result
end
p result

The output of this program is:

[16, 22, 28]

Show me how you would parse the equivalent program in an
indentation-sensitive Ruby, e.g.:

Okay. But just to recap what's gone before: you've said all along that
Pythonic indentation in Ruby was impossible. It's impossible, because
it's incompatible with blocks. It's impossible, because everything's
an expression. It's impossible, because Guido said so. And I've asked
you over and over for an example demonstrating its impossibility.
You've had time to think it over, you were under no constraints, and
this is what you've come up with.

I found the old preprocessor script from awhile ago that I mentioned
earlier in this thread. I've pastebinned it at http://pastebin.com/m5fee1e92.
It's very short, and pretty simple. I have no doubt that it would need
a lot of work to be robust. (In particular, I think things need to be
added to the enumeration at line 68.)

But Tony, it blasted through your "impossible" example without
skipping a beat, working perfectly on the first try.

jhaas@littlefinger:~/pyruby$ cat pyrbtest.rb
__BEGIN__

# Look, ma! No ends!

foo = [1,2,3]
x = foo.map do |n|:
n += 1
n *= 2

result = case x:
when Array
x.map! do |n|:
n *= 3
n += 4
when NilClass
x

result = if result.size > 10:
result[0..2]
else:
result

p result
jhaas@littlefinger:~/pyruby$ irb
irb(main):001:0> require 'pyruby'
=> true
irb(main):002:0> require 'pyrbtest'
[16, 22, 28]
=> true

As I've said repeatedly, I don't follow your reasons for claiming that
this is impossible. Can you come up with a better demonstration?
 
J

J Haas

n = 2 * -[1,2,3,4,5].inject(0) do |a, b|
  c = a * 2
  a * c + b
end
result = 8 * -if n > 0
  -n += 10000
else
  n + 500000
end
puts result

__BEGIN__

n = 2 * -[1,2,3,4,5].inject(0) do |a, b|:
c = a * 2
a * c + b
result = 8 * -if n > 0:
-n += 10000
else:
n + 500000
puts result

Once again, worked perfectly on its first time through the
preprocessor.
 
J

J Haas

I found the old preprocessor script from awhile ago that I mentioned
earlier in this thread. I've pastebinned it athttp://pastebin.com/m5fee1e92.

Sorry for the repeated posts, but I forgot to mention: I did not write
this, although I did make minor modifications. I don't recall where I
found it, and Google was no help. I regret that I cannot credit the
author; should he happen to be reading this, speak up!
 
J

James Britt

Joshua said:
It's at this point that I started to wonder if you've had a look-see at
_why's new language, Potion? Specifically:

This from the guy who championed YAML?

(Side rant: interesting that so many Rubyists go ga-ga over magic
indentation in Yaml and Haml, but find the idea repulsive in Ruby.)

--
James Britt

www.jamesbritt.com - Playing with Better Toys
www.ruby-doc.org - Ruby Help & Documentation
www.rubystuff.com - The Ruby Store for Ruby Stuff
www.neurogami.com - Smart application development
 

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

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top