Pythonic indentation (or: beating a dead horse)

R

Roger Pack

#if you actually need an end, that's allowed too
#(if not further outdented than the line that started the statement)
result = case ARGV[0]
when /^\d*$/
p "That's an integer!"
when /^[A-Za-z]*$/
p "That's a word!"
else
p "That's something that's not an integer or a word..."
end if ARGV[0]

#you can explicitly end just the last scope of something deeply nested.
class A
class B
class C
module D
foo
end #actually 4 ends


I assume that that end is optional, too?
end also doubles as the equivalent for Python's "pass", as well?
So you can have ends if you want them but they're optional? Does it
work with {}'s too?
So the basic rule it uses is that if something returns to the original
indentation level without being an end, it assumes it should have been
an end, is that right? (i.e. it *requires* blocks to be at a greater
indentation level).
Thanks just wondering.
-=r
 
J

J Haas

Oops, I should have done that when I posted before. Thanks for the reminder.

Fairly awesome. But I think we should consider keeping the colon, and
here's why: blocks that are not delimited by a colon at the start
behave exactly as normal Ruby blocks do, requiring an "end" to close
them, and more importantly ignoring indentation. That way, existing
code can be run through the preprocessor when it's "on", and will
continue to work. And it leaves people to pursue ASCII art with their
indentation, if they are so inclined.

Matz says the colon won't work as a delimiter, though. I'm curious to
know why, but even so, surely something would work.
 
J

James Britt

Reid said:
I find this code less readable than the above original code with the
'end's included

Same here.


Maybe, after enough exposure, I would get used to it, but I don't see
anything intrinsic to that format that would make it more readable, and
currently (for whatever reasons) the endian version is more readable for me.

FWIW, daring people to dispute what is ultimately a matter of opinion is
not terribly productive. I've had enough discussions with Haml lovers
to know that rounds of "But look how beautiful it is" vs "I find it
grating" go nowhere.

Maybe some verifiable proof that compulsory indentation makes for faster
apps or less buggy code or simpler IDE tool development or whatever
would make for a better case.

"I like it" lacks an element of persuasion.



--
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
 
J

Joshua Ballanco

No, it doesn't, because I don't see why case statements are not
transformable into indent-only blocks. I've _done_ them using the
quick-and-dirty hacky script and they work just fine. (In cases like
Joshua's impossible.rb I had to make a minor modification to the
script to have it inject 'end ' rather than 'end\n', but it still
worked fine.)

Ok, but now you're beginning to see the edge cases that make this sort
of transformation difficult on a global level. Specifically, how would
you differentiate between these two cases using Pythonic indentation:
cat conditional_case.rb
result = case ARGV[0]
when /^\d*$/
"That's an integer"
when /^[A-Za-z]*$/
"That looks like a word..."
else
"That's not an integer or a word"
end if ARGV[0]

puts result
cat case_and_conditional.rb
result = case ARGV[0]
when /^\d*$/
"That's an integer"
when /^[A-Za-z]*$/
"That looks like a word..."
else
"That's not an integer or a word"
end
if ARGV[0]
puts result
end


Attaching a conditional to the end of a case statement (or any block,
for that matter) is possible in Ruby because the block is just an
expression, and the statement doesn't end until the newline. With your
preprocessor, adding "end " when the indentation level decreases would
yield the first form, but then how do I get the second form? I suppose
I could both decrease the indentation level and leave a blank space,
but then it seems like we're adding an awful lot of formatting rules
just to have the code look nice and still function. On top of that, I
think this makes things much less clear! Consider that in "Pythonic
form" the above cases would become:
cat pythonic_conditional_case.rb
result = case ARGV[0]:
when /^\d*$/
"That's an integer"
when /^[A-Za-z]*$/
"That looks like a word..."
else
"That's not an integer or a word"
if ARGV[0]
puts result
cat pythonic_case_and_conditional.rb
result = case ARGV[0]:
when /^\d*$/
"That's an integer"
when /^[A-Za-z]*$/
"That looks like a word..."
else
"That's not an integer or a word"

