For ... else ... end

For the keyword war: (silly, dummy example)

cnt=0
for i in anArray do
break if i<0
res=19*i+4-i
puts res
cnt+=res
else
puts “Empty array”
on_exit
puts “The result is #{cnt}”
on_break # or on_abort

ok, I admit it is like an exception…

puts “Invalid negative element found in the array!”
end

So, in any kind of loop:

else : code block is not executed
on_exit : code block is executed, and terminated normally
on_break / on_abort : code block executed and exited via ‘break’

These modifiers are in connection with the whole loop, not one
iteration, so perhaps another arrangement will be better.

Gergo
±[Kontra, Gergely @ Budapest University of Technology and Economics]-+

    Email: kgergely@mcl.hu,  kgergely@turul.eet.bme.hu          |

URL: turul.eet.bme.hu/~kgergely Mobile: (+36 20) 356 9656 |
±------“Olyan langesz vagyok, hogy poroltoval kellene jarnom!”-------+
.
Magyar php mirror es magyar php dokumentacio: http://hu.php.net

I’d add “afterwards” as the most logical English keyword:

for …
# do stuff
afterwards
# do stuff
end

But then it’s not clear if afterwards gets done always, or only
if the loop iterates completely.

I don’t think “ensure” should be used, because that seems like
it should always be executed upon exiting the iterator regardless
of if it completely iterated or was broken out of.

I think the “else” syntax for indicating code that should be
executed when the iterator is empty is cool, but unnecessary
as there are other ways of implementing the same behavior just
as clearly. I definitely think the choice of “else” in Python
was a poor choice as you’re really not doing “this or else that”
with regard to the iterator.

I think “then” might be the more appropriate keyword:

for …
# do stuff
then
# do stuff when finished iterating
end

Breaking out of the iterator breaks out of the whole construct,
skipping the “then” clause code.

– Dossy

···

On 2002.07.09, Sean Russell ser@germane-software.com wrote:

Yukihiro Matsumoto wrote:

But I don’t feel “for … else” is intuitive. The “else” seem like
indentation mistake rather than loop termination hook. Maybe there
can be a more suitable keyword.

Here are the suggestions, so far:

    else
    ensure
    finally


Dossy Shiobara mail: dossy@panoptic.com
Panoptic Computer Network web: http://www.panoptic.com/
“He realized the fastest way to change is to laugh at your own
folly – then you can let go and quickly move on.” (p. 70)

replacing 'exceptions' with 'breaks' of a for-loop

