From: pluskid Date: 2007-12-14T18:37:17+09:00 Subject: Re: Is there any way to redefine the `new' method? Thank you, Robert! I think that's really what I want! :) On Dec 14, 5:07 pm, "Robert Klemme" wrote: > 2007/12/14, Robert Klemme : > > > > > 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 > > 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