Pythonic indentation (or: beating a dead horse)

Joshua Ballanco wrote:

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

* Deeply nested blocks can be closed quickly. I don't like significant whitespace, personally.

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

I'm having a hard time following why. Can you provide an example of a
Ruby snippet that couldn't be done with scoping defined by
indentation?

A multi-line block returning a value, e.g.

foo = somemethod do |arg1, arg2, arg3|
  x = do_something arg1
  y = do_something_else x, arg2
  and_something_else_again y, arg3
end

Or for that matter, a multi-line lambda:

foo = lambda do |arg1, arg2, arg3|
  x = do_something arg1
  y = do_something_else x, arg2
  and_something_else_again y, arg3
end

I'm sure you're aware the "multi-line lambda" problem is somewhat infamous
in the Python world. Guido van Rossum himself has ruled it an "unsolvable
problem" because of the statement-based nature of Python indent blocks.
Lambdas must be expressions or they are worthless, and there is no way to
embed an indent block inside of a Python expression.

And a bit of supplemental information: I conducted a poll of what Rubyists'
favorite features are in the language. Blocks were #1 by a wide margin.

This seems like a problem with Python, not a problem with indentation.

As I said, a Haskell-like syntax would facilitate including indent blocks in
a purely expression-based grammar. It's Python's statement-structured
syntax that's incompatible. However the sort of syntax you would get from a
Haskell-like approach is going to be different than Python's.

You can have a look at Logix, which is a purely expression based language
which tries to mimic Python's syntax while using Haskell-styled indent
rules. This is about the best you can do:

http://web.archive.org/web/20060517203300/www.livelogix.net/logix/tutorial/3-Introduction-For-Python-Folks.html

Well, every expression in a Ruby-like grammar must be terminated by a

token. [... snip ...]

In other words, the parser treats an indentation level less than the
indentation level of the previous line as a statement-terminating
token.

Because there are statements which contain multiple indent blocks, such as
if or try/catch. If you wanted to carry over Rubyisms, this would include
the case statement, e.g.

case foo
when bar
  ...
when baz
  ...

Therefore you can't just treat a "dedent" as a statement terminator, because
a single statement may itself contain multiple "dedent" tokens.

The best solution I could think of for this was a syntactically relevant
blank line, which sucks. It also requires lexer logic more complex than
Python to handle the case of a syntactically relevant newline, which in turn
pollutes the grammar.

> Implicit line joining works in Python because the only syntactic
> constructions which can exist surrounded in [...] (...) {...} tokens are
> expressions, so you can't put an indent block inside of these. If you
have
> an indent-sensitive Ruby with implicit line joining, you limit the
> expressiveness of what you can do inside any syntactic constructs
enclosed
> by these tokens.

This sorta makes sense but I'd really like to see a concrete example
of what you're talking about. It doesn't seem like this would be an
insurmountable difficulty but it's hard to say without the example.

This is valid Ruby:

on_some_event(:something, :filter => proc do
  something_here
  another_thing_here
  etc
end)

Implicit line joining removes any newline tokens inside of (...) [...] {...}
type syntactic constructions. So it becomes impossible to embed anything
with an indent block inside of expressions enclosed in any of these tokens.

And now we've hit an entirely new can of worms: how do you make implicit
line joining work when parens are optional?

···

On Tue, May 19, 2009 at 4:50 PM, J Haas <Myrdred@gmail.com> wrote:

--
Tony Arcieri
medioh.com

This is *not* DRY. Or anything remotely resembling it. This is an
ugly blemidh on a language that otherwise is very beautiful.

It's a blemish all right, but not on the language.

If not the language, then where? In the library code? Maybe those four
places where "end" is repeated seven consecutive times are poorly
engineered and could be refactored,

They almost certainly could be, this is a sign of strong code-smel

but how about the nearly thousand
times "end" is repeated three or more times? Is every one of those the
result of poor engineering on the part of the library programmers, or
were at least some of them forced on the programmers by the language?

One statistic that I didn't print out from my script was that there
are an average of 135 lines of "end" per file. For a language that
prides itself on expressiveness and brevity, this is just plain silly.

