I always thought that rubyists choose to make returns in ruby implicit because of a style preference (less words = more concise). However, can someone confirm with me that in the following example you actually have to make the returns implicit or else the intended functionality won't work? (The intended functionality is to be able to split a sentence into words and return either "Begins with a vowel" or "Begins with a consonant" for each word)
# With Implicit Returns
def begins_with_vowel_or_consonant(words)
words_array = words.split(" ").map do |word|
if "aeiou".include?(word[0,1])
"Begins with a vowel" # => This is an implicit return
else
"Begins with a consonant" # => This is another implicit return
end
end
end
# With Explicit Returns
def begins_with_vowel_or_consonant(words)
words_array = words.split(" ").map do |word|
if "aeiou".include?(word[0,1])
return "Begins with a vowel" # => This is an explicit return
else
return "Begins with a consonant" # => This is another explicit return
end
end
end
Now, I know there are definitely many ways to make this code more efficient and better, but the reason I've laid it out like this is to illustrate the need for the implicit returns. Can someone confirm with me that implicit returns are indeed needed and not just a stylistic choice?
EDIT:
Here's an example to illustrate what I'm trying to show:
# Implicit Return
begins_with_vowel_or_consonant("hello world") # => ["Begins with a consonant", "Begins with a consonant"]
# Explicit Return
begins_with_vowel_or_consonant("hello world") # => "Begins with a consonant"
The implicit return value of a method is the last expression evaluated in the method.
In your case, neither of the two lines you annotated are the last expression. The last expression that gets evaluated is the assignment to words_array (which BTW is completely useless since because it is the last expression there is no way to use that variable afterwards).
Now, what is the value of an assignment expression? It is the value being assigned, in this particular case, the return value of the map method, which is an Array. So, that is what the method returns.
In the second example, at the very first iteration of the map, you will hit one of the two returns and thus immediately return from the method. In the first example, however, you will always iterate through the entire words array.
The problem is not that implicit and explicit returns are different, the problem is that the two lines you claim are implicit returns aren't.
This reason this is happening is because the return statement is inside of a block. If the return statement was inside of just a function, execution flow would be as you expect. Blocks and returns in ruby (and break statements for that matter) are a weird beast. Let's take a simplier example to capture what you're asking:
def no_return()
(1..10).each do |i|
puts i
end
puts 'end'
end
def yes_return()
(1..10).each do |i|
puts i
return
end
puts 'end'
end
If you run both of these, you'll see that the first will print out the numbers 1-10 and the word 'end' as you would expect, but the second function only prints out 1. This is because ruby internally implements returns (and break statements) as exceptions. When these exceptions are thrown, a lookup table called a "catch table" is used to try and find where the flow of execution should continue. If none is found, ruby internally will search down through the stacks of rb_control_frame structures looking for the pointer that points to the code that we are executing. So in your case, the exception is thrown and the closest pointer (in terms of stack frames) is at the end of the method, essentially causing a termination of the entire method. That's why you won't even see the 'end' being printed.
no_return instructions:
0000 trace 1 ( 3)
0002 putnil
0003 getdynamic i, 0
0006 send :puts, 1, nil, 8, <ic:0>
0012 leave
yes_return instructions:
0000 trace 1 ( 3)
0002 putnil
0003 getdynamic i, 0
0006 send :puts, 1, nil, 8, <ic:0>
0012 pop
0013 trace 1 ( 4)
0015 putnil
0016 throw 1
0018 leave
The important bit is in the yes_return instructions, there's that 'throw 1' that is actually the return statement implemented as a thrown (and caught) exception. Breaks work in the same way except they 'throw 2'.
To see the actual instructions with all of the frames and catch table yourself, check out this app I put together not too long ago:
http://rubybytes.herokuapp.com/
For more information, check out Pat Shaughnessy's blog, in particular this entry for more information:
http://patshaughnessy.net/2012/6/29/how-ruby-executes-your-code
And another shameless plug, if you're into java, check out my java version of rubybytes at
javabytes.herokuapp.com to see disassembled java bytecode (sorry for it being linkless, you'll have to copy and paste the url into your browser).
return will return from the method that yielded to the block, so you either need to be implicit or use next
Related
I'm unclear on why there is a need to pass block arguments when calling a function.
why not just pass in as function arguments and what happens to the block arguments, how are they passed and used?
m.call(somevalue) {|_k, v| v['abc'] = 'xyz'}
module m
def call ( arg1, *arg2, &arg3)
end
end
Ruby, like almost all mainstream programming languages, is a strict language, meaning that arguments are fully evaluated before being passed into the method.
Now, imagine you want to implement (a simplified version of) Integer#times. The implementation would look a little bit like this:
class Integer
def my_times(action_to_be_executed)
raise ArgumentError, "`self` must be non-negative but is `#{inspect}`" if negative?
return if zero?
action_to_be_executed
pred.my_times(action_to_be_executed)
end
end
3.my_times(puts "Hello")
# Hello
0.my_times(puts "Hello")
# Hello
-1.my_times(puts "Hello")
# Hello
# ArgumentError (`self` must be non-negative but is `-1`)
As you can see, 3.my_times(puts "Hello") printed Hello exactly once, instead of thrice, as it should do. Also, 0.my_times(puts "Hello") printed Hello exactly once, instead of not at all, as it should do, despite the fact that it returns in the second line of the method, and thus action_to_be_executed is never even evaluated. Even -1.my_times(puts "Hello") printed Hello exactly once, despite that fact that it raises an ArgumentError exception as the very first thing in the method and thus the entire rest of the method body is never evaluated.
Why is that? Because Ruby is strict! Again, strict means that arguments are fully evaluated before being passed. So, what this means is that before my_times even gets called, the puts "Hello" is evaluated (which prints Hello to the standard output stream), and the result of that evaluation (which is just nil because Kernel#puts always returns nil) is passed into the method.
So, what we need to do, is somehow delay the evaluation of the argument. One way we know how to delay evaluation, is by using a method: methods are only evaluated when they are called.
So, we take a page out of Java's playbook, and define a Single Abstract Method Protocol: the argument that is being passed to my_each must be an object which implements a method with a specific name. Let's call it call, because, well, we are going to call it.
This would look a little bit like this:
class Integer
def my_times(action_to_be_executed)
raise ArgumentError, "`self` must be non-negative but is `#{inspect}`" if negative?
return if zero?
action_to_be_executed.call
pred.my_times(action_to_be_executed)
end
end
def (hello = Object.new).call
puts "Hello"
end
3.my_times(hello)
# Hello
# Hello
# Hello
0.my_times(hello)
-1.my_times(hello)
# ArgumentError (`self` must be non-negative but is `-1`)
Nice! It works! The argument that is passed is of course still strictly evaluated before being passed (we can't change the fundamental nature of Ruby from within Ruby itself), but this evaluation only results in the object that is bound by the local variable hello. The code that we want to run is another layer of indirection away and will only be executed at the point where we actually call it.
It also has another advantage: Integer#times actually makes the index of the current iteration available to the action as an argument. This was impossible to implement with our first solution, but here we can do it, because we are using a method and methods can take arguments:
class Integer
def my_times(action_to_be_executed)
raise ArgumentError, "`self` must be non-negative but is `#{inspect}`" if negative?
__my_times_helper(action_to_be_executed)
end
protected
def __my_times_helper(action_to_be_executed, index = 0)
return if zero?
action_to_be_executed.call(index)
pred.__my_times_helper(action_to_be_executed, index + 1)
end
end
def (hello = Object.new).call(i)
puts "Hello from iteration #{i}"
end
3.my_times(hello)
# Hello from iteration 0
# Hello from iteration 1
# Hello from iteration 2
0.my_times(hello)
-1.my_times(hello)
# ArgumentError (`self` must be non-negative but is `-1`)
However, this is not actually very readable. If you didn't want to give a name to this action that we are trying to pass but instead simply literally write it down inside the argument list, it would look something like this:
3.my_times(Object.new.tap do |obj|
def obj.call(i)
puts "Hello from iteration #{i}"
end
end)
# Hello from iteration 0
# Hello from iteration 1
# Hello from iteration 2
or on one line:
3.my_times(Object.new.tap do |obj| def obj.call; puts "Hello from iteration #{i}" end end)
# Hello from iteration 0
# Hello from iteration 1
# Hello from iteration 2
# or:
3.my_times(Object.new.tap {|obj| def obj.call; puts "Hello from iteration #{i}" end })
# Hello from iteration 0
# Hello from iteration 1
# Hello from iteration 2
Now, I don't know about you, but I find that pretty ugly.
In Ruby 1.9, Ruby added Proc literals aka stabby lambda literals to the language. Lambda literals are a concise literal syntax for writing objects with a call method, specifically Proc objects with Proc#call.
Using lambda literals, and without any changes to our existing code, it looks something like this:
3.my_times(-> i { puts "Hello from iteration #{i}" })
# Hello from iteration 0
# Hello from iteration 1
# Hello from iteration 2
This does not look bad!
When Yukihiro "matz" Matsumoto designed Ruby almost thirty years ago in early 1993, he did a survey of the core libraries and standard libraries of languages like Smalltalk, Scheme, and Common Lisp to figure out how such methods that take a piece of code as an argument are actually used, and he found that the overwhelming majority of such methods take exactly one code argument and all they do with that argument is call it.
So, he decided to add special language support for a single argument that contains code and can only be called. This argument is both syntactically and semantically lightweight, in particular, it looks syntactically exactly like any other control structure, and it is semantically not an object.
This special language feature, you probably guessed it, are blocks.
Every method in Ruby has an optional block parameter. I can always pass a block to a method. It's up to the method to do anything with the block. Here, for example, the block is useless because Kernel#puts doesn't do anything with a block:
puts("Hello") { puts "from the block" }
# Hello
Because blocks are not objects, you cannot call methods on them. Also, because there can be only one block argument, there is no need to give it a name: if you refer to a block, it's always clear which block because there can be only one. But, if the block doesn't have methods and doesn't have a name, how can we call it?
That's what the yield keyword is for. It temporarily "yields" control flow to the block, or, in other words, it calls the block.
With blocks, our solution would look like this:
class Integer
def my_times(&action_to_be_executed)
raise ArgumentError, "`self` must be non-negative but is `#{inspect}`" if negative?
return enum_for(__callee__) unless block_given?
__my_times_helper(&action_to_be_executed)
end
protected
def __my_times_helper(&action_to_be_executed, index = 0)
return if zero?
yield index
pred.__my_times_helper(&action_to_be_executed, index + 1)
end
end
3.my_times do
puts "Hello from iteration #{i}"
end
# Hello from iteration 0
# Hello from iteration 1
# Hello from iteration 2
0.my_times do
puts "Hello from iteration #{i}"
end
-1.my_times do
puts "Hello from iteration #{i}"
end
# ArgumentError (`self` must be non-negative but is `-1`)
Okay, you might notice that I simplified a bit when I wrote above that the only thing you can do with a block is call it. There are two other things you can do with it:
You can check whether a block argument was passed using Kernel#block_given?. Since blocks are always optional, and blocks have no names, there must be a way to check whether a block was passed or not.
You can "roll up" a block (which is not an object and doesn't have a name) into a Proc object (which is an object) and bind it to a parameter (which gives it a name) using the & ampersand unary prefix sigil in the parameter list of the method. Now that we have an object, and a way to refer to it, we can store it in a variable, return it from a method, or (as we are doing here) pass it along as an argument to a different method, which otherwise wouldn't be possible.
There is also the opposite operation: with the & ampersand unary prefix operator, you can "unroll" a Proc object into a block in an argument list; this makes it so that the method behaves as if you had passed the code that is stored inside the Proc as a literal block argument to the method.
And there you have it! That's what blocks are for: a semantically and syntactically lightweight form of passing code to a method.
There are other possible approaches, of course. The approach that is closest to Ruby is probably Smalltalk. Smalltalk also has a concept called blocks (in fact, that is where Ruby got both the idea and the name from). Similarly to Ruby, Smalltalk blocks have a syntactically light-weight literal form, but they are objects, and you can pass more than one to a method. Thanks to Smalltalk's generally light-weight and simple syntax, especially the keyword method syntax which intersperses parts of the method name with the arguments, even passing multiple blocks to a method call is very concise and readable.
For example, Smalltalk actually does not have an if / then / else conditional expression, in fact, Smalltalk has no control structures at all. Everything is done with methods. So, the way that a conditional works, is that the two boolean classes TrueClass and FalseClass each have a method named ifTrue:ifFalse: which takes two block arguments, and the two implementations will simply either evaluate the first or the second block. For example, the implementation in TrueClass might look a little bit like this (note that Smalltalk has no syntax for classes or methods, instead classes and methods are created in the IDE by creating class objects and method objects via the GUI):
True>>ifTrue: trueBlock ifFalse: falseBlock
"Answer with the value of `trueBlock`."
↑trueBlock value
The corresponding implementation in FalseClass would then look like this:
FalseClass>>ifTrue: trueBlock ifFalse: falseBlock
"Answer with the value of `falseBlock`."
↑falseBlock value
And you would call it like this:
2 < 3 ifTrue: [ Transcript show: 'yes' ] ifFalse: [ Transcript show: 'no' ].
"yes"
4 < 3 ifTrue: [ Transcript show: 'yes' ] ifFalse: [ Transcript show: 'no' ].
"no"
In ECMAScript, you can simply use function definitions as expressions, and there is also lightweight syntax for functions.
In the various Lisps, code is just data, and data is code, so you can just pass the code as an argument as data, then inside the function, treat that data as code again.
Scala has call-by-name parameters which are only evaluated when you use their name, and they are evaluated every time you use their name. It would look something like this:
implicit class IntegerTimes(val i: Int) extends AnyVal {
#scala.annotation.tailrec
def times(actionToBeExecuted: => Unit): Unit = {
if (i < 0) throw new Error()
if (i == 0) () else { actionToBeExecuted; (i - 1).times(actionToBeExecuted) }
}
}
3.times { println("Hello") }
// Hello
// Hello
// Hello
I am following a linked tutorial from the Odin project, its about blocks and procs in ruby. I can't quite understand how does the following code work.
class Array
def eachEven(&wasABlock_nowAProc)
# We start with "true" because arrays start with 0, which is even.
isEven = true
self.each do |object|
if isEven
wasABlock_nowAProc.call object
end
isEven = (not isEven) # Toggle from even to odd, or odd to even.
end
end
end
['apple', 'bad apple', 'cherry', 'durian'].eachEven do |fruit|
puts 'Yum! I just love '+fruit+' pies, don\'t you?'
end
# Remember, we are getting the even-numbered elements
# of the array, all of which happen to be odd numbers,
# just because I like to cause problems like that.
[1, 2, 3, 4, 5].eachEven do |oddBall|
puts oddBall.to_s+' is NOT an even number!'
end
Is ['apple', 'bad apple', 'cherry', 'durian'] a block in this context and are we calling the method isEven on that block?
Does isEven used to only return true or false and if true the following code will be executed?
do |fruit|
puts 'Yum! I just love '+fruit+' pies, don\'t you?'
end
Also, what is this line doing?
self.each do |object|
if isEven
wasABlock_nowAProc.call object
end
end
If isEven is true then call [1, 2, 3, 4, 5] with the object??? What does calling that block with object mean?
Let's do it in parts:
1)The class Array was native from ruby, which means we are adding a method to all instances of Array, the method is the eachEven.
2) This method receives as parameter a block to be executed, keep this information in mind.
3) The ["apple", "bad apple", "cherry"] is an instance from Array, which means that we can execute the method eachEven for this array:
array = ["apple", "bad apple", "cherry"]
array.eachEven do |something|
# The do/end block is the parameter passed to the method `eachEven`
# the block will be binded in `wasABlock_nowAProc` in this case
end
4) Inside the method eachEven we get the self (self is the array itself) and execute another method from the Array instance: each (this method iterate over the array binding the current position to the variable inside brackets: |object|)
5) If the condition returns a positive result, it will execute the block inside if, in the case:
wasABlock_nowAProc.call object
# We execute the block of step 2 passing the current position value as a parameter
In fact, if we execute the following code:
array = [1, 2, 3, 4]
array.eachEven do |position_value|
puts "The #{position_value} is even"
end
We gonna get the following result:
The 1 is even # The block `wasABlock_nowAProc` will bind the 1 to the object and print it
The 3 is even # Same here, 3 will be used as the object in the execution of `wasABlock_nowAProc`
Hope it helps
Let's break apart the code here:
['apple', 'bad apple', 'cherry', 'durian'].eachEven do |fruit|
puts 'Yum! I just love '+fruit+' pies, don\'t you?'
end
What we have here boils down to:
receiver.method do |block_argument_one|
# this is the _body_ of the _block_
end
So:
['apple', 'bad apple', 'cherry', 'durian'] is called the receiver (or subject, or just object or instance)
eachEven is the method being called on the receiver
Everything from do to end is the block. It could also be { to } and work the same (well, mostly)
|fruit| is the block arguments list, with fruit being the only argument the block cares about.
puts … is the body of the block
What happens to the block is:
The code in the block gets interpreted, but not run
A placeholder for that code is passed to the method the block is attached to
the method runs, and can access the block while running
Now lets look at how a method that takes a block works:
class SomeClass
def some_method(regular_argument, &block_capture_argument)
# method body
# explicitly call the block:
block_capture_argument.call("first value passed to block")
# implicitly call the block (same as above)
yield "first value passed to block"
end
end
This shows several ways a block can be used:
When you define a method with the last argument beginning with &, a reference to the block is made available to the method by the name after the & (your wasABlock_nowAProc argument, for example). Then your method can do what is likes with the block, maybe calling it, or maybe even storing it somewhere a completely different method can use it.
Alternatively, you can use the yield keyword to call the block implicitly. In that case, you don't need a & argument to the method (but it still works if you do have that argument). Note that ruby allows you to attach a block to any method, regardless of if it uses that block. Methods can check if there was a block with the keyword block_given?, or check that the value of the & argument is present.
When you call the block, either with yield or with call, arguments you give to the call method are passed as arguments to the block.
The method can do whatever it wants with the block. It can call it once, twice, 0, or 300 times. It can call it with the same arguments each time or with different arguments each time.
In your specific example, the block gets called (with the value of object) for each item in the receiver, but only if the isEven variable is true.
Also in your specific example, you are calling the block from inside another block (which provides object for you), but don't let that confuse you.
To summarize:
blocks can be attached to any method using either do … end or {…}
blocks don't run unless the method they are attached to decides to call them
methods get called on a receiver
methods that use blocks get to decide how and when to use them
methods that use blocks can call blocks (or use yield) and pass any number of arguments to the block.
blocks can be defined to use those arguments (with the |…| syntax), and can name those arguments whatever they want (what matters is the order/position of the arguments).
One challenge in a Ruby course I'm doing is to print the :data values of the following linked list, in reverse:
{:data=>3, :next=>{:data=>2, :next=>{:data=>1, :next=>nil}}}
So when my method is passed the above code, it should return
1
2
3
Here's my attempt, which doesn't work for the above code. I can't figure out why, and I'd appreciate it if someone could explain what I'm doing wrong:
def print_list_in_reverse(hash)
if hash[:next].nil? #i.e. is this the final list element?
print "#{hash[:data]}\n"
return true
else
#as I understand it, the next line should run the method on `hash[:next]` as well as checking if it returns true.
print "#{hash[:data]}\n" if print_list_in_reverse(hash[:next])
end
end
Here's a solution, in case it helps you spot my mistake.
def print_list_in_reverse(list)
return unless list
print_list_in_reverse list[:next]
puts list[:data]
end
Thank you.
Your solution relies on return values, and you don't explicitly provide one in your else clause. In fact, you implicitly do because Ruby returns the result of the last statement evaluated, which for a print statement is nil. In Ruby false and nil are both logically false, causing the print to get bypassed for all but the last two calls. Your choices are to add a true at the end of the else, or make a solution that doesn't rely on return values.
To negate the need for return values, just check what logic is kosher based on info in the current invocation. You can simplify your life by leveraging the "truthiness" non-nil objects. Your basic recursive logic to get things in reverse is "print the stuff from the rest of my list, then print my stuff." A straightforward implementation based on truthiness would be:
def print_list_in_reverse(hash)
print_list_in_reverse(hash[:next]) if hash[:next]
print "#{hash[:data]}\n"
end
The problem with that is that you might have been handed an empty list, in which case you don't want to print anything. That's easy to check:
def print_list_in_reverse(hash)
print_list_in_reverse(hash[:next]) if hash[:next]
print "#{hash[:data]}\n" if hash
end
That will work as long as you get handed a hash, even if it's empty. If you're paranoid about being handed a nil:
def print_list_in_reverse(hash)
print_list_in_reverse(hash[:next]) if hash && hash[:next]
print "#{hash[:data]}\n" if hash
end
The other alternative is to start by checking if the current list element is nil and returning immediately in that case. Otherwise, follow the basic recursive logic outlined above. That results in the solution you provided.
Better to iterate over every value in your hash, and push the values until there's no any other hash as value inside the main hash.
def print_list_in_reverse(hash, results = [])
hash.each_value do |value|
if value.is_a? Hash
print_list_in_reverse(value, results)
else
results << value unless value.nil?
end
end
results.reverse
end
p print_list_in_reverse(data)
=> [1, 2, 3]
The problem in your code is in the else-case. You need to return true to print the hash[:data].
Your method always print the last 2 elements.
Substrings work where "hello"[0..2] returns "hel"
Is there an integer equivalent, that returns the sub-bits, as in 9[1..3] returns 4 or "100"?
Context:
I'm trying to do a genetic algorithm, and there is a cross over stage where you split two chromosomes in two, then swap halves, e.g. "10101010" crossed with "00000000" at i = 4 would be "00001010", "10100000"
However, I'm doing this a few million times, so using strings is inefficient, so is there a bitwise way to do this?
You might consider refining the class Fixnum to permit Fixnum#[]'s argument to be either a bit index or a range of bit indices.
module StabBitRange
def [](arg)
case arg
when Range
mask = arg.reduce(0) { |n, idx| n |= (1 << idx) }
(self & mask) >> arg.first
else
super
end
end
end
module StabBits
refine Fixnum do
prepend StabBitRange
end
end
See Refinements and Module#prepend. Prepend StabBitRange moves the methods contained therein (here just one) before the methods with the same names in Fixnum in the ancestor chain. The alternative (commonly used before Prepend was introduced in Ruby v2.0) is to alias Fixnum#[] and then redefine Fixnum[] to be the new method that takes either a bit index or a range of bit indices. (See the edit history of this answer to see how that is done.) I expect readers will agree that Prepend is a more sensible way of doing that.
To make this code available for use we need only invoke the keyword using.
using StabBits
n = 682
n.to_s(2) #=> "1010101010"
n[0] #=> 0
n[1] #=> 1
n[2] #=> 0
n[0..7] #=> 170 170.to_s(2) => "10101010"
n[1..7] #=> 85 85.to_s(2) => "1010101"
n[2..6] #=> 10 10.to_s(2) => "1010"
When StabBitRange#\[\] is called and the argument is not a range, super invokes Fixnum#[] and passes the argument. That method handles argument errors as well as returning the desired bit when there are no errors.
When this code is run in IRB, the following exception is raised: RuntimeError: main.using is permitted only at top level. That's because IRB is running at the top level, but code run within IRB is running at a higher level from the perspective of the Ruby parser. To run this in IRB it is necessary to enclose using StabBits and the code following in a module.
I thought that ruby just call method to_s but I can't explain how this works:
class Fake
def to_s
self
end
end
"#{Fake.new}"
By the logic this should raise stack level too deep because of infinity recursion. But it works fine and seems to call #to_s from an Object.
=> "#<Fake:0x137029f8>"
But why?
ADDED:
class Fake
def to_s
Fake2.new
end
end
class Fake2
def to_s
"Fake2#to_s"
end
end
This code works differently in two cases:
puts "#{Fake.new}" => "#<Fake:0x137d5ac4>"
But:
puts Fake.new.to_s => "Fake2#to_s"
I think it's abnormal. Can somebody suggest when in ruby interpreter it happens internally?
Short version
Ruby does call to_s, but it checks that to_s returns a string. If it doesn't, ruby calls the default implementation of to_s instead. Calling to_s recursively wouldn't be a good idea (no guarantee of termination) - you could crash the VM and ruby code shouldn't be able to crash the whole VM.
You get different output from Fake.new.to_s because irb calls inspect to display the result to you, and inspect calls to_s a second time
Long version
To answer "what happens when ruby does x", a good place to start is to look at what instructions get generated for the VM (this is all MRI specific). For your example:
puts RubyVM::InstructionSequence.compile('"#{Foo.new}"').disasm
outputs
0000 trace 1 ( 1)
0002 getinlinecache 9, <is:0>
0005 getconstant :Foo
0007 setinlinecache <is:0>
0009 opt_send_simple <callinfo!mid:new, argc:0, ARGS_SKIP>
0011 tostring
0012 concatstrings 1
0014 leave
There's some messing around with the cache, and you'll always get trace, leave but in a nutshell this says.
get the constant Foo
call its new method
execute the tostring instruction
execute the concatstrings instruction with the result of the tostring instruction (the last value on the stack (if you do this with multiple #{} sequences you can see it building up all the individual strings and then calling concatstrings once on all consuming all of those strings)
The instructions in this dump are defined in insns.def: this maps these instructions to their implementation. You can see that tostring just calls rb_obj_as_string.
If you search for rb_obj_as_string through the ruby codebase (I find http://rxr.whitequark.org useful for this) you can see it's defined here as
VALUE
rb_obj_as_string(VALUE obj)
{
VALUE str;
if (RB_TYPE_P(obj, T_STRING)) {
return obj;
}
str = rb_funcall(obj, id_to_s, 0);
if (!RB_TYPE_P(str, T_STRING))
return rb_any_to_s(obj);
if (OBJ_TAINTED(obj)) OBJ_TAINT(str);
return str;
}
In brief, if we already have a string then return that. If not, call the object's to_s method. Then, (and this is what is crucial for your question), it checks the type of the result. If it's not a string it returns rb_any_to_s instead, which is the function that implements the default to_s