if ARGV[0]:
puts result


Looking at those two pieces of code, is it clear that they do two
different things? At the very least, I think that this sort of change
to the syntax would have to be optional. This would, of course, mean
that you're not getting rid of all of the "end"s in code, so then
what's the point (other than to confuse matters of syntax even more)?

Let me also provide a counter-point. I'm currently using MacVim with
the ruby-vim files and a coloring scheme which colors "def...end"
pairs in yellow and other "case/if/do/etc...end" pairs in purple. This
gives me a good way to quickly look at some code, and if I see that
the "end" immediately preceding a "def" is purple, then I know I've
forgotten and "end" somewhere in that function definition.

Finally, let me suggest a bit of a "wisdom of crowds" argument: if the
advantages to significant whitespace were so unambiguously clear as
you'd have us believe, then why do most languages not use it (even
those developed before many of the advantages of advanced text editors/
IDEs existed)?

- Josh
 
J

Jan Friedrich

J Haas said:
few areas where I think Python beats Ruby, and that's syntatically-
significant
indentation.
You think so, I'm not. ;)
I recognize that
syntactically-
significant indentation is not perfect, and it would bring a few pain
points
with it. But let me say that again: ONE OUT OF EVERY SIX LINES, for
crying out
loud! This should be intolerable to engineers who value elegance.
"Streaks"
means what you'd expect: there are four places in the scanned files that
look
like this:

end
end
end
end
end
end
end

This is *not* DRY.
Objection! It is DRY: You have already mentioned that in Ruby indention
is not significant. The "ends" in your example are the *only* (not
repeated!) representation of the end of a block.

Regards,
Jan
 
J

Juan Zanos

Tony's point was that certain constructs, like case statements,
won't be
transformable into indentation only blocks. Does that make sense?

No, it doesn't, because I don't see why case statements are not
transformable into indent-only blocks. I've _done_ them using the
quick-and-dirty hacky script and they work just fine. (In cases like
Joshua's impossible.rb I had to make a minor modification to the
script to have it inject 'end ' rather than 'end\n', but it still
worked fine.)

Code speaks louder than words, right? Here's some real-world code...
it's application_controller.rb from the AuthLogic example (http://
github.com/binarylogic/authlogic_example/tree):

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

# Filters added to this controller apply to all controllers in the
application.
# Likewise, all the methods added will be available for all
controllers.

class ApplicationController < ActionController::Base
helper :all
helper_method :current_user_session, :current_user

Tony's point was that certain constructs, like case statements,
won't be
transformable into indentation only blocks. Does that make sense?

No, it doesn't, because I don't see why case statements are not
transformable into indent-only blocks. I've _done_ them using the
quick-and-dirty hacky script and they work just fine. (In cases like
Joshua's impossible.rb I had to make a minor modification to the
script to have it inject 'end ' rather than 'end\n', but it still
worked fine.)

Code speaks louder than words, right? Here's some real-world code...
it's application_controller.rb from the AuthLogic example (http://
github.com/binarylogic/authlogic_example/tree):

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

# Filters added to this controller apply to all controllers in the
application.
# Likewise, all the methods added will be available for all
controllers.

class ApplicationController < ActionController::Base
helper :all
helper_method :current_user_session, :current_user
filter_parameter_logging :password, :password_confirmation

private
def current_user_session
return @current_user_session if defined?(@current_user_session)
@current_user_session = UserSession.find
end

def current_user
return @current_user if defined?(@current_user)
@current_user = current_user_session &&
current_user_session.record
end

def require_user
unless current_user
store_location
flash[:notice] = "You must be logged in to access this page"
redirect_to new_user_session_url
return false
end
end

def require_no_user
if current_user
store_location
flash[:notice] = "You must be logged out to access this page"
redirect_to account_url
return false
end
end

def store_location
session[:return_to] = request.request_uri
end

