Home grown continuations

DISCLAIMER: It has been said that continuations can cause brain damage… I
am not liable for any such damage if you read further.

I was thinking about closures, continuations, etc., and I suddenly had this
thought that I might be able to “roll my own” continuations using closures.
It doesn’t seem to work, though. Can anyone tell me why?

def make_c
yield(proc{|*r| return r})
end

puts(make_c do |c|
puts "In continuation…"
c.call(“Done”)
puts "…oops"
end)

C:\ruby-projects>ruby t.rb
In continuation…
…oops
nil

It’s obvious that calling return in a block doesn’t do what I thought it
did… so what does it do?

Nathaniel

P.S. Yes, I know about callcc… I was just playing.

<:((><

Hi,

···

In message “Home grown continuations” on 03/08/03, “Nathaniel Talbott” nathaniel@NOSPAMtalbott.ws writes:

I was thinking about closures, continuations, etc., and I suddenly had this
thought that I might be able to “roll my own” continuations using closures.
It doesn’t seem to work, though. Can anyone tell me why?

Since 1.8, return within the closures created by proc or lambda, just
terminates the closure execution. If you create a closure by
Proc.new, it causes error, since call frame information is already
lost unlike callcc.

						matz.

Nathaniel, although I’m not doing something a bit different than what
you are attempting, you might still enjoy the following links …

http://onestepback.org/index.cgi/Tech/Programming/Kata/KataTwoCps.rdoc
http://onestepback.org/index.cgi/Tech/Programming/Kata/KataTwoNoTail.rdoc
http://onestepback.org/index.cgi/Tech/Programming/Kata/KataTwoCallCC.rdoc

···

On Sat, 2003-08-02 at 11:52, Nathaniel Talbott wrote:

DISCLAIMER: It has been said that continuations can cause brain damage… I
am not liable for any such damage if you read further.

I was thinking about closures, continuations, etc., and I suddenly had this
thought that I might be able to “roll my own” continuations using closures.


– Jim Weirich jweirich@one.net http://onestepback.org

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

Fascinating. Good thing we have callcc :slight_smile:

Nathaniel

<:((><

···

Yukihiro Matsumoto [mailto:matz@ruby-lang.org] wrote:

Since 1.8, return within the closures created by proc or
lambda, just terminates the closure execution. If you create
a closure by Proc.new, it causes error, since call frame
information is already lost unlike callcc.

Since 1.8, return within the closures created by proc or lambda, just
terminates the closure execution.

Huh? I’m not sure I am understanding. What should the following
return?

def x
10.times { |n| return 1 if n == 5 }
2
end
p x

I would expect 1, but you seem to be saying 2.

If you create a closure by
Proc.new, it causes error, since call frame information is already
lost unlike callcc.

So Proc.new is different? What about the following code?

def y
p = Proc.new { |n| return 1 if n == 5 }
10.times(&p)
2
end

Again, I would expect 1, but you seem to be saying it will be an error.

BTW, both return 1 in an not-very-recent version of 1.8.0. (But that
might be different in the previews).

···

On Sat, 2003-08-02 at 12:02, Yukihiro Matsumoto wrote:


– Jim Weirich jweirich@one.net http://onestepback.org

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

Jim Weirich wrote:

def y
p = Proc.new { |n| return 1 if n == 5 }
10.times(&p)
2
end

Again, I would expect 1, but you seem to be saying it will be an error.

BTW, both return 1 in an not-very-recent version of 1.8.0. (But that
might be different in the previews).

Here is what I got with (ruby 1.8.0 (2003-08-03) [i386-mswin32]).

···

On Sat, 2003-08-02 at 12:02, Yukihiro Matsumoto wrote:


def X(t)
m = 5 if t == 5
return Proc.new { || 1 if m == 5 }
end

def Y(t)
m = 5 if t == 5
return Proc.new { || 1 if m == 5 }
end

def Z(t)
m = 5 if t == 5
return Proc.new { || return 1 if m == 5 }
end

p X(3).call, X(5).call # nil, 1
p Y(3).call, Y(5).call # nil, 1
p Z(3).call, Z(5).call # LocalJumpError

There was a time in somewhat more distant past (when there was
only one type of procs) were returns weren’t allowed in any type of
procs (assuming my failing memory serves me right;-).
Thank you very much for pointing that this restriction is (half;-)gone.

/Christoph

Hello,

Since 1.8, return within the closures created by proc or lambda, just
terminates the closure execution.

Huh? I’m not sure I am understanding. What should the following
return?

def x
10.times { |n| return 1 if n == 5 }
2
end
p x

I would expect 1, but you seem to be saying 2.

It would be 1. Don’t worry. It’s not created with proc nor lambda.

If you create a closure by
Proc.new, it causes error, since call frame information is already
lost unlike callcc.

So Proc.new is different? What about the following code?

def y
p = Proc.new { |n| return 1 if n == 5 }
10.times(&p)
2
end

Again, I would expect 1, but you seem to be saying it will be an error.

It would be 1 again. It causes error when the call frame is lost. In
your example, the method created a proc still running so that the call
frame exists too.

						matz.
···

In message “Re: Home grown continuations” on 03/08/03, Jim Weirich jweirich@one.net writes: