In Ruby, running a "def" of a function is actually an operation on the namespace of the object currently in scope. "def" may look like a function, but there are no functions in Ruby, only messages sent to objects, asking the object to chase down a method by name, and to run this method in the environment of that object. So "def" is actually a message sent to the core of Ruby, asking it to associate the name with the iseq that is the byte-compiled body of the function. ------------------- addtwo-bytecode.rb ------------------- code = <@>================================ 0000 trace 1 ( 1) 0002 putspecialobject 1 // this is VM_SPECIAL_OBJECT_VMCORE object 0004 putobject :add_two // this is the name (Ruby symbol) 0006 putiseq add_two // this is the iseq to associate with that name 0008 opt_send_without_block , 0011 pop // the result of this call to define_method is not // needed by our code, and hence discarded. 0012 trace 1 ( 4) 0014 putself // this is what will get "puts" 0015 putself // this is what will get :add_two, which we // luckily just defined above via define_method 0016 putobject 100 0018 putobject 200 0020 opt_send_without_block , // so, send :add_two with 2 arguments (100 and 200) 0023 opt_send_without_block , // and now 300 is on top of the stack, from running // the iseq below. So print it (send puts with 1 arg) 0026 leave == disasm: #>=================================== local table (size: 4, argc: 2 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1]) [ 4] a [ 3] b [ 2] sum 0000 trace 8 ( 1) 0002 trace 1 ( 2) 0004 getlocal_OP__WC__0 4 // get value from slot 4 of current stack frame ("a"); // (this is where "a" lives, according to the local table) // push it on top of the stack 0006 getlocal_OP__WC__0 3 // get value from slot 3; this is where "b" lives 0008 opt_plus , // send message "+" to 100, with argument 200; // this is a special optimized form of send for "+" // when called, "+" will consume its addressee object // and its argument, and push the result (300) on // top of the stack 0011 dup // duplicate the top of the stack (300). We need this // for setting "sum" 0012 setlocal_OP__WC__0 2 // set the slot stack 2, where "sum" lives, to what's // on top of the stack. This will consume that copy of 300 // which we just created with dup // the original 300 is still on top of the stack, // exactly as we want as a result of a function call; // all other values we used in the function have // been cleaned up. Under 300 is the "self" that // we pushed with opcode 0014 above, and that // will get the "puts" message sent by opcode at 0023. 0014 trace 16 ( 3) 0016 leave ( 2) 300 Note that, unlike Elisp, Ruby uses a common stack for all method calls and iseqs, so that once an iseq (a method, a lambda, a proc) finished, it must leave only its return value and nothing else. The calling code will expect to find just the returned value pushed on top, and the rest of the stack exactly how it left it before the call!