what about allowing to specify, which end belongs to which start?

J

Jan Lelis

Hi Ruby mailing list,

I've recently come across a pretty common situation in Ruby:

end
end
end

After those parts, you often don't know, where exactly you have to
continue.

So what about allowing to specify, which end belongs to which start?
I've thought about something like this:

end|do
end|if
end|def

or

end~do
end~if
end~def

or

end:do
end:if
end:def

If you specify it, and it does not match, the compiler throws an error.
Of course, you can always omit it to have the normal behaviour, but you
are encouraged to often "document", which end belongs to which block
(and you do yourself a favour in these nested situations).

What do you think about it?
 
R

Robert Klemme

Not to forget about end:case, end:class, end:module...

The compiler as it is today will throw an error anyway.

I think "encouraged" is the wrong word. Your extension would _force_
the user to use this idiom (which I personally find too verbose). Also,
your solution does not help if you nest the same type of control flow
statement. If you want to document nesting you can do that today
already (and some people actually do it). But I agree with Ryan here:
I think if you have so many ends that you need to extend the syntax
then you're doing something wrong to begin with (no pun). I try to
make all my methods short when I can, and I use judicious use of
extra returns to separate code into paragraphs to further help. I
think this type of syntax extension would further encourage large bad
codes.

Plus, editors with auto indentation and code completion usually help. I
personally have made it a habit to always write the opening and closing
construct before I fill in the body. That way you can work pretty well
even if your editor does not have fancy features.

Kind regards

robert
 
J

Jan Lelis

I think "encouraged" is the wrong word. Your extension would _force_
the user to use this idiom (which I personally find too verbose). Also,
your solution does not help if you nest the same type of control flow
statement. If you want to document nesting you can do that today
already (and some people actually do it). [...]