def redirect_back_or_default(default)
redirect_to(session[:return_to] || default)
session[:return_to] = nil
end
end

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

Nothing particularly special about this code, right? Pretty standard
Ruby, if a bit simple? 37 non-blank, non-comment lines, of which 9
consist of the bare word "end". I defy anyone to tell me that the
code
would be less readable as this:

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

# Filters added to this controller apply to all controllers in the
application.
# Likewise, all the methods added will be available for all
controllers.

class ApplicationController < ActionController::Base
helper :all
helper_method :current_user_session, :current_user
filter_parameter_logging :password, :password_confirmation

private
def current_user_session:
return @current_user_session if defined?(@current_user_session)
@current_user_session = UserSession.find

def current_user:
return @current_user if defined?(@current_user)
@current_user = current_user_session &&
current_user_session.record

def require_user:
unless current_user:
store_location
flash[:notice] = "You must be logged in to access this page"
redirect_to new_user_session_url
return false

def require_no_user:
if current_user:
store_location
flash[:notice] = "You must be logged out to access this page"
redirect_to account_url
return false

def store_location:
session[:return_to] = request.request_uri

def redirect_back_or_default(default):
redirect_to(session[:return_to] || default)
session[:return_to] = nil
As this debate unfolds I've watched the stronger criticisms fall
apart. The
strongest type of criticism would be that it can't be done, or that
it's too
hard to do. But the impossible examples seem to be defeated fairly
easily.
Moreover, the solutions are backward compatible to existing Ruby.

Now when I look at this latest example I see some ordinary code
that's 44 lines
long. With the pythonic scheme it looks like it's only 35 lines
long. I find
it difficult to convince myself that it's a good idea to make code
25% larger
just to preserve some ends of dubious value.

I suppose I could try to come up with some nonsense argument that
'end' makes
everything more readable. But that would just be prejudice. It's
trivially
easy to read. It can't just be me. There seems to be no shortage
of Python
folk who have no problem either. Objectively, being forced to
explicitly type
'end' all the time seems to takes up a whole lot of space.

filter_parameter_logging :password, :password_confirmation

private
def current_user_session
return @current_user_session if defined?(@current_user_session)
@current_user_session = UserSession.find
end

def current_user
return @current_user if defined?(@current_user)
@current_user = current_user_session &&
current_user_session.record
end

def require_user
unless current_user
store_location
flash[:notice] = "You must be logged in to access this page"
redirect_to new_user_session_url
return false
end
end

def require_no_user
if current_user
store_location
flash[:notice] = "You must be logged out to access this page"
redirect_to account_url
return false
end
end

def store_location
session[:return_to] = request.request_uri
end

def redirect_back_or_default(default)
redirect_to(session[:return_to] || default)
session[:return_to] = nil
end
end

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

Nothing particularly special about this code, right? Pretty standard
Ruby, if a bit simple? 37 non-blank, non-comment lines, of which 9
consist of the bare word "end". I defy anyone to tell me that the code
would be less readable as this:

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

# Filters added to this controller apply to all controllers in the
application.
# Likewise, all the methods added will be available for all
controllers.

class ApplicationController < ActionController::Base
helper :all
helper_method :current_user_session, :current_user
filter_parameter_logging :password, :password_confirmation

private
def current_user_session:
return @current_user_session if defined?(@current_user_session)
@current_user_session = UserSession.find

def current_user:
return @current_user if defined?(@current_user)
@current_user = current_user_session &&
current_user_session.record

def require_user:
unless current_user:
store_location
flash[:notice] = "You must be logged in to access this page"
redirect_to new_user_session_url
return false

def require_no_user:
if current_user:
store_location
flash[:notice] = "You must be logged out to access this page"
redirect_to account_url
return false

def store_location:
session[:return_to] = request.request_uri