Does anybody complain about terminating '}' in C, C++ or Java? Does anybody complain about terminating '.' on sentences? (There's a folowing capital letter for disambiguation!) I think we need to remove all useles constructs from all languages

···

On May 19, 2009, at 15:25, J Haas wrote:

One of the nice advantages of an open source project like ruby is that you can fork it, and take it in directions not held by the original developers. Become your own committer. That should be the least of your worries. If you really do have a better mouse-trap you will have no problems about finding people who will join *you* rather than the other way around.

Cheers--

Charles

···

On May 20, 2009, at 10:10 AM, J Haas wrote:

Ugh, pass. I've wasted far too much of my life coding what I thought
were useful features for open-source projects only to find that the
committers didn't share my opinion. I ain't touching something like
this unless there's at least some reasonable chance the patch might
actually get accepted.

---
Charles Johnson
Advanced Computing Center for Research and Education
Vanderbilt University

I already responded to this. I guess you didn't see it. There are several
types of statements which contain multiple indent blocks (and thus multiple
dedent tokens). These would include if statements:

if foo
  blah
elsif bar
  blah2
else
  baz

Begin statements (ala try/catch in Python)

begin
  somecode
  morecode
rescue FooError
  some_rescue_action
rescue BarError
  another_rescue_action
ensure
  something_gets_done

Case statements:

case foo
when bar
  do_something
when baz
  do_something_else

Each of these statements is an expression with multiple clauses. How do you
tell when these expressions are complete? Obviously a naive "dedent = end
of expression" approach doesn't work in these cases.

These work in Python because Python has a special grammar for statements
which doesn't require a statement separator for any statements which have
indent blocks. This doesn't work in a language where everything is an
expression, because all expressions must be treated the same and all
expressions must have an expression terminator (newline or semicolon)

···

On Wed, May 20, 2009 at 1:10 PM, J Haas <Myrdred@gmail.com> wrote:

I still have a tough time understanding this objection. What I'm
essentially proposing is that at least in the case of code blocks that
start with a colon, a de-dent takes the place of an end. Given that, I
just don't see what it is that could be done without end that couldn't
be done without dedenting.

--
Tony Arcieri
medioh.com

A friendly suggestion: One of Ruby's strengths (one that it shares with Perl) is its power to manipulate and parse strings. If you're new to Ruby, a script which takes your colon/de-indent syntax and turns it into the proper do/end syntax sounds like a great project to get started. Since you desire to write Ruby code in this way, it would also give you a great excuse to approach this problem using TDD. That is, write the code in the way you would like it to appear as a test, then write the parser/de-re-mangler to have the test pass. I honestly think you could have done this with the same amount of effort as it has taken to reply to each of the e-mails in this thread.

Let me be frank: Your suggestion is not new. Code speaks louder than words. When you _do_ implement this alternative Ruby syntax, I think you may be surprised at the number of corner and edge cases. Ruby is currently in the process of being standardized. I would imagine the last thing that Ruby needs while undergoing the standardization process is a new, optional syntax with a multitude of corner and edge cases.

Cheers,

Josh

···

On May 20, 2009, at 3:10 PM, J Haas wrote:

Also could parsers handle it?

I think so, especially since the preprocessor I've used (wish I could
remember its name... it's not Lazibi [1]) does it in a fairly clever
way in Ruby itself, so I don't see why the parser couldn't do what it
does.

print 3

3 :slight_smile:

Nifty! Thanks.

Appears I went too far--this is enough:

class Object
def print *args
      super *(args + [" :-)"])
end
end

print 3

3 :-)=> nil

This works because

class A; end
A.ancestors