What do you call a `for' loop ?

For me

    for i in 1..2
    end

is the same than

   (1..2).each do |i|
   end

except for block local variables.

Guy Decoux

> for elt in arr
> puts elt
> else
> puts "no rows"
> ensure
> puts "done looping"
> end

Ahm, this seems a slightly different problem.
Here the else marks the case that the loop
_never_ has been entered, not interrupted by 'break'.

And what do you suggest with 'ensure' ("done looping")
here?

ensure should catch break... break strikes me as being identical to an
exception that's caught at the end of the loop. Truthfully though, I
was more excited about catching the case when a loop wasn't entered
(ex: 0 rows from the DB), vs when a break is thrown. If you want an
"else", then use a normal exception block... though it is nice sugar
to have in the language I suppose (albeit slightly confusing to the
uninformed). <:~) -sc

···

--
Sean Chittenden

David Alan Black schrieb:

puts if arr.empty? then “no rows” else arr end

puts (arr.empty? ? “no rows” : arr )

:wink:

Det

Hello David,
What about:

while very_time_consuming_operation
do_something
else
do_something_else
end

or:

while a and b and c or d and e and f and g #and so on, i.e. a complex
#condition
do_something
else
do_something_else
end

I know it’s possible to rewrite those snippets without using an
else-construct. But I think they are easier to understand.

···


Best regards,
Jonas

The brain is a wonderful organ. It starts working the moment you get
up in the morning, and does not stop until you get into the office.

  • Robert Frost

Tuesday, July 09, 2002, 12:28:32 PM, you wrote:

Hi –

On Tue, 9 Jul 2002, Sean Chittenden wrote:

Hmm… I work around not having this construct constantly when doing
database work. After talking with Holden about this on IRC, I think
the following examples are helpful.

dbh.select_all(sql) do |row|

do something with row

else
puts “No rows returned!”
end

To me this introduces a seriously criss-crossed quality to the logic
flow. You’d end up with things like:

arr = [1,2,3,4]
f = arr.find_all {|n| n > 4 else puts “Not found”}

for elt in arr
puts elt
else
puts “No rows processed”
end

Which opens the door for:

for elt in arr
puts elt
else
puts “no rows”
ensure
puts “done looping”
end

Hmm… I think else is the correct word because it is short hand for
typing out:

if .length > 0
for elt in
puts elt
end
else
puts “now rows”
end
puts “done looping”

The example immediately above strikes me as a way of working around
the language, as opposed to the language doing what you want it to.
::shrug:: My $0.02. -sc

puts if arr.empty? then “no rows” else arr end
puts “done looping”

(Couldn’t resist :slight_smile:

How about:

if arr.empty?
puts “no rows”
else
for elt in arr
# do stuff
end
end

But in any case, I agree with Det who pointed out that this
(determining whether a loop is executed/entered at all) is different
from the ‘break’-trapping scenario.

David

They’re not, though. It’s entirely possible that the begin … end
block rethrows an exception or throws its own exception after
receiving an exception. The ensure clause requires that the code
within it be executed, even if the block is left because of a
thrown, uncaught, or rethrown exception.

-austin
– Austin Ziegler, austin@halostatue.ca on 2002.07.09 at 10.34.47

···

On Tue, 9 Jul 2002 18:10:01 +0900, Dirk Detering wrote:

Regarding the ‘ensure’ … I think I did not understand if it is
a necessary part or only declarative sugar, as IMHO every code
after the end is run in either case.

So writing:

f = File.open(“testfile”)
begin

… process

[…]
ensure
f.close
end

or writing:

f = File.open(“testfile”)
begin

… process

[…]
end
f.close

I like your naming, but will it work as well for:

cnt=0
anArray.each do |i|
break if i<0
res=19*i+4-i
puts res
cnt+=res
else
puts “Empty array”
on_exit
puts “The result is #{cnt}”
on_break # or on_abort
# ok, I admit it is like an exception…
puts “Invalid negative element found in the array!”
end

More than that, what will happen if else/on_exit/on_break is done in
a non-looped block? As far as I can tell, blocks don’t have any
context as to whether they are run in a loop or not. If I’m
implementing my own mytype#each, how do I make this work? How do I
yield to the blocks that else/on_exit/on_break represent?

-austin
– Austin Ziegler, austin@halostatue.ca on 2002.07.09 at 10.38.39

···

On Tue, 9 Jul 2002 23:19:05 +0900, Kontra, Gergely wrote:

For the keyword war: (silly, dummy example)

cnt=0
for i in anArray do
break if i<0
res=19*i+4-i
puts res
cnt+=res
else
puts “Empty array”
on_exit
puts “The result is #{cnt}”
on_break # or on_abort
# ok, I admit it is like an exception…
puts “Invalid negative element found in the array!”
end

So, in any kind of loop:

else : code block is not executed
on_exit : code block is executed, and terminated normally
on_break / on_abort : code block executed and exited via ‘break’

These modifiers are in connection with the whole loop, not one
iteration, so perhaps another arrangement will be better.

Sean Chittenden schrieb:

And what do you suggest with ‘ensure’ (“done looping”)
here?

ensure should catch break… break strikes me as being
identical to an exception that’s caught at the end of
the loop.

question-mark above my head

But … this does not correlate to the
‘ensure’ semantic in begin…end.

There the ensure does not catch anything.
On the contrary it declares coding to run
everytime , not regarding exceptions or
success.

(And to answer my own question:
Regarding the Pickaxe it runs also
for uncaught exceptions, in which case
the code following the end would not be executed).

Truthfully though, I
was more excited about catching the case when a loop wasn’t entered
(ex: 0 rows from the DB), vs when a break is thrown.

If you want an
“else”, then use a normal exception block…

You mean catch/throw ?
As I’ve been taught in this thread that catch/throw is
for flow control and exception for error handling.

though it is nice sugar
to have in the language I suppose (albeit slightly confusing to the
uninformed). <:~) -sc

Yes … that’s exactly why we talk about
keywords and semantics …

Bye
Det

ts schrieb:

What do you call a `for’ loop ?