def redirect_back_or_default(default):
redirect_to(session[:return_to] || default)
session[:return_to] = nil
As I've watched this debate unfold I've watched the stronger
criticisms fall
apart. The strongest type of criticism would be that it can't be
done, or that
it's too hard to be done. But the impossible examples seem to be
defeated
fairly easily. Moreover, the solutions are backward compatible to
existing
Ruby.

Now when I look at this latest example I see some ordinary code that's
44 lines
long. With the pythonic scheme it looks like it's only 35 lines
long. I find
it difficult to convince myself that it's a good idea to make code 25%
larger
just to preserve some ends of dubious value.

I suppose I could try to come up with some nonsense argument that
'end' makes
everything more readable. But that would just be prejudice. The
pythonic
example is trivially easy to read. It can't just be me. There seems
to be no
shortage of Python folk who have no problem. Objectively, the ends
just take
up a whole lot of space.
 
C

Caleb Clausen

I assume that that end is optional, too?
Yes.

end also doubles as the equivalent for Python's "pass", as well?

Mostly. As I understand it, pass in python is a no-op. End 'stand in',
if you will, for the value of the entire statement it's ending.

(In endless.rb, if you really want a no-op to end your statement, you
should use an (appropriately indented) semicolon.)
So you can have ends if you want them but they're optional?

You got it. Your end now HAS to be intented right, tho.
Does it work with {}'s too?

No... seemed a little weird to me to have { without the matching }.
But there's no technical reason why { couldn't be autoended too.
So the basic rule it uses is that if something returns to the original
indentation level without being an end, it assumes it should have been
an end, is that right? (i.e. it *requires* blocks to be at a greater
indentation level).

Yep.

J said:
Fairly awesome. But I think we should consider keeping the colon, and
here's why: blocks that are not delimited by a colon at the start
behave exactly as normal Ruby blocks do, requiring an "end" to close
them, and more importantly ignoring indentation. That way, existing
code can be run through the preprocessor when it's "on", and will
continue to work. And it leaves people to pursue ASCII art with their
indentation, if they are so inclined.

In my preprocessor, end is still allowed, it's just optional now. So
you can copy and paste from a normal ruby file and not worry. (As log
as the snippet you paste is properly indented.)
 
E

Eleanor McHugh

As I've watched this debate unfold I've watched the stronger
criticisms fall
apart. The strongest type of criticism would be that it can't be
done, or that
it's too hard to be done. But the impossible examples seem to be
defeated
fairly easily. Moreover, the solutions are backward compatible to
existing
Ruby.

Some cases have been presented elsewhere in this thread where the
pythonic indentation would fall flat: specifically for expressions of
the form

a = case x
when...
when...
when...
end if y

It's not a common formulation in this form, but it highlights the
problem of using significant whitespace as an expression delimiter in
expression-based languages. Were there a way to solve this ambiguity
elegantly then there would be a case in favour of introducing pythonic
indentation, but until then this would either introduce an unnecessary
limitation on the things that can be expressed in ruby or lead to a
considerably more complicated lexer that might have other implications.
Now when I look at this latest example I see some ordinary code
that's 44 lines
long. With the pythonic scheme it looks like it's only 35 lines
long. I find
it difficult to convince myself that it's a good idea to make code
25% larger
just to preserve some ends of dubious value.

I suppose I could try to come up with some nonsense argument that
'end' makes
everything more readable. But that would just be prejudice. The
pythonic
example is trivially easy to read. It can't just be me. There
seems to be no
shortage of Python folk who have no problem. Objectively, the ends
just take
up a whole lot of space.

Begin..end indicates explicitly that a series of expressions is
contained between these statements and that their return value is
available to use as part of a more complex expression which may have
modifiers, something of great value to some of us. Your experience
might well be very different and this might not be a use case you
commonly encounter, but please don't make the mistake of believing
that your use case invalidates the utility of this language feature.
Most of the code I work on takes this form and has perhaps a 10%
density of 'end' statements, if that.