=> [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! :slight_smile:

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

···

--
Posted via http://www.ruby-forum.com/\.

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

YAML and Haml are fundamentally different from Ruby, or do you
consider markup to be programming?
It's true that Haml has the same any-Ruby-is-allowed rules as ERB, but
you naturally restrict yourself because you're working with a template
as opposed to an actual program. (Or at least you should.)

And for the record, I get kind of annoyed with the significant
whitespace in Haml when it comes to Ruby code, but I love how easy and
clean HTML becomes.

···

On May 21, 1:12 pm, James Britt <james.br...@gmail.com> wrote:

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

--
-yossef

Does anybody complain about terminating '}' in C, C++ or Java?

Python programmers?

:slight_smile:

Does anybody
complain about terminating '.' on sentences? (There's a following capital
letter for disambiguation!)

I agree with your point, but I don't this argument helps - computer
languages and human languages are two fairly distinct classes, with
different origins, requirements, and, um...parsers.

In my opinion they aren't always comparable.

Ben Kudria

···

On Tue, May 19, 2009 at 19:49, Eric Hodel <drbrain@segment7.net> wrote:
--
http://ben.kudria.net | Jabber: ben@kudria.net

Does anybody complain about terminating '}' in C, C++ or Java?

I do, now. Redundancy irritates me.

Does anybody complain about terminating '.' on sentences?

If the period accounted for one-sixth of English text, perhaps they
would.

···

On May 19, 4:49 pm, Eric Hodel <drbr...@segment7.net> wrote:

And yet another consideration with this in Ruby vs. Python: in Ruby these
are all expressions (as has been stated repeatedly) and therefore you can do
this sort of thing:

x = case foo
when bar
  do_something
when baz
  do_something_else
else
  whatever
end

i.e. the case statement returns the value of the last expression evaluated
in the taken branch.

This is not the case in Python (well first because Python doesn't have case
statements) where no expressions can contain indent blocks.

···

On Wed, May 20, 2009 at 1:25 PM, Tony Arcieri <tony@medioh.com> wrote:

I already responded to this. I guess you didn't see it. There are several
types of statements which contain multiple indent blocks (and thus multiple
dedent tokens). These would include if statements: [... snip ...]

Begin statements (ala try/catch in Python) [... snip ...]

Case statements: [... snip ...]

case foo
when bar
do_something
when baz
do_something_else

--
Tony Arcieri
medioh.com

I already responded to this. I guess you didn't see it.

I responded to your response, I guess you didn't see _that_. Tell me
what's wrong with the following alternatives to your examples:

if foo
blah
elsif bar
blah2
else
baz

Just like with your case example before, whoops! You're missing an
end, and the parser will complain when it sees the end-of-file without
a missing end. And just as I said with your case example before, I
sure hope this missing end isn't in the middle of a long file or you
get to spend a lot of time scrolling through your code looking for the
place where it's missing.

But if we amend your example to

if foo
  blah
elsif bar
  blah2
else
  bar
end

...I really don't see what's wrong with this as an alternative:

if foo:
  blah
elsif bar:
  blah
else:
  bar

No end necessary.

Begin statements (ala try/catch in Python)

begin
somecode
morecode
rescue FooError
some_rescue_action
rescue BarError
another_rescue_action
ensure
something_gets_done

Again, you're missing an end. Applying the same pattern I applied in
the if and case examples, I do not see what the problem is. How is it
any less functional than the current Ruby?

Each of these statements is an expression with multiple clauses. How do you
tell when these expressions are complete? Obviously a naive "dedent = end
of expression" approach doesn't work in these cases.

Okay, I think I see what you're saying now. But each of those also, in
the clauses after the first one, begins with a keyword that is not
valid except as part of the previous expression. Does it solve the
problem if dedenting ends an expression unless it's immediately
followed by a keyword that makes no sense except as a continuation of
the expression?

This doesn't work in a language where everything is an
expression, because all expressions must be treated the same and all
expressions must have an expression terminator (newline or semicolon)

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.

···

On May 20, 12:25 pm, Tony Arcieri <t...@medioh.com> wrote:

I may have ben too sutle Maybe your email program spel-chex I certainly didnt have useles double leters in my original

···

On May 19, 2009, at 16:58, Benjamin Kudria wrote:

On Tue, May 19, 2009 at 19:49, Eric Hodel <drbrain@segment7.net> > wrote:

Does anybody complain about terminating '}' in C, C++ or Java?

Python programmers?

:slight_smile:

Does anybody
complain about terminating '.' on sentences? (There's a following capital
letter for disambiguation!)

I agree with your point, but I don't this argument helps - computer
languages and human languages are two fairly distinct classes, with
different origins, requirements, and, um...parsers.

In my opinion they aren't always comparable.

Did you include Comparable and implement <=> ?

···

On Wed, May 20, 2009 at 08:58:44AM +0900, Benjamin Kudria wrote:

On Tue, May 19, 2009 at 19:49, Eric Hodel <drbrain@segment7.net> wrote:
> Does anybody complain about terminating '}' in C, C++ or Java?

Python programmers?

:slight_smile:

> Does anybody
> complain about terminating '.' on sentences? (There's a following capital
> letter for disambiguation!)

I agree with your point, but I don't this argument helps - computer
languages and human languages are two fairly distinct classes, with
different origins, requirements, and, um...parsers.

In my opinion they aren't always comparable.

--
Aaron Patterson
http://tenderlovemaking.com/

wellwhydontwegetridofallpunctuationthingslikespacescommassemicolonsquotesetcperiodcertainlytakeupmuchmoreofourprosethantheydeserveandcapitalizationeatsupvaluableverticalspaceandnoneedforparagraphseparationeither

Seriously, if you measure things by avoiding extra keystrokes, get a
better editor. I value readability over parsimony of lexical items.

···

On Wed, May 20, 2009 at 11:05 AM, J Haas <Myrdred@gmail.com> wrote:

On May 19, 4:49 pm, Eric Hodel <drbr...@segment7.net> wrote:

Does anybody complain about terminating '}' in C, C++ or Java?

I do, now. Redundancy irritates me.

Does anybody complain about terminating '.' on sentences?

If the period accounted for one-sixth of English text, perhaps they
would.

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

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.

···

On Wed, May 20, 2009 at 2:30 PM, J Haas <Myrdred@gmail.com> wrote:

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.

--
Tony Arcieri
medioh.com

Doh :slight_smile:

I have a compulsive habit of correcting (perceived!) typos in quotes.
I should probably stop.

Ben

···

On Tue, May 19, 2009 at 20:11, Eric Hodel <drbrain@segment7.net> wrote:

I may have ben too sutle Maybe your email program spel-chex I certainly
didnt have useles double leters in my original

--
http://ben.kudria.net | Jabber: ben@kudria.net

That would be a valid criticism if J Haas's suggestion made things less readable. But having to scroll less makes things more readable.

···

On May 20, 2009, at 11:51 AM, Rick DeNatale wrote:

On Wed, May 20, 2009 at 11:05 AM, J Haas <Myrdred@gmail.com> wrote:

On May 19, 4:49 pm, Eric Hodel <drbr...@segment7.net> wrote:

Does anybody complain about terminating '}' in C, C++ or Java?

I do, now. Redundancy irritates me.

Does anybody complain about terminating '.' on sentences?

If the period accounted for one-sixth of English text, perhaps they
would.

wellwhydontwegetridofallpunctuationthingslikespacescommassemicolonsquotesetcperiodcertainlytakeupmuchmoreofourprosethantheydeserveandcapitalizationeatsupvaluableverticalspaceandnoneedforparagraphseparationeither

Seriously, if you measure things by avoiding extra keystrokes, get a
better editor. I value readability over parsimony of lexical items.

-- Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Seriously, if you measure things by avoiding extra keystrokes, get a
better editor. I value readability over parsimony of lexical items.

Cluttering up your code with "end" everywhere makes it less readable,
not more.

I have some suspicion this was a joke thread.
(Hint: Format of OP)

Nope, I'm sincere. As I said before, I'm new. The formatting was a
misguided attempt to make things look nice by manually wrapping them
at 80 columns. Oops.

This sort of structuring pieces of code stopped me from trying Python
seriously.

And I specifically addressed this in my OP. A lot of engineers who
haven't done work in Python think that the idea of giving syntactical
significance to whitespace is a ridiculous idea. I used to be one of
them. Now I know better. Don't knock it until you've tried it.

Isn't there an Syntax-Highlighting Editor out there which allows assigning
1-Point size to End-Only-Lines?

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.

Wouldnt this be the easiest way to solve your problem?

The easiest way to solve _my_ problem would be for me to use one of
the preprocessing scripts that impose Python-like indentation syntax
on Ruby. But that wouldn't solve the larger problem, which is that
Ruby could be better than it is.

···

On May 20, 8:51 am, Rick DeNatale <rick.denat...@gmail.com> wrote:
On May 20, 9:01 am, "Michael Bruschkewitz" <brusch4_removeunderlinesandtextbetwe...@gmx.net> wrote:

On May 20, 10:04 am, Joshua Ballanco <jball...@gmail.com> wrote:

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

Nope. but I'll check it out. Thanks.