Advanced Ruby Studio, Day 2

This morning session rocked my world. The afternoon session was better than yesterday but, for me, dragged a lot toward the end of the day.

I suspect that my less enthusiastic response to this class vice the Rails class has more to do with my significantly greater experience with Ruby the language than Rails the framework.

That said, I am still finding this class worthwhile to fill in the gaps in my understanding of Ruby to date.

Notes after the jump.

Ruby Object Model

NOTE: Parts of this portion of the class were presented to NoVaRUG in April by DT.

  • self is the only way to access member variables.
  • Changing self is key to Ruby
    • On a method call
    • self gets set to the receiver then the method is looked up
    • When defining a class
    • This is universal to all implementations of Ruby
  • Methods are stored on classes, data in objects. (Me: Nothing new there but important to note for below)
  • When defining a method on an instance of a class, Ruby creates an anonymous class (aka “singleton class”, “eigenclass”, “virtual class”, and “metaclass”) to contain the new method and has it inherit from the original parent class.
  • If reader == Java.WEENIE
    • Ruby classes are executable code
    • Ruby classes are Ruby Objects
    • Me: Imagining your brain ‘sploding. :D

Classes are executable code

puts "foo"

class Stuff
  puts "bar"
end

puts "blech"

… outputs:

  foo
  bar
  blech

Classes are objects

puts "foo"

class Stuff
  @v = 123
  def self.get_v
    @v
  end
end

puts Stuff.get_v
puts "bar"

… outputs:

  foo
  123
  bar

Matz says “don’t use @@ vars” and DT agrees.

  • Instance variables looked up in self
  • Methods looked up in self’s class

  • Method definition is different than method lookup

    • def foo is defined in the current class
    • def obj.foo is defined in obj’s singleton class

And the lightbulb goes off over my head

So this idiom that I’ve seen Giles use in his code somewhere doesn’t hurt my brain anymore:

  something = "42"
  class << something
    def say_something
      puts self
    end
  end
  something.say_something

… will output 42. class << something changes the current Class to the singleton class of something.

Although the below example behaves the same way, it is less explicit in that it obscures what’s happening under the covers. The below example seems to define a method on something; it’s actually defining the method on something’s singleton class.

  something = "42"
  def something.say_something
    puts self
  end
  something.say_something

Intrestingly, clone copies a singleton class as well but dup doesn’t.

Cute but not hugely relevant:

  class Person < Struct.new(:name, :state)
    # do stuff
  end

… is legal – and a nifty way to save lines of code if you want to add methods to a Struct (or other expression that evals to a Class).

  • include

    • Points this object’s singleton class to the referred to module
    • Does not copy methods from a module into a class
    • So modules are actually shared
  • extend

    • includes into this object’s class’ singleton class.

Metaprogramming

  • instance_eval
    • Changes self to the receiver of instance_eval
    • Me: Cheeky way to call private methods on objects
  • class_eval

    • Changes self to the receiver (a class) of class_eval
    • WTF is the current class? Still not clear on this – and DT was getting confused too! Oy vey!
  • “Top level” methods are defined on a singleton instance of Object

    • to_s is redefined here as well to return “main”
    • Slide 167 explains the toplevel environment (although you’re not really in instance_eval)
  • Me: I actually found the Object Model discussion far more intense than playing with define_method – probably because I’m already pretty comfortable with meta/reflective programming from Java and having already used a fair bit of define_method and eval.

  • DT: Use of method_missing involves two method calls so it’s a bit slower.

  • initialize_copy
    • Define this to override the behavior of dup – to possibly provide a deep copy
  • const_missing
    • Rails uses this to require files at runtime
    • const_getCan only call on one class at a time.
  class Foo
    class Bar
      class Blech
      end
    end
  end

  c = self.class.const_get "Foo"
  c = c.const_get "Bar"
  c = c.const_get "Blech"

  puts c
  # >> Foo::Bar::Blech

The below example was in the Rails class but makes even more sense today thanks to our discussions of include and extend:

Hooks

  • included

Mixin a Module containing both instance methods and “class” methods

module Foo
  def self.included(klass)
    klass.extend ClassMethods
  end

  def foo
    puts "foo"
  end

  module ClassMethods
    def class_foo
      puts "class foo"
    end
  end
end

class Person
  include Foo
end

Person.new.foo
Person.class_foo
  • inherited

  • Explain why garbage collection in MRI ‘sucks’ (Me: Certain individuals I know, who shall remain nameless, *cough*Toby DiPasquale*cough* have commented on this)

    • DT
    • Typically not a problem
    • However, if you have a LOT of loose objects (100s of thousands… try creating a String by concat’ing lots of Strings together).
      • Had a program that did this. Instead of concat’ing several times, accumulated the Strings in an Array and created it at the end
      • Performance went from two minutes to one second
    • JRuby uses the JVM garbage collector (GOOD)
    • Rubinius is better
    • 1.9 is better

… make it fast

  • CF rant about maintainability. No argument here.
  • benchmark.rb
    • Benchmark#bmbm (great name) does a rehersal run first and then a real run
  • For socket code
    • Socket::do_not_reverse_lookup = true
  • YAML
    • YAML#dump == slow
  • update_page in Rails

    • Calling in more than 15 times for a single page will cause a noticeable slowdown
  • ObjectSpace

    • Iterate through objects and ue Marshal#dump to determine amount of memory taken up by a certain class
  • To speed things up

    • C (and other) extensions
    • DL (dynamic linking) – link a library at runtime and use it directly
    • Requires mapping C function calls (and structs if used) to Ruby objects
      • Slide 115-6
  • Some lecture on good ol’ fashioned CS: O(n), O(n^2), and avoiding stupid loops

    • Wow, DT cites Sedgewick (Me: I learned wth Corman)
  • Now CF is talking about eager loading and caching as a way of optimizing runtime.
  • This afternoon just seems like… common sense programming/software engineering/computer science that every student in here ought to have.
  • “Memoization”
    • Caching values of expensive operations for later re-use
    • There are some gems/libraries out there to keep code cleaner
    • Basically just the use of the ||= idiom

Exercise Playing with memoization Fibonacci to run super-fast

Library Organization

  • Discussion of setup.rb and RubyGems
  • Having written a few gems and installed who knows how many, this section of the class is mind-numbing
    • Dr. Nic’s NewGem gem essentially obviates much of this section of the class. Just use NewGem, write your own little gem, play with it, and that will teach you plenty.

Posted by evan on Friday, May 09, 2008

blog comments powered by Disqus