Notes after the jump (as I write them)
Review of the day: Morning session was excellent and intense. This afternoon has been theory. As of 3:45pm, it hasn’t felt so “advanced”.
Blocks, Procs, and Closures
- “Brace” form of block always associates it self with the nearest method call. Not true of
do ... end breakbreaktakes an optional parameter — which becomes the return value of the block.- So it’s behaving like a typical Proc return value except we’re jumping the call stack
- Freaky that we’re all getting so bent out of shape on like the first slide or two of the real content.
next- Just return from the block early
- Similarly, has an optional parameter that is the return value of the Proc
redo- Me: I’ve never used it
- DT: Used it maybe 3 times in 8 yars of Ruby
- Ooooh, I have softcopy of all of the code samples from the class (but almost certainly can’t redistribute, sorry)
retry- Ok, didn’t know this one…
- Like
redoexcept that it reevaluates the CALL to the proc so the below example could be implemented withretry
i = 0
loop_until i == 3 do
i += 1
end
… because retry will reevaluate the loop_write call which reevaluates the i < 3 call. And this is getting removed from Ruby 1.9 (but will still be available for exception handling)
Hrmph. Blocks aren’t Procs in MRI unless you pass a & on the param to the method.
DT: There are two kinds of Proc objects differentiated by a hidden flag
- Using
lambda, behaves like an anonymous method - Using
Proc.new, get an object that behaves like an inline block procchanged from an alias tolambdatoMe: Glad that I’ve always just used
lambdaBindings
- Ruby stack frames point to Binding objects
- Me: Used in the common Ruby implementations under the cover?
- DT: They must
- Closures
- Whenever a block is creating, it automatically gets a Binding to the current stackframe
- Me: So that’s how we get closures. Cool. Follows like 1 + 2 = 3
- Blocks need the local Binding in order to be able to implement loop constructs
- CF: Multiple calls to
bindingreturn different wrappers to the stack frame’s Binding — so they can’t be compared at runtime. - Methods are not closures
We were given a fun little exercise to write a counter method using a Proc. Below is my Java-ish solution initializing a counter to nil.
def counter(start = 0, increment = 1)
count = nil
lambda {
count += increment if count
count ||= start
}
end
c = counter(10, 2)
p c.call
p c.call
p c.call
My neighbor today, Jimmy Baker, tried something that I liked. He passed a added a third parameter on the counter method and used that instead of defining a local variable in the method impl. I thought this was cute because the arguments to the method are also part of the Binding and so could save another line of code.
Ruby Internals
- Ruby C extensions are running in the same runtime
- So ParseTree, for instance, can walk the parse tree
- Me: I’ve read about ParseTree (and Ruby2Ruby). Cool stuff.
- Now we’re poking a little through Ruby 1.8.6’s parse.y (written in yacc) looking at the definition of
stmtandcompstmt. Uf da! - eval.c
eval_nodeis how Ruby walks it’s internal parsed tree of instructions
Design in a Dynamic Language
- DT: ranting about OO programming really being about classes and not objects.
- Experienced Ruby programmers prefer composition and rarely use inheritance
- Me: At least I’m on the right track
- Long argument about whether inheritance hierarchies (and static typing) are all that necessary.
- DT: Cites how infrequently Java developers run into ClassCastExceptions when extracting Objects from collections (zero or one times per year) and how this problem was “fixed” with Java 1.5.
- CF: Interesting minimalist view of the advantage of composition over inheritance: you only implement the methods that you need and can avoid exposing those that you don’t.
- DT:
Forwardablein std lib- Declarative delegation, i.e.,
def_delegator :@member, :member_method, :exposed_methodis clearer than:
- Declarative delegation, i.e.,
def exposedmethod
@member.membermethod
end
- Logical delegation via method_missing (simple stuff)
- Duck typing
- DT gave an example of prototype-based programming in Ruby: defining Objects and having Objects inherit from other Objects by use of
clone - CF: Why never to use
kind_of?: because objects can have methods remove at runtime just as easily as they can be added; it’s more important to know if an object canrespond_to?a particular message.- Knew this already but I love this explanation.
- CF: Points out how the Martin Fowler Refactoring book really turned him on to OO with “Handle Conditions with Polymorphism”. With Ruby, just reopen the class, add different impls to each possible object with the same method name, remove the conditional, and just invoke the method outright in the code.
- Mixins
- Look for “-able” descriptions (i.e., Loggable, Enumerable, Printable, etc.) and sometimes “-ing”
- CF on splitting methods up: When I have comments in a method, that’s a big hint
- Me: Yup. And, wow, do I see a lot of code like that (No, I usually didn’t write it!)
- Minimize interaction between Mixin and including class — otherwise coupling the including Class to the Mixin
Messin’ With Types
- to_x conversion methods just make a “best guess”
- Coercion
- Not supposed to be lossy
- DT: Representation of one type in another type
Symbol.to_proccoerce- DT: You’ll probably never need it
- DT: Good example of double-dispatch
“Homework”
- Use
coerceto write 1 + “123″ to return 124


0 comments ↓
There are no comments yet...Kick things off by filling out the form below.
Leave a Comment