Generally: An iterative loop.
(iterative means: every entry starts with a
new parameter. Maybe the next list item, or
an incremented value or something like that).

For me
for i in 1…2
end
is the same than
(1…2).each do |i|
end

except for block local variables.

Aha!!   ;-)   

Well that may be the current state.
But what about thinking of a for loop as
a syntactic sugar of a catch/throw construct?

The topic we discuss here is based on
the feeling, that some more complex flow
control should be easily expressable
by language support.

What possibilities does Ruby currently have to
express the following scheme completely?
(parts of it have just been shown in this
thread):

iterate over elements in container
if no elements were found do …
if loop completes without break do …
if loop has been interrupted with break do …

Can all this easily be expressed via catch/throw ?

Bye
Det

Tuesday, July 09, 2002, 11:34:50 AM, Sean wrote:

Truthfully though, I
was more excited about catching the case when a loop wasn’t entered
(ex: 0 rows from the DB), vs when a break is thrown.

Sean,
I agree! I can’t think of when I would like to distinguish how the
loop has been exited. But I can think of many cases where I would like
to know if it has been entered or not.

I’m not a Python-expert but I thought that Python’s else-construct for
loops is used for those cases.

···


Best regards,
Jonas

Give a man a fire and he’s warm for a day, but set him on fire and
he’s warm for the rest of his life.

  • Terry Pratchett

Austin Ziegler schrieb:

They’re not, though. It’s entirely possible that the begin … end
block rethrows an exception or throws its own exception after
receiving an exception.
[…]

Yes, I answered this question to myself some mails
ago. But you affirm, what I understood from the book
was correct.

MTNX

Det

Hello –

cnt=0
anArray.each do |i|
break if i<0
res=19*i+4-i
puts res
cnt+=res
else
puts “Empty array”
on_exit
puts “The result is #{cnt}”
on_break # or on_abort
# ok, I admit it is like an exception…
puts “Invalid negative element found in the array!”
end

I still don’t see how a code block can have an ‘else’ clause.
Wouldn’t this make for some awfully bizarre code?

array.each {|e| else puts “Empty array”}

Given an empty array, this else clause would execute. It seems to me
to be crossing all sorts of borders and boundaries for a proc/block to
have this kind of knowledge. Is a block of code really supposed to
know whether or not it was executed, without any explicit test? And,
come to think of it… shouldn’t the block not be entered at all if
the array is empty? What the “else” thing means is that the block
will be entered. I wish I knew the technical term for why that
isn’t OK :slight_smile: but doesn’t it feel very non-OK?

I guess this thread is bringing out my Ruby-conservative streak :slight_smile:
I’m personally very happy to do something like this (which I know
isn’t identical to your example, but still):

if arr.empty?
puts “Empty array”
elsif arr.detect {|x| x < 0}
puts “Illegal negative number!” # or raise and catch TypeError
else
total = arr.inject(0) do |n,m|
tmp = n + (19*m+4-m)
puts tmp
tmp
end
puts “The result is #{total}”
end