Admittedly when I've worked on Rails apps I've seen the 25%
demonstrated in your quoted example frequently: to my mind that's a
code smell suggesting that much of that code is boilerplate ripe for
abstraction and meta-programming. Such an approach would bring the
'end' density back down to an acceptable and useful level.

The real answer to this issue is to have a pythonic indentation pre-
processor for those who find that of use, and to leave the core
language syntax alone.


Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net
 
P

Pascal J. Bourguignon

Eleanor McHugh said:
Some cases have been presented elsewhere in this thread where the
pythonic indentation would fall flat: specifically for expressions of
the form

a = case x
when...
when...
when...
end if y

It's not a common formulation in this form, but it highlights the
problem of using significant whitespace as an expression delimiter in
expression-based languages. Were there a way to solve this ambiguity
elegantly then there would be a case in favour of introducing pythonic
indentation, but until then this would either introduce an unnecessary
limitation on the things that can be expressed in ruby or lead to a
considerably more complicated lexer that might have other implications.

There's a simply way to solve it. Since everything is an expression,
we can easily wrap expressions and subexpressions in parentheses, and
by the way resolve any ambiguity:

(a = ((case x
when ...
when ...
when ...
end) if y))

((a = (case x
when ...
when ...
when ...
end))
if y)


Begin..end indicates explicitly that a series of expressions is
contained between these statements and that their return value is
available to use as part of a more complex expression which may have
modifiers, something of great value to some of us. Your experience
might well be very different and this might not be a use case you
commonly encounter, but please don't make the mistake of believing
that your use case invalidates the utility of this language feature.
Most of the code I work on takes this form and has perhaps a 10%
density of 'end' statements, if that.

It could be reduced to 0%, if you notice that the close parenthesis is
all that is needed to end the subexpressions.

(a = ((case x
when ...
when ...
when ...) if y))

((a = (case x
when ...
when ...
when ...))
if y)


Also we could decide to always put the operator first, to simplify a little:


(a = (if y
(case x
when ...
when ...
when ...)))

(if y
(a = (case x
when ...
when ...
when ...)))

so it would be clearer what is IF'ed.

The real answer to this issue is to have a pythonic indentation pre-
processor for those who find that of use, and to leave the core
language syntax alone.

Exactly. The concrete syntax should be purely a question of
presentation and user interface, that should be dealt with by the
editor. Source files could be kept in s-exp form, like it was
intended originally (50 years ago).
 
C

Charles Johnson

FWIW, daring people to dispute what is ultimately a matter of
opinion is not terribly productive. I've had enough discussions
with Haml lovers to know that rounds of "But look how beautiful it
is" vs "I find it grating" go nowhere.


Exactly. I prefer chocolate ice cream to python, and thai cuisine to
both.

Cheers--

Charles
 
J

J Haas

In my preprocessor, end is still allowed, it's just optional now. So
you can copy and paste from a normal ruby file and not worry. (As log
as the snippet you paste is properly indented.)

This was my point. It would be good to still have the option of
freeform indentation. Much Ruby code _isn't_ presently canonically
formatted, and it'd break if put through your preprocessor. One
solution to this would be to only activate the preprocessor on a per-
file basis, but I think a better solution would be for the
preprocessor not to damage existing code. The ultimate goal in the
long term should be to make this style part of core Ruby syntax rather
than the result of a preprocessor, and the best way to do that would
be for the parser to be able to distinguish between indentation-aware
blocks and "old-style" blocks.
 
J

J Haas

FWIW, daring people to dispute what is ultimately a matter of opinion is
not terribly productive.  

Yeah, I realized that as soon as I posted. Sorry 'bout that. But look
at it this way.

In the example from AuthLogic I posted, which is real-world code and
not at all atypical, just under one-fourth of the non-blank, non-
comment lines consist of the bare word 'end'. The 'end' keyword
doesn't _do_ anything. It's just a signal to the parser that here is
the end of the block... and with canonical indentation, this is
something the parser is quite capable of inferring on its own. 'end'
is redundant.

