From: Robert Klemme Date: 2007-12-14T17:35:20+09:00 Subject: Re: Is there any way to redefine the `new' method? 2007/12/13, Rick DeNatale : > On 12/13/07, pluskid 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 Cheers robert -- use.inject do |as, often| as.you_can - without end