I thought more of: use it seldom (it's too verbose), only at spots,
where there are, e.g. at least 3 "end"s... The problem with documenting
is that the interpreter cannot detect false order, etc.
I think if you have so many ends that you need to extend the syntax
then you're doing something wrong to begin with (no pun). I try to
make all my methods short when I can, and I use judicious use of
extra returns to separate code into paragraphs to further help. I
think this type of syntax extension would further encourage large bad
codes.

Yes, the syntax would to have be extended... but that's no reason why it
cannot be good...
Unfortunately, it is not always possible (or good) to keep the code
short and flat...
Plus, editors with auto indentation and code completion usually help. I
personally have made it a habit to always write the opening and closing
construct before I fill in the body. That way you can work pretty well
even if your editor does not have fancy features.

Yes, but it is not only about the writing, also about the reading or
refactoring of code.

_____
J-_-L
 
J

Jan Lelis

Wrong wrong wrong. I cannot disagree more.

I mean, of course, you should try to keep it short... but I think the

end:do
end:if
end:def

is not too much nested, in most cases. I do not want to put every block
or if into its own method...

_____
J-_-L
 
E

Eleanor McHugh

If you specify it, and it does not match, the compiler throws an = error.=20
Of course, you can always omit it to have the normal behaviour, but = you=20
are encouraged to often "document", which end belongs to which block=20=
(and you do yourself a favour in these nested situations).
=20
What do you think about it?

Jan, it's not in Ruby's nature to hold your hand so whilst I can't see =
any particular technical reason for having such an _optional_ syntax =
extension, I'd be uncomfortable with code that relied upon them.

In any event the underlying problem you're describing is one which in =
the vast majority of cases is a code smell and is best dealt with by =
aggressive refactoring. Move the inner loops into their own method =
calls, or write your outer-loop logics as a method taking a block and =
drive iteration/whatever that way. The resulting code will be much =
easier to read and maintain, and the generality will improve your code =
reuse options.


Ellie

Eleanor McHugh
Games With Brains
http://feyeleanor.tel
 
C

Caleb Clausen

So what about allowing to specify, which end belongs to which start?
I've thought about something like this:

end|do
end|if
end|def

or

end~do
end~if
end~def

or

end:do
end:if
end:def

I've been told that very old versions of ruby used to have this
feature, using a space to separate the end from the keyword being
terminated instead of | ~ or : as suggested by Jan. So, in other
words, you could write:

if foo
bar
end if


I like this syntax far above anything involving punctuation.
Supposedly, this feature was removed when the 'modifier' versions of
if and unless and etc were added to the language; keeping both was
difficult to support in the parser. However, after giving it a little
thought, it seems to me that a form of this feature could be
reintroduced with not an excessive amount of trouble. If the keyword
being terminated is immediately followed by a newline or semicolon, it
is treated as a Jan wants. Otherwise, it's treated as a 'modifier'
flow control (if it's an if or unless or etc).

I could write a RubyLexer-based preprocessor which does this pretty
easily. However, I'm not terribly motivated. This doesn't seem like
that useful a feature to me and I've got so much else to work on....
 
B

Brian Candler

Jan said:
Hi Ruby mailing list,

I've recently come across a pretty common situation in Ruby:

end
end
end

After those parts, you often don't know, where exactly you have to
continue.

You can always use comments, although I'd only usually do this for
nested modules. e.g.

module Foo
module Bar
class Baz
....
end # class Baz
end # module Bar
end # module Foo

Otherwise, I've never found it a problem, unless I've missed an 'end',
or forgotten a 'do'.

ruby 1.9 with -w flag has a neat feature where it will warn if the
indentation is not as expected, thus making it much easier to find where
the problem is.

e.g.

$ cat test.rb
def foo
puts "hello"
5.times # note missing "do"
puts "world"
end
puts "goodbye"
end
$ ruby19 test.rb
test.rb:7: syntax error, unexpected keyword_end, expecting $end
$ ruby19 -w test.rb
test.rb:5: warning: mismatched indentations at 'end' with 'def' at 1
test.rb:7: syntax error, unexpected keyword_end, expecting $end

This shows that the 'end' at line 5 was associated with the 'def' at
line 1, which helps localise the problem.

It's a shame that ruby 1.8.7 doesn't have this feature, although you can
keep a copy of ruby 1.9 lying around just for locating such problems
(the parsing of the two languages is very similar, even though the
semantics are very different)
 
R

Robert Klemme

I've been told that very old versions of ruby used to have this
feature, using a space to separate the end from the keyword being
terminated instead of | ~ or : as suggested by Jan. So, in other
words, you could write:

if foo
bar
end if


I like this syntax far above anything involving punctuation.
Supposedly, this feature was removed when the 'modifier' versions of
if and unless and etc were added to the language; keeping both was
difficult to support in the parser.

I don't want to advocate this but concatenating "end" directly with the
opening keyword is probably easy to do because it will create a whole
bunch of new tokens , so there would be

endclass
endmodule
enddef
endbegin
endif
endunless
endwhile
enduntil
endfor
enddo
endcase

Did I miss one?

Each of those would be then alternatively allowed to "end", so you could
write

begin
if foo
else
case x
when y
when z
endcase
end
endbegin

I still don't like it.
However, after giving it a little
thought, it seems to me that a form of this feature could be
reintroduced with not an excessive amount of trouble. If the keyword
being terminated is immediately followed by a newline or semicolon, it
is treated as a Jan wants. Otherwise, it's treated as a 'modifier'
flow control (if it's an if or unless or etc).

IMHO this is not feasible: "if <condition>" is almost always followed by
a line break. And think about

begin
puts "aaa"
end if
x > 100

This is perfectly legal with the current syntax but it looks like "end
if" would be a terminator while in reality it is a statement modifier.
I could write a RubyLexer-based preprocessor which does this pretty
easily. However, I'm not terribly motivated. This doesn't seem like
that useful a feature to me and I've got so much else to work on....

:)

Cheers

robert
 
C

Caleb Clausen

I don't want to advocate this but concatenating "end" directly with the
opening keyword is probably easy to do because it will create a whole
bunch of new tokens , so there would be

endclass
endmodule
enddef
endbegin
endif
endunless
endwhile
enduntil
endfor
enddo
endcase

Eh, I don't like it either.

IMHO this is not feasible: "if <condition>" is almost always followed by
a line break. And think about

Yes, but 'if' itself almost never is. So when the parser sees 'end'
followed by 'if' followed by newline, it can treat that specially.
begin
puts "aaa"
end if
x > 100

This is perfectly legal with the current syntax but it looks like "end
if" would be a terminator while in reality it is a statement modifier.

I did consider this. Who ever writes this way, instead of putting the
'if' and condition on the same line? In cases like this, I think it
would be acceptable to break broken style.
 
J

Jan Lelis

Thank you for all the opinions :)
endclass
endmodule
enddef
endbegin
endif
endunless
endwhile
enduntil
endfor
enddo
endcase

Did I miss one?

Each of those would be then alternatively allowed to "end", so you could
write

begin
if foo
else
case x
when y
when z
endcase
end
endbegin

I still don't like it.

I agree, that does not look good. But with a little punctation, it
becomes more readable:

begin
if foo
else
case x
when y
when z
end~case
end
end~begin

Also compare the readability of the whole list with the token version:

end~class
end~module
end~def
end~begin
end~if
end~unless
end~while
end~until
end~for
end~do
end~case

The token version might be easier to implement, but I think, it is not
satisfying.
I could write a RubyLexer-based preprocessor which does this pretty
easily. However, I'm not terribly motivated. This doesn't seem like
that useful a feature to me and I've got so much else to work on....

Cool :). I also want to try to implement it in some way, but at the
earliest in about a month (also have too many things to do).

