Csaba Henk wrote: >>I'm curious about the implementation that makes this work. Could you >>please post it. > > > Here you go: <snipped code> Thanks for that. At first I was confused as to why you returned rv in the else block of TrueModule and also why you didn't just call the block in the ifthen of the TrueModule. Then I realised that you wanted to have the correct return value just like the builtin if..then..else..end syntax. Very nice. What is the threading problem? It looks ok to me... :-) It's annoying that ifthen doesn't work when there is no else block and that calling else directly on true fails but on false it works. I didn't know about calling a block with [] rather than .call. That's cool but I prefer .call for now. Neither about sending :include message to classes - that's not something I would have thought of. I came up with some code to do the unless and when methods for single argument versions of if and if not. I also came up with if_then a two argument version where I simply pass in two blocks as normal arguments (rather than as the implicit block argument). The result calling side syntax is a bit ugly: result = 10.if_else Proc.new { ... }, Proc.new { ... }; It's starting to remind me of doing blocks/closures in Java (but not yet *that* ugly). When Ruby get's keyword arguments it will look a little better: result = 10.if Proc.new { ... }, else: Proc.new { ... }; Then the 1-arg if and the 2-arg if-then-else can be done with a single method without too much trouble. It would be nice to be able to elide the Proc.new calls and have something like: result = 10.if { ... }, else: { ... }; And seriously nice if you didn't have to use commas to separate arguments when not using "()" style calling syntax. Here's the modified code for the curious: ########## module TrueModule def ifthen &b @bl = b self end def else rv, @bl = @bl.call, nil rv end def if_else(ifblock, elseblock) ifblock.call end end module FalseModule def ifthen self end def else yield end def if_else(ifblock, elseblock) elseblock.call end end module JustTrueModule # 'when' is the same as 'on_true' (if with no else) def on_true yield end def when yield end # 'on_false' is the same as 'on_false' (unless) def on_false nil end def unless nil end end module JustFalseModule def on_true nil end def when nil end def on_false yield end def unless yield end end class Object include TrueModule include JustTrueModule def if_else(ifblock, elseblock) if self then ifblock.call else elseblock.call end end end [NilClass, FalseClass].each { |c| c.send :include, FalseModule c.send :include, JustFalseModule } if __FILE__ == $0 [1, 0, "Hello", false, true, nil].each { |item| puts "--- #{item.inspect} ---" # using on_true result = item.on_true { puts "TRUE"; 1 } puts "result = #{result.inspect}" # using when result = item.when { puts "TRUE"; 1 } puts "result = #{result.inspect}" # using built-in if result = if (item) puts "TRUE" 1 end puts "result = #{result.inspect}" # using ifthen result = item.ifthen { puts "item is true" 1 }.else { puts "item is false" 0 } puts "result = #{result.inspect}" # using built-in if & then result = if item puts "item is true" 1 else puts "item is false" 0 end puts "result = #{result.inspect}" # using if_else result = item.if_else(Proc.new { puts "item is true" 1 }, Proc.new { puts "item is false" 0 }); puts "result = #{result.inspect}" # using on_false result = item.on_false { puts "FALSE"; 0 } puts "result = #{result.inspect}" # using unless result = item.unless { puts "FALSE"; 0 } puts "result = #{result.inspect}" # using built-in if not result = if (not item) puts "FALSE" 0 end puts "result = #{result.inspect}" } end if __FILE__ == $0 require "runit/testcase" require 'runit/cui/testrunner' require 'runit/testsuite' class Testing_class < RUNIT::TestCase def test1 result = 1.on_true { 10 } assert_equal(result, 10); end def test2 result = false.on_true { 10 } assert_equal(result, nil); end def test3 result = nil.on_true { 10 } assert_equal(result, nil); end end RUNIT::CUI::TestRunner.run(Testing_class.suite) end ########## > But, the point is: > > * no stock conditional constructs were used in the above code; > > * this ifthen/else are really methods, you can override them, wrap > them, or > whatever you want. > > This latter thingy is what the Smalltalkers are proud of, ain't it? I'm not a proud Smalltalker. I think both Smalltalk and Ruby are great (the Smalltalk image thing makes me uncomfortable though). I just wanted to see the code 'cause I thought I'd learn something from it :-). I did - thanks. Steve. -- Steven Shaw http://c2.com/cgi/wiki?StevenShaw