This is one of the many reasons I cringe at languages like Ruby with implicit behaviors. Take this example:
class DoStuff attr_reader :accum def initialize @accum = '' end def do_a(&block) @accum << 'a' @accum << yield end def do_b(&block) @accum << 'b' @accum << yield end end def fubar do_stuff = DoStuff.new do_stuff.do_a do do_stuff.do_b do "rec\r\n" end end puts (do_stuff.accum) end fubar
Quick, tell me why the return is:
abrec
abrec
The reason is because the outer call do_stuff.do_a() has an implicit return of the result of the call to do_stuff.do_b() and so also returns “rec”.
To fix this, one must explicitly return an empty string as the return:
do_stuff.do_a do do_stuff.do_b do "rec\r\n" end '' end
and now the return is:
abrec
So, beware, especially beginner programmers, of the implicit return in Ruby functions.
Compare this with a C# implementation:
public class DoStuff { public string Accum {get; protected set;} public DoStuff() { Accum = ""; } public void DoA(Func a) { Accum.Append("a"); Accum.Append(a()); } public void DoB(Func b) { Accum.Append("b"); Accum.Append(b()); } } class Program { static void Main(string[] args) { DoStuff doStuff = new DoStuff(); doStuff.DoA(() => doStuff.DoB(() => "rec\r\n")); Console.WriteLine(doStuff.Accum.ToString()); } }
We get a compiler error:
Cannot implicitly convert type ‘void’ to ‘string’
This clearly tells us we have done something wrong.
If we change the return types to strings, then it becomes obvious (hopefully) that we want to return an empty string:
public string DoA(Func a) { Accum.Append("a"); Accum.Append(a()); return ""; } public string DoB(Func b) { Accum.Append("b"); Accum.Append(b()); return ""; }
and we get the desired behavior.
We can of course write the code the illustrate the implicit return of the Ruby code, but of course the C# code clearly illustrates this (and therefore the error of our ways):
public string DoA(Func a) { Accum.Append("a"); Accum.Append(a()); return Accum.ToString(); } public string DoB(Func b) { Accum.Append("b"); Accum.Append(b()); return Accum.ToString(); }
And indeed, we get:
abrec
abrec
just like in my “wrong” Ruby example.
Reblogged this on Sutoprise Avenue, A SutoCom Source.