Is there any way to redefine the `new' method?

P

pluskid

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!
 
B

Brian Mitchell

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

First of all, if you want a list or all symbols try:

Symbol.all_symbols

Next, if you want to define a method on the class object itself (i.e.
a class method) the you should try this:

class Symbol
def Symbol.my_new(name)
...
end
end

Symbol.my_new('foo')

Now, lastly, you should note that new has no implementation on Symbol.
This is deliberate. If you want to create a symbol from a string you
should use the String#to_sym method:

class Symbol
def Symbol.my_new(name)
name.to_sym
end
end

If you want to get into the details of why all this is the way it is,
then please ask. If you want to name my_new to new go ahead but I
wouldn't count on it being called for symbols being created in literal
style or via String#to_sym.

Brian.
 
R

Rick DeNatale

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

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. 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.

If Symbol doesn't do the job for you, you might look at things like
Ara's multiton code

http://raa.ruby-lang.org/project/multiton/
 
R

Robert Klemme

2007/12/13 said:
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
 
R

Robert Klemme

2007/12/14 said:
2007/12/13 said:
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
 
P

pluskid

Thank you, Robert! I think that's really what I want! :)

2007/12/14, Robert Klemme <[email protected]>:


2007/12/13 said:
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.
In this case you don't need to override #allocate - #new is perfectly
ok (see below).
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

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
 
C

Christophe Mckeon

another way:

module Scheme
class Symbol
@names = {}
def self.new name
@names[name.to_sym] ||= super
end
def initialize name
@name = name.to_sym
end
end
end

foo1 = Scheme::Symbol.new:)foo)
foo2 = Scheme::Symbol.new:)foo)
bar1 = Scheme::Symbol.new:)bar)
bar2 = Scheme::Symbol.new:)bar)
puts ((foo1 == foo2) && (bar1 == bar2) && (bar1 != foo1))
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top