@Brian
Thank you for this neat 1.9 indention warning hint :)
 
R

Robert Klemme

Thank you for all the opinions :)


I agree, that does not look good. But with a little punctation, it
becomes more readable:

.... and much less typeable on my keyboard (German).
begin
if foo
else
case x
when y
when z
end~case
end
end~begin

Also compare the readability of the whole list with the token version:

end~class
end~module
end~def
end~begin
end~if
end~unless
end~while
end~until
end~for
end~do
end~case

The token version might be easier to implement, but I think, it is not
satisfying.

The whole concept is dissatisfying to me. :)

Kind regards

robert
 
R

Robert Klemme

Eh, I don't like it either.



Yes, but 'if' itself almost never is.

Unfortunately the word "almost" makes this unusable for creating a
parser. How do you want the parser to decide if the case at hand is one
of the rare cases? Even if it would be feasible this sounds like an
awful hack and I'd rather not make parsing more complicated (and thus
slower) as it is today.
So when the parser sees 'end'
followed by 'if' followed by newline, it can treat that specially.


I did consider this. Who ever writes this way, instead of putting the
'if' and condition on the same line? In cases like this, I think it
would be acceptable to break broken style.

Let's hear what others say.

Kind regards

robert
 
C

Caleb Clausen

Unfortunately the word "almost" makes this unusable for creating a
parser. How do you want the parser to decide if the case at hand is one
of the rare cases? Even if it would be feasible this sounds like an
awful hack and I'd rather not make parsing more complicated (and thus
slower) as it is today.

The syntax change I proposed requires forbidding a construct which is
currently legal but rarely used and considered to be poor style. What
is wrong with that? In those few cases where someone decided to
separate an 'if' from its condition with a newline, the code would
have to be rewritten (inserting a backslash to make the newline soft
is the easiest way). Such constructs should be rewritten anyway, for
purely stylistic reasons.

This new feature, like most, will make the parser ever so slightly
slower. The delta is tiny and not worth mentioning.

And it will make the parser a little bit more complicated; however,
there are already many special cases and complications in the parser.
One more is not a big deal. The philosophy of ruby's syntax overall is
to make the parser complicated if it makes life easier for the user. I
think this change at least ought to be considered under that
criterion.

Now if you want to argue that Jan's proposal is esthetically
unpleasing, I won't really disagree. But just leave it at that. I hate
it when people try to throw up a lot of rhetorical chaff when their
real, and only valid, objection amounts to a subjective judgment call.
 
C

Caleb Clausen

Cool :). I also want to try to implement it in some way, but at the
earliest in about a month (also have too many things to do).

If you want help figuring out how to do this, I'll be glad to give you
advice, tho you'll have to write it. Doing something like this the
right way is going to be quite difficult unless you know where to
start, and even after that will be fairly tricky. Unless you're an
expert on parsing ruby, you need the assistance of someone (like me)
who is.

Of course, you could also do this the fragile/wrong way, using a lot
of regular expressions or something, in which case you'll probably be
able to manage it on your own.
 
R

Robert Klemme

2010/7/11 Caleb Clausen said:
The syntax change I proposed requires forbidding a construct which is
currently legal but rarely used and considered to be poor style. What
is wrong with that? In those few cases where someone decided to
separate an 'if' from its condition with a newline, the code would
have to be rewritten (inserting a backslash to make the newline soft
is the easiest way). Such constructs should be rewritten anyway, for
purely stylistic reasons.