Code speaks louder, right? The whole point of writing code is to tell
the interpreter what you want it to do, and the whole concept of
'expressiveness' is based on being able to tell the interpreter what
you want it to do with a minimum of overhead. Let's tell the
interpreter to do something:

1.upto 10 do |x|
p x

Stop! Don't write another word. At this point, you've told the
interpreter _exactly_ what you want. Using the bare minimum of code,
you've expressed with perfect clarity your intent. Anything you write
beyond that is superfluous. And if the language _requires_ you to
write this extraneous code, it's not as expressive as it could be.

I know it looks funny to a lot of people. It looked funny to me the
first time, too. As I said, my reaction when I first learned of
significant indentation was the same reaction I've seen from lots of
developers I've told about it: "what, are you kidding?" But it makes
sense. After a day or two of playing around with it, you'll find that
it becomes second nature.
 
C

Caleb Clausen

Some cases have been presented elsewhere in this thread where the
pythonic indentation would fall flat: specifically for expressions of
the form

a = case x
when...
when...
when...
end if y

I feel that I did address this point adequately already, so it's
annoying to see both you and Joshua Ballanco bring it up again,
without even acknowledging that I had done so. Perhaps you don't agree
with my points, but as you haven't tried to rebut them, I think it
more likely that you did not read what I had to say at all.

To reiterate: Yes, you can't really write that expression without an
end. Cases like this are why I decided, in my preprocessor, to allow
users to put in an end if they really want to. It's sufficiently rare
to need more tokens on the same line after an end that it's not
unreasonable to ask the user to type an extra (normally unnecessary)
end in those cases. 99% of ends can still be eliminated. If that
proportion were lower -- 50% or 75% or even 90%, I would say that the
convenience of not having to type end is outweighed by the additional
burden of remembering that at least a tenth of the time you do anyway.
But when you get it down to the less than once a week level, a small
exception like this is ok. Very occasionally, you have to type end in
endless ruby. Very occasionally, you have to type pass in python. BFD.
It's not a common formulation in this form, but it highlights the
problem of using significant whitespace as an expression delimiter in
expression-based languages. Were there a way to solve this ambiguity
elegantly then there would be a case in favour of introducing pythonic
indentation, but until then this would either introduce an unnecessary
limitation on the things that can be expressed in ruby or lead to a
considerably more complicated lexer that might have other implications.

I disagree that indentation sensitivity 'considerably' complicates the
lexer. endless.rb has about 180 lines of code, of which at least 25%
are concerned with the mechanics of pre-processing and wouldn't be
necessary if it were fully integrated into the lexer. It was
moderately difficult, but not bad. Quite a few other ruby features
(here documents, utf-8 in identifiers, the ambiguity of some
operators) were what I would call complicated; by comparison
indentation was pretty easy.
The real answer to this issue is to have a pythonic indentation
pre-processor for those who find that of use, and to leave the
core language syntax alone.

I did, already.
 
C

Caleb Clausen

This was my point. It would be good to still have the option of
freeform indentation. Much Ruby code _isn't_ presently canonically
formatted, and it'd break if put through your preprocessor. One

If the end is misaligned, it will cause a warning on ruby 1.9. I think
the language is already moving in the direction of encouraging you to
properly indent everything anyway.
We've had changes to ruby before which break old code before, and I
think it's ok for this to be one too. (If this is going to be
integrated into the core language at all.) Always maintaining
backwards compatibility is one of the things that makes systems with a
long history kludgy, and I'm glad ruby doesn't have that hangup.
solution to this would be to only activate the preprocessor on a per-
file basis, but I think a better solution would be for the
preprocessor not to damage existing code. The ultimate goal in the
long term should be to make this style part of core Ruby syntax rather
than the result of a preprocessor, and the best way to do that would
be for the parser to be able to distinguish between indentation-aware
blocks and "old-style" blocks.

Let's look at an example:

if foo: #new-style indentation block
while bar #old-style ended block
baz
end

