The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
Singleton Methods in Smalltalk and Ruby

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Rick DeNatale

Posts: 269
Nickname: rdenatale
Registered: Sep, 2007

Rick DeNatale is a consultant with over three decades of experience in OO technology.
Singleton Methods in Smalltalk and Ruby Posted: May 30, 2009 6:17 PM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Rick DeNatale.
Original Post: Singleton Methods in Smalltalk and Ruby
Feed Title: Talk Like A Duck
Feed URL: http://talklikeaduck.denhaven2.com/articles.atom
Feed Description: Musings on Ruby, Rails, and other topics by an experienced object technologist.
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Rick DeNatale
Latest Posts From Talk Like A Duck

Advertisement

Yesterday, Travis Griggs posted an interesting article on his blog about a couple of tricks he used to write a test which needed to ensure that a race condition actually happened during the test.

And Randal Schartz just discovered it too. These two posts point out some interesting similarities and differences between Ruby and Smalltalk.

Singleton methods

A lot of folks point to Smalltalk as a source for the kind of metaprogramming techniques that we Ruby programmers take for granted. Smalltalk does allow a lot of metaprogramming, but things like instance-specific behavior aren't part of the standard repertoire of most Smalltalkers. That's why Randal, who is no slouch at Smalltalk, expressed a certain amount of amazement at how Travis did this. Here's his (Travis') example Smalltalk code:

p := 4 @ 3.
p changeClassTo: (p class copy superclass: p class).
p class methodDictionary at: #negated put: (p class methodDictionary at: #transpose).
p negated

For those unfamiliar with Smalltalk, the expression 4 @ 3 creates an instance of Point, which is a 2-d point object with x=4 and y=3.

Let's write a Point class in Ruby which works like a subset of Smalltalk's Point

class Point
  attr_accessor :x, :y
  def initialize(x, y)
    @x, @y = x, y
  end

  def negated
    self.class.new(-x, -y)
  end

  def transpose
    self.class.new(y, x)
  end

  def inspect
    "#{@x} @ #{@y}"
  end
end

p = Point.new(4,3) # => 4 @ 3

p.negated
p.negated          # => -4 @ -3
p.transpose        # => 3 @ 4

Now , the above code might look something like this:

p = Point.new(4,3)
def p.negated
  transpose
end

p.negated # => 3 @ 4

Most Rubyists of any experience will recognize that what I've done is define a singleton method for that sole instance of point which overrides the negate method by calling transpose instead.

Another way to do this which might be a little bit more like what Travis shows in Smalltalk might be:

p = Point.new(4,3)
class <<p
  alias_method :negated, :transpose
end

Let's look at Travis' example and how he creates a 'singleton' class in Smalltalk. Here are the relevant lines:

p changeClassTo: (p class copy superclass: p class).
p class methodDictionary at: #negated put: (p class methodDictionary at: #transpose).

He gets p's class (which is Point up to now), copies it, and sets it's super class to p's class, effectively interposing the copied class object. Next he gets the transpose instance method from the copied class's method dictionary and replaces the negated method. Effectively what Ruby's alias_method does.

Now, I should point out here that Travis's example is probably specific to the Cincom VisualWorks Smalltalk dialect. The changeClassTo: method doesn't seem to be available in Squeak, although there might be a similar method, and I don't recall a similar method in the Smalltalks I've used in the past. Also changeClassTo: isn't entirely guaranteed to work, besides the cases where Ruby can't create a singleton class (for example immediate objects like FixNums), changeClassTo: requires that the 'shape' of the instance conform to the instance variable template defined in the new class, simplifying things a bit, that means that it needs to have either exactly the number of instance variables expected by the class, or at least the number of fixed instance variables expected by the class. Smalltalk classes can have a variable set of indexed instance variables which are placed after all the fixed (named) instance variables.

So let's end this exploration of comparative instance specific method creation between Ruby and Smalltalk before I move on to another interesting difference which Travis' article exposes:

  1. Smalltalk provides dialect-specific mechanisms for monkeying with the class of an object and manipulating methods.
  2. Ruby has some nice syntactic sugar for doing this in a way which is part of the language definition.

As a result, these techniques are far more commonly used in Ruby than in Smalltalk.

Now for the second difference, one where Smalltalk leaves Ruby a bit behind.

Turtles All the Way Down

One of the really interesting things about Smalltalk is just how much of the runtime system is exposed as 'normal' Smalltalk objects. In Ruby certain things are hidden away (sometimes not so securely) from the Ruby programmer, there's a "Wizard of Oz" behind the curtain which separates to the Ruby program from the VM (or interpreter if you prefer).

Almost everything the VM deals with in Smalltalk pokes up as one or more Smalltalk objects. In Smalltalk everything really is an object, it's turtles all the way down, at least it looks that way.

Travis' motivating problem was to force a race condition to occur on demand. Anyone who has done concurrent programming has learned that race conditions have probabilistic minds of their own.

The lever that Travis pulled was the fact that Smalltalk threads (which Smalltalk calls Processes for historic reasons) are implemented as Smalltalk objects which can be manipulated directly from Smalltalk. The Smalltalk IDE makes use of this. For example the Smalltalk debugger is really just a specialized inspector which inspects a Process object, including showing it's state (the stack frames) and manipulate it (breaking, stepping, and responding when class definitions change).

So Travis could grab the instance of a single process and change its instance-specific behavior to modify the way it handled termination in order to simulate the condition he needed.

This aspect of Smalltalk is something which many maybe too many Smalltalk programmers are familiar with. The second part of that old article link I just snuck in talks about the distributed version of Smalltalk I did at IBM many years ago which added a new kind of Process proxy which tied execution threads which crossed machine boundaries together allowing distributed debugging, exception handling etc.

Can Ruby get along without this? Sure. But it is one thing I miss from Smalltalk

Read: Singleton Methods in Smalltalk and Ruby

Topic: Moosy Previous Topic   Next Topic Topic: Making mutable state faster: optimizing the caml_modify writer barrier

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use