I mostly agree apart from the missing aspect of efforts. Even such a
small change can cause significant other work to be done.
This new feature, like most, =A0will make the parser ever so slightly
slower. The delta is tiny and not worth mentioning.

And it will make the parser a little bit more complicated; however,
there are already many special cases and complications in the parser.
One more is not a big deal. The philosophy of ruby's syntax overall is
to make the parser complicated if it makes life easier for the user. I
think this change at least ought to be considered under that
criterion.

Now if you want to argue that Jan's proposal is esthetically
unpleasing, I won't really disagree. But just leave it at that. I hate
it when people try to throw up a lot of rhetorical chaff when their
real, and only valid, objection amounts to a subjective judgment call.

It's not only that. I question the balance of effort and benefit.
Since most code around does not use the new syntax, you will have to
support the old syntax as well. As long as it is not mandatory only
people benefit that use it. OTOH, there is additional effort for
backporting new code to projects that only use an old Ruby
interpreter. Given that we do not have this feature today and most
people seem to be able to write code that gets the nesting right I
wonder what the real benefit of this is given that there will be
development effort for the interpreter, test cases, documentation etc.

Uglyness was really just a side aspect although I agree I should have
made this more clear. Somehow I must have assumed that the other
points are obvious. :)

Cheers

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
C

Caleb Clausen

It's not only that. I question the balance of effort and benefit.
Since most code around does not use the new syntax, you will have to
support the old syntax as well. As long as it is not mandatory only

Well, it has to be optional for another reason too: it would be far to
annoying to have to type 'end if' instead of 'end' at the end of every
if statement. I for one wouldn't be willing to sacrifice ruby's
celebrated terseness in this area just to make Jan happy.
people benefit that use it. OTOH, there is additional effort for
backporting new code to projects that only use an old Ruby
interpreter. Given that we do not have this feature today and most
people seem to be able to write code that gets the nesting right I
wonder what the real benefit of this is given that there will be
development effort for the interpreter, test cases, documentation etc.

Uglyness was really just a side aspect although I agree I should have
made this more clear. Somehow I must have assumed that the other
points are obvious. :)
I mostly agree apart from the missing aspect of efforts. Even such a
small change can cause significant other work to be done.

Ok, now this is a valid point, and one I tend to forget about.
Complicating code makes related work products more complicated but as
a single-minded engineer I only think about the code.

Additionally, I now see that there are some ambiguities around the
keyword 'do' which would have to be worked through before my proposal
could be implemented. So for example, this is valid currently:

something begin
42
end do
foo
end

But with the proposed new syntax, the 'end do' would be interpreted as
an attempt to end a do block. I'm not sure what, if anything, can be
done about this, or if it's just an issue that can be ignored.
 
J

Jan Lelis

[...] I question the balance of effort and benefit.
Since most code around does not use the new syntax, you will have to
support the old syntax as well. As long as it is not mandatory only
people benefit that use it. OTOH, there is additional effort for
backporting new code to projects that only use an old Ruby
interpreter.

The backporting effort for 99% of the cases: code.gsub /end~(class|
module|def|begin|if|unless|while|until|for|do|case)/, 'end'

Given that we do not have this feature today and most
people seem to be able to write code that gets the nesting right I
wonder what the real benefit of this is given that there will be
development effort for the interpreter, test cases, documentation etc.

Of course, you are able to write code with the right nesting, else it
wouldn't run ;). That doesn't mean, that it is easy to write or read.
Uglyness was really just a side aspect although I agree I should have
made this more clear. Somehow I must have assumed that the other
points are obvious. :)

Is it really that ugly? I want to emphasize that the additions would be
optional. I really think of using it only, when there are three ore more
consecutive ends. But then, it is really helpful (please also see the
example at bottom).
[...] Even such a
small change can cause significant other work to be done.

That is true :/
If you want help figuring out how to do this, I'll be glad to give you
advice, tho you'll have to write it. Doing something like this the
right way is going to be quite difficult unless you know where to
start, and even after that will be fairly tricky. Unless you're an
expert on parsing ruby, you need the assistance of someone (like me)
who is.

Thank you for this nice offer. I would gladly take it :) [but as I said,
I have much to to do, so it would be possible at the earliest in about a
month].

But we still have different opinions about whether the syntax would
involve punctuation. I think with it, the code is better readable in
cases like this:

