2007/12/14, Robert Klemme <shortcut...@googlemail.com>:
> 2007/12/13, Rick DeNatale <rick.denat...@gmail.com>:
> > On 12/13/07, pluskid <plus...@gmail.com> wrote:
> > > Hi! I'm writing a toy interpreter for scheme in Ruby. I created a
> > > class to represent scheme Symbol.
> > > And as the scheme Symbol, I want only one instance for symbols with
> > > the same name. I try to
> > > do it like this:
> > > class Symbol
> > > alias orig_new new
> > > def new(name)
> > > @@symbols[name] ||= orig_new(name)
> > > @@symbols[name]
> > > end
> > > end
> > > But I failed. It says `new' is undefined. Is there any way to do the
> > > tricky? Thanks!
> > Well.
> > First, Ruby has a core class called Symbol, which is the class of
> > those funny :abc thingies. You probably don't want to mess with it,
> > and it might just already do what your are looking for. Note that you
> > can't do Symbol.new symbol instances are created either as literals,
> > or with conversion methods like "abc".to_sym
> Good point.
> > Second, Ruby probably does instance instantiation and initialization a
> > bit differently than whatever language you might be familiar with.
> > The new method which is an instance method of the class Class, is
> > normally never overridden, and it really isn't intended to be. It
> > effectively calls another method initialize to allocate the space for
> > the object, and then calls initialize on the result passing the
> > arguments of new.
> > The way Class#new does this is a bit magical. You can't override
> > allocate easily since ruby doesn't use normal method lookup to invoke
> > it.
> In this case you don't need to override #allocate - #new is perfectly
> ok (see below).
> > This works for ruby since, unlike many other OO languages, the
> > space needed for an object doesn't depend on things how many instance
> > variables it has, since these are acquired dynamically and found via a
> > hash.
> It's not that difficult:
> $ ./scheme-symbols.rb
> [134314620]
> 09:32:48 ~/ruby
> $ cat ./scheme-symbols.rb
> #!/usr/bin/env ruby
> module Scheme
> Symbol = Struct.new :name
> class Symbol
> @names = Hash.new do |h, k|
> k = k.dup.freeze
> h[k] = __new(k)
> end
> class << self
> alias __new new
> def new(name)
> @names[name]
> end
> end
> end
> end
> syms = (1..2).map { Scheme::Symbol.new "foo" }
> p syms.map {|o| o.object_id}.uniq
I had forgotton one #freeze:
module Scheme
Symbol = Struct.new :name
class Symbol
@names = Hash.new do |h, k|
k = k.dup.freeze
h[k] = __new(k).freeze
end
class << self
alias __new new
def new(name)
raise ArgumentError, "not a string" unless String === name
@names[name]
end
end
end
end
Cheers
robert
--
use.inject do |as, often| as.you_can - without end