(requires 1.7.x, whichever one #inject was added to :slight_smile:

David

···

On Tue, 9 Jul 2002, Austin Ziegler wrote:


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Jonas Bengtsson schrieb:

But I can think of many cases where I would like
to know if it has been entered or not.

I’m not a Python-expert but I thought that Python’s else-construct for
loops is used for those cases.

No it isn’t.
Read my doc-extract in former mails

Det

I still don’t see how a code block can have an ‘else’ clause.
Wouldn’t this make for some awfully bizarre code?

I can’t, either – which is why I’m asking the questions:

  1. How would this work in a case where there is no loop, but just a
    block?
  2. How would I construct my own each member function to take
    advantage of the else (and possibly other clauses)?

I can see the utility of the construct, but I think it makes a lot
more sense in languages where there are real control structures.

array.each {|e| else puts “Empty array”}

Given an empty array, this else clause would execute. […] And,
come to think of it… shouldn’t the block not be entered at all
if the array is empty? What the “else” thing means is that the
block will be entered. I wish I knew the technical term for why
that isn’t OK :slight_smile: but doesn’t it feel very non-OK?

Agreed. I’d prefer to do that as:

puts “Empty array” if array.empty?
array.each { |e| puts e } unless array.empty?

It might be nice to have some syntactic sugar that does something
like that:

array.each { |e| puts e } unless array.empty then puts “Empty array”

(Not currently possible, AFAIK, and probably really nasty in the
interpretation of same.)

Why not something like:

case array.each { |e| puts e }
when array.empty?
puts “Empty array”
when broken # The ugly part
puts “Broke from each early”
else
puts “Done processing”
end

I don’t know if that will work (except, of course, ‘broken’, which
won’t work), but it seems to be conceptually cleaner. IMO.

It seems to me to be crossing all sorts of borders and boundaries
for a proc/block to have this kind of knowledge. Is a block of
code really supposed to know whether or not it was executed,
without any explicit test?

I think that it’s a bad idea, myself.

I guess this thread is bringing out my Ruby-conservative streak :slight_smile:
I’m personally very happy to do something like this (which I know
isn’t identical to your example, but still):

FWIW, this was someone else’s example that I adapted from a
for…end format to an each do…end format – because I don’t think
that it’s necessarily a good way of doing it.

-austin
– Austin Ziegler, austin@halostatue.ca on 2002.07.09 at 13.06.12

···

On Wed, 10 Jul 2002 01:52:38 +0900, David Alan Black wrote:

class Array
def each_if_empty(blk1, &blk2)
if empty?
return blk1.call
else
each(&blk2)
return self
end
end
end

.each_if_empty(proc{ p ‘is empty’ }) { |item| p item }

[1,2,3].each_if_empty(proc{ p ‘is empty’ }) { |item| p item }

···

On Tuesday 09 July 2002 10:18 am, Austin Ziegler wrote:

It might be nice to have some syntactic sugar that does something
like that:

array.each { |e| puts e } unless array.empty then puts “Empty
array”

(Not currently possible, AFAIK, and probably really nasty in the
interpretation of same.)


Ned Konz
http://bike-nomad.com
GPG key ID: BEEA7EFE

Hi –

I still don’t see how a code block can have an ‘else’ clause.
Wouldn’t this make for some awfully bizarre code?

[…]

array.each {|e| else puts “Empty array”}

Given an empty array, this else clause would execute. […] And,
come to think of it… shouldn’t the block not be entered at all
if the array is empty? What the “else” thing means is that the
block will be entered. I wish I knew the technical term for why
that isn’t OK :slight_smile: but doesn’t it feel very non-OK?

Agreed. I’d prefer to do that as:

puts “Empty array” if array.empty?
array.each { |e| puts e } unless array.empty?

It might be nice to have some syntactic sugar that does something
like that:

array.each { |e| puts e } unless array.empty then puts “Empty array”

Hmmm… unless I’m missing something, this can be done very simply:

if array.empty?
puts “Empty array”
else
array.each {|e| puts e}
end

or even:

puts “Empty array” if array.each {|e| puts e}.empty?

since Array#each returns the original array. (But that has a slightly
inside-out feel to it.)

(Of course if it’s really just #puts, then:

puts if array.empty? then “Empty array” else array end

(or ternary operator equivalent, as I think Det pointed out)

but that can’t be generalized :slight_smile:

FWIW, this was someone else’s example that I adapted from a
for…end format to an each do…end format – because I don’t think
that it’s necessarily a good way of doing it.

Sorry if I was attributing too much to you… it was actually hard to
find exactly the right point of entry into the thread!

David

···

On Wed, 10 Jul 2002, Austin Ziegler wrote:

On Wed, 10 Jul 2002 01:52:38 +0900, David Alan Black wrote:


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Austin Ziegler wrote:

I still don’t see how a code block can have an ‘else’ clause.
Wouldn’t this make for some awfully bizarre code?

I can’t, either – which is why I’m asking the questions:

  1. How would this work in a case where there is no loop, but just a
    block?
  2. How would I construct my own each member function to take
    advantage of the else (and possibly other clauses)?

Instead of passing one block with ‘else’ or ‘on_exit’ clauses in it, I
think you’d have to pass multiple blocks in: one normal block, one
“else” block, one “on_exit” block, etc. Currently, the only way to do
that is by throwing some Procs in with the args, right?

How 'bout a more general construct which makes passing in multiple
blocks less messy:

arr.each do |el|

stuff

block :on_abort do |*args|

stuff

block :on_exit do |*args|

stuff

#etc.
end

where block' is a keyword used to separate/name blocks. Inside the method, you'd invoke the named blocks by their name (the anonymous block at the top, if present, would still be invoked with yield’):

class Array
def each
if empty?
yield_named :on_empty if block_given?(:on_empty)
else
if catch :broken # see [1]
if block_given?
(0…length).each do |i|
yield self[i] # anonymous block
end
end
yield_named :on_exit if block_given?(:on_exit)
false
end
yield_named(:broken) if block_given?(:broken)
end
end
end
end

[1] How do you detect if the block was broken? I pretend here break' == throw :broken, true’.

Or with multiple anonymous blocks:

def foo
yield_anon 0 if anon_blocks.length > 0
yield_anon 1 if anon_blocks.length > 1
end

foo do

anonymous block 1

block do

anonymous block 2

end

Using symbols for block names implies you could also use arbitrary
objects as block names. The blocks passed could be accessed as a Hash
if you want to act on blocks based on their names. Contrived e.g.:

class HtmlParser
def each_tag
blocknames = block_hash.keys
@html.scan /<(.*?)>/m do # inadequate regex, but for e.g.
blocknames.each do |re|
if re =~ $1
yield_named block_hash[re], $~
break
end
end
end
end
end

Yes, I know there are plenty of clean ways to do that HtmlParser example
using current Ruby. No, I don’t know if there exists any scenarios where
any of this would be a real advantage. I’m just throwing another crazy,
probably stupid, possibly flawed idea in the air for people to play
with/dismiss.

···

On Wed, 10 Jul 2002 01:52:38 +0900, David Alan Black wrote:

I’ve got the feeling that this thread is
drifting from the original problem (detect
successful looping) to the discussion about
some related but different problems.

But now I miss the global view of a
loop construction syntax handling the
different passways of a loop.

We never claimed that there is no way
to do this or that with Ruby.
(See below).
The subject is about a principle loop
construct as syntactic sugar for
easily describe the different passes?

Problem 1: Identify bypassing (e.g. empty array)
and declare coding that shall run in this case

Problem 2: Identify interruption (by break or throw)
and declare coding that shall run in this case

Problem 3: Identify full passing (no break)
and declare coding that shall run in this case.

David Alan Black schrieb:

if array.empty?
puts “Empty array”
else
array.each {|e| puts e}
end

Ok, this solves problem 1 in some way (although it
does not ‘identify’ the bypassing itself, but checks
explicitly a precondition). So in relation to loops
you would check a condition twice:

if a > b
while a > b

end
else

end

The catch/throw solves problem 3 and, yes, problem 2
in some kind (suggestion of Marcin Kowalczyk):

j = 3 # or j = 11 or greater
catch (:done) do
for i in 1…10
if i == j
print “Interruption branch\n”
throw :done
end
print “Working in loop \n”
end
print “Loop terminated without break\n”
end

Although it is a matter of design decision if the full code of the break-branch should be written at this point ('print "Interruption...') or at a specific place external to this algorithm. Well, this could be done in a special text block of a defined syntax construct ( an 'on_break' or whatever) or in by calling a function/method at this point.

So the complete example looks something like:

if array.empty?
print “Loop bypassed \n”
else
catch (:done) do
for i in array
if #
print “Interruption branch\n”
throw :done
end
print “Working in loop \n”
end
print “Loop terminated without break\n”
end
end

Now I have the different cases of my loop termination on different places with different indentations ... The primary goal, expressed with "Working in loop" is somewhat hidden between the control stuff and all.

Hum, the discussed construct with different
for-branches would simplify things … don’t you
think too?

Bye
Det

How 'bout a more general construct which makes passing in multiple
blocks less messy:

What is the reason one cannot pass multiply block simply

method_with_2_blocks {
block1
} {
block2
}

Gergo

±[Kontra, Gergely @ Budapest University of Technology and Economics]-+

    Email: kgergely@mcl.hu,  kgergely@turul.eet.bme.hu          |

URL: turul.eet.bme.hu/~kgergely Mobile: (+36 20) 356 9656 |
±------“Olyan langesz vagyok, hogy poroltoval kellene jarnom!”-------+
.
Magyar php mirror es magyar php dokumentacio: http://hu.php.net