Chiyuan Zhang
12/14/2007 9:37:00 AM
Thank you, Robert! I think that's really what I want! :)
On Dec 14, 5:07 pm, "Robert Klemme" <shortcut...@googlemail.com>
wrote:
> 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