def test
while 1
puts (1..9).each_slice(3).map do |slice|
sum = slice.inject do |acc, ele|
acc + ele
end

if sum > 6
42
else
99
end~if
end~do.join ','
end~while
end
 
B

Bob Nadler

[...] I question the balance of effort and benefit.
Since most code around does not use the new syntax, you will have to
support the old syntax as well. =A0As long as it is not mandatory only
people benefit that use it. =A0OTOH, there is additional effort for
backporting new code to projects that only use an old Ruby
interpreter.

The backporting effort for 99% of the cases: code.gsub /end~(class|
module|def|begin|if|unless|while|until|for|do|case)/, 'end'

Given that we do not have this feature today and most
people seem to be able to write code that gets the nesting right I
wonder what the real benefit of this is given that there will be
development effort for the interpreter, test cases, documentation etc.

Of course, you are able to write code with the right nesting, else it
wouldn't run ;). That doesn't mean, that it is easy to write or read.
Uglyness was really just a side aspect although I agree I should have
made this more clear. =A0Somehow I must have assumed that the other
points are obvious. :)

Is it really that ugly? I want to emphasize that the additions would be
optional. I really think of using it only, when there are three ore more
consecutive ends. But then, it is really helpful (please also see the
example at bottom).
[...] Even such a
small change can cause significant other work to be done.

That is true :/
If you want help figuring out how to do this, I'll be glad to give you
advice, tho you'll have to write it. Doing something like this the
right way is going to be quite difficult unless you know where to
start, and even after that will be fairly tricky. Unless you're an
expert on parsing ruby, you need the assistance of someone (like me)
who is.

Thank you for this nice offer. I would gladly take it :) [but as I said,
I have much to to do, so it would be possible at the earliest in about a
month].

But we still have different opinions about whether the syntax would
involve punctuation. I think with it, the code is better readable in
cases like this:

def test
=A0while 1
=A0 =A0puts (1..9).each_slice(3).map do |slice|
=A0 =A0 =A0sum =3D slice.inject do |acc, ele|
=A0 =A0 =A0 =A0acc + ele
=A0 =A0 =A0end

=A0 =A0 =A0if sum > 6
=A0 =A0 =A0 =A042
=A0 =A0 =A0else
=A0 =A0 =A0 =A099
=A0 =A0 =A0end~if
=A0 =A0end~do.join ','
=A0end~while
end
Hi,
I know it's a bit of a contrived example, and I'm not advocating a version
of "Ruby Golf" here, but if I saw this method in some code I was maintainin=
g
I would refactor it to something like:

def test
while 1
puts (1..9).each_slice(3).map do |slice|
sum =3D slice.inject { |acc, ele| acc + ele }
sum > 6 ? 42 : 99
end.join(',')
end
end

...or even better, move the "summing" to another method...

def test
while 1
puts (1..9).each_slice(3).map do |slice|
calculate_sum > 6 ? 42 : 99
end.join(',')
end
end

def calculate_sum(items)
items.inject { |acc, ele| acc + ele }
end

I think most cases where the end~if syntax is "necessary" would be better o=
ff
(e.g. more readable) with a healthy dose of refactoring.
 
J

Jan Lelis

def test
Hi,
I know it's a bit of a contrived example, and I'm not advocating a version
of "Ruby Golf" here, but if I saw this method in some code I was maintaining
I would refactor it to something like:

def test
while 1
puts (1..9).each_slice(3).map do |slice|
sum = slice.inject { |acc, ele| acc + ele }
sum > 6 ? 42 : 99
end.join(',')
end
end

...or even better, move the "summing" to another method...

def test
while 1
puts (1..9).each_slice(3).map do |slice|
calculate_sum > 6 ? 42 : 99
end.join(',')
end
end

def calculate_sum(items)
items.inject { |acc, ele| acc + ele }
end

I think most cases where the end~if syntax is "necessary" would be better off
(e.g. more readable) with a healthy dose of refactoring.

Of course, the example was made up to demonstrate the ends and not real
world code. I would not write it in this way, either...

This one is from existing code:

module ABC

# ...

def abc
x.each do
if x

case lorem

when :ipsum
# ...
when :ipsum
# ...
when :ipsum
# ...
when :ipsum
# ...
else
# ...
end
end
end
end
end
 

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,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top