About Extending Systax

S

Sam Kong

Hi!

A friend of mine challenged me with Smalltalk.
He's a big fan of Smalltalk.
He asked me what I can do if I want to add "try ~ finally ~" systax in
Ruby.
Yes, we already have "begin ~ ensure ~".
But he asked me whether Ruby is flexible enough to extend such a thing
without changing the language itself.
He said that Smalltalk doesn't have "try ~ finally ~" in the language
but can be defined without changing the language.

Personally, I don't think such flexibility is really needed.
However, I want to defend Ruby.
How would you react such an attack?

Disclaimer: This post is not for language flame war but for better
understanding of Ruby.

Thanks.

Sam
 
J

Jim Weirich

Sam said:
Hi!

A friend of mine challenged me with Smalltalk.
He's a big fan of Smalltalk.
He asked me what I can do if I want to add "try ~ finally ~" systax in
Ruby.
Yes, we already have "begin ~ ensure ~".
But he asked me whether Ruby is flexible enough to extend such a thing
without changing the language itself.
He said that Smalltalk doesn't have "try ~ finally ~" in the language
but can be defined without changing the language.

Personally, I don't think such flexibility is really needed.
However, I want to defend Ruby.
How would you react such an attack?

There are several ways this could be done ... here is one:

class TryFinally
def initialize(block)
@block = block
end
def finally
@block.call
ensure
yield
end
end

def try(&block)
TryFinally.new(block)
end

Usage:

try {
puts "Trying"
fail "oops"
}.finally {
puts "Always printed"
}

It is a bit little easier in Smalltalk because of the use of keywords in
an argument list, but still quite doable in Ruby.
 
L

Lou Vanek

nice

Jim said:
Sam said:
[snip]


There are several ways this could be done ... here is one:

class TryFinally
def initialize(block)
@block = block
end
def finally
@block.call
ensure
yield
end
end

def try(&block)
TryFinally.new(block)
end

Usage:

try {
puts "Trying"
fail "oops"
}.finally {
puts "Always printed"
}

It is a bit little easier in Smalltalk because of the use of keywords in
an argument list, but still quite doable in Ruby.
 
S

Sam Kong

Jim said:
There are several ways this could be done ... here is one:

class TryFinally
def initialize(block)
@block = block
end
def finally
@block.call
ensure
yield
end
end

def try(&block)
TryFinally.new(block)
end

Usage:

try {
puts "Trying"
fail "oops"
}.finally {
puts "Always printed"
}

It is a bit little easier in Smalltalk because of the use of keywords in
an argument list, but still quite doable in Ruby.

This is nice.
But my intention is not to make a new syntax that does the same thing.
Let's assume that there's no *ensure* syntax in Ruby.

Sam
 
L

Logan Capaldo

Here's another go at it using continuations:

% cat try_catch_throw.rb
class Flow
def initialize(parent = nil)
@exceptions = []
@parent = parent
@uncaught_exception = nil
end
def try(&block)
@try_block = block
end

def throw(exception)
caught = @exceptions.each do |key, value|
if key === exception
value.call(exception)
break true
end
end

unless caught == true
if @parent
@parent.throw(exception)
else
@uncaught_exception = exception
end
end
@cc.call
end

def finally(&block)
@finally = block
self
end

def catch(exception, &block)
@exceptions << [exception, block]
self
end
def go
callcc { |@cc| @try_block.call }
if @finally
@finally.call
end
if @uncaught_exception
STDERR.puts "Uncaught exception: #{@uncaught_exception}"
exit(1)
end
end

end




% cat test_flow.rb
require 'try_catch_throw'


handling2 = Flow.new
handling2.try {
handling3 = Flow.new(handling2)
handling3.try {
puts "Nested try"
handling3.throw "ERROR! in handling3"
}
handling3.go
}

handling2.catch(String) do |exception|
puts "handling2 Caught exception: #{exception}"
end

handling2.go

handling = Flow.new

handling.try {
puts "Hello"
handling.throw "ERROR!"
puts "World"
}
handling.finally {
puts "Finally"
}

handling.go


% ruby test_flow.rb
Nested try
handling2 Caught exception: ERROR! in handling3
Hello
Finally
Uncaught exception: ERROR!

At first I tried to do it without continuations but I couldn't think
of a way to do so. Also the nesting is explicit which has the
advantage of not using global vars and the disadvantage of excessive
typing.
 

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
474,202
Messages
2,571,057
Members
47,662
Latest member
salsusa

Latest Threads

Top