Maybe you have something else in mind, idunno. To me, this just looks
totally weird, and I wouldn't expect it to work at all. Parsing this
(in a program) probably wouldn't be too much harder, but it's
significantly jarring to human readers. (At least, to this one.)
 
G

Gary Wright

I did, already.

I'm not convinced of the general utility of a pre-processor like
this. Obviously it can be used 'privately', but code that is
written with the expectation of being pre-processed is not
portable unless the wider Ruby community (or even other developers
in your organization) are prepared to run it through a preprocessor.

For that to work there has to be a 'standard' of some sort or
you'll have to distribute the pre-processor along with your code.
And that argues for it to be part of the language and *not* a
pre-processor.

Yes, it is technically possible for this to 'work' but I just don't
see the value in expending all that community energy to make it work.
I'd rather see better documentation, better implementations of the
existing syntax, gem compatibility with 1.9, frameworks that improve
my productivity, and so on.

Even if there was some way to prove that pythonic-indentation for
Ruby was 'better' than the current syntax rules any benefit has
to offset the costs of transition also (tools, developer workflow,
IDE re-writes, books, tutorials, bugs introduced in a mixed code
base, new idioms, etc.)

It just doesn't seem worth it to me.

Gary Wright
 
J

J Haas

If the end is misaligned, it will cause a warning on ruby 1.9.

Does it? That's pretty cool.
I think
the language is already moving in the direction of encouraging you to
properly indent everything anyway.
We've had changes to ruby before which break old code before, and I
think it's ok for this to be one too.

Well... keep in mind that this would break a _lot_ of code. One of the
things I had my script do (the one which computed ~16% non-blank lines
were nothing but 'end') was try to figure out how many instances there
were of 'end' not being aligned with the block it began. The answer
was: relatively few, in the single-digit percentages, but that still
worked out to several hundred instances.
Always maintaining
backwards compatibility is one of the things that makes systems with a
long history kludgy, and I'm glad ruby doesn't have that hangup.

I completely agree with you in principle, and I'm generally in favor
of breaking with the past when such a break is warranted. But
listening to the objections people have raised in this thread, for a
lot of people it boils down to "I don't like it." Well, there's no
accounting for taste, and while I happen to feel that many of these
people would change their tune once they've had a little experience
with syntactic indentation, I think the best way to assuage their
doubts would be for any change to have absolutely no impact on
existing code, with a clear distinction between old-style syntax and
new-style indentation-aware syntax.

Besides, I kind of like the look of the colon as a block-start
delimiter. It emphasizes the separation between the loop or
conditional or method call and the block it controls.
Let's look at an example:

  if foo:  #new-style indentation block
   while bar #old-style ended block
baz
   end

Maybe you have something else in mind, idunno. To me, this just looks
totally weird, and I wouldn't expect it to work at all.

Yep, looks totally weird to me too. Okay, so: no end-delimited blocks
nested inside indentation-delimited blocks. Once you're inside a scope
where the parser is paying attention to your indentation, it will
continue paying attention to your indendation until you leave that
scope.
 
E

Eleanor McHugh

I feel that I did address this point adequately already, so it's
annoying to see both you and Joshua Ballanco bring it up again,
without even acknowledging that I had done so. Perhaps you don't agree
with my points, but as you haven't tried to rebut them, I think it
more likely that you did not read what I had to say at all.

Possibly not. This has been a long thread and I'm sure I've either
missed posts or misunderstood their intent.
To reiterate: Yes, you can't really write that expression without an
end. Cases like this are why I decided, in my preprocessor, to allow
users to put in an end if they really want to. It's sufficiently rare
to need more tokens on the same line after an end that it's not
unreasonable to ask the user to type an extra (normally unnecessary)
end in those cases. 99% of ends can still be eliminated. If that
proportion were lower -- 50% or 75% or even 90%, I would say that the
convenience of not having to type end is outweighed by the additional
burden of remembering that at least a tenth of the time you do anyway.
But when you get it down to the less than once a week level, a small
exception like this is ok. Very occasionally, you have to type end in
endless ruby. Very occasionally, you have to type pass in python. BFD.

And as I've said elsewhere, how you handle things in a preprocessor is
entirely up to you. I'm not your target audience as I don't like
pythonic indentation - it's one of the reasons I didn't take to the
language despite several attempts to get into it - but I'm sure those
who are won't mind writing the occasional end statement.
I disagree that indentation sensitivity 'considerably' complicates the
lexer. endless.rb has about 180 lines of code, of which at least 25%
are concerned with the mechanics of pre-processing and wouldn't be
necessary if it were fully integrated into the lexer. It was
moderately difficult, but not bad. Quite a few other ruby features
(here documents, utf-8 in identifiers, the ambiguity of some
operators) were what I would call complicated; by comparison
indentation was pretty easy.

Until I have time to study your code I'll take your word for that.
Have you tried framing endless.rb as a patch for MRI's lexer? and if
so how significant are the changes?
I did, already.

Then put out an [ANN] and if the community finds pythonic indentation
valuable, it'll catch on.


Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net
 
J

Juan Zanos

I feel that I did address this point adequately already, so it's
annoying to see both you and Joshua Ballanco bring it up again,
without even acknowledging that I had done so. Perhaps you don't agree
with my points, but as you haven't tried to rebut them, I think it
more likely that you did not read what I had to say at all.

To reiterate: Yes, you can't really write that expression without an
end. Cases like this are why I decided, in my preprocessor, to allow
users to put in an end if they really want to. It's sufficiently rare
to need more tokens on the same line after an end that it's not
unreasonable to ask the user to type an extra (normally unnecessary)
end in those cases. 99% of ends can still be eliminated. If that
proportion were lower -- 50% or 75% or even 90%, I would say that the
convenience of not having to type end is outweighed by the additional
burden of remembering that at least a tenth of the time you do anyway.
But when you get it down to the less than once a week level, a small
exception like this is ok. Very occasionally, you have to type end in
endless ruby. Very occasionally, you have to type pass in python. BFD.

Exactly, this is a bit of a straw man issue. Nobody is saying get
rid of all
ends. Use end where it makes sense, but if it's just wasting space
there is
no need.
I disagree that indentation sensitivity 'considerably' complicates the
lexer. endless.rb has about 180 lines of code, of which at least 25%
are concerned with the mechanics of pre-processing and wouldn't be
necessary if it were fully integrated into the lexer. It was
moderately difficult, but not bad. Quite a few other ruby features
(here documents, utf-8 in identifiers, the ambiguity of some
operators) were what I would call complicated; by comparison
indentation was pretty easy.

That code was pretty standard looking. It had some functions in a
class. The
nesting wasn't particularly deep. Are classes with functions now
considered
code smell? Also, if I recall correctly the Ruby core libraries are
about 16%
end. That ought to be, relatively speaking, pretty good Ruby. So
ironically, if Ruby added this capability it's own code base would
shrink.
I did, already.

I think I'll use it. That said, the case for giving core Ruby this
capability
seems to be getting stronger.
 
E

Eleanor McHugh

I know it looks funny to a lot of people. It looked funny to me the
first time, too. As I said, my reaction when I first learned of
significant indentation was the same reaction I've seen from lots of
developers I've told about it: "what, are you kidding?" But it makes
sense. After a day or two of playing around with it, you'll find that
it becomes second nature.

You might just as well tell the Lisp community that all those brackets
they use are redundant. You might well find some converts, but I
suspect most people would look at you with a mix of incomprehension
and revulsion. In a certain sense Lisp *is* the brackets.

So contrary to how you feel about this, one size doesn't fit all -
especially not in matters of aesthetics. Indeed I suspect that much of
the resistance that you've experienced in this thread is a reflection
of the fact that your original post and this one both show an equal
lack of awareness of that fact.


Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top