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

Discussion in 'Ruby' started by pluskid, Dec 13, 2007.

  1. pluskid

    pluskid Guest

    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!
    pluskid, Dec 13, 2007
    #1
    1. Advertising

  2. On Dec 13, 2007 9:35 AM, 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


    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.
    Brian Mitchell, Dec 13, 2007
    #2
    1. Advertising

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

    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/
    --
    Rick DeNatale

    My blog on Ruby
    http://talklikeaduck.denhaven2.com/
    Rick DeNatale, Dec 13, 2007
    #3
  4. 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
    Robert Klemme, Dec 14, 2007
    #4
  5. 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
    Robert Klemme, Dec 14, 2007
    #5
  6. pluskid

    pluskid Guest

    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
    pluskid, Dec 14, 2007
    #6
  7. 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))
    --
    Posted via http://www.ruby-forum.com/.
    Christophe Mckeon, Dec 14, 2007
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Nafai
    Replies:
    4
    Views:
    333
    James Rafter
    Dec 8, 2004
  2. Daniel Berger
    Replies:
    17
    Views:
    169
    Trans
    Dec 30, 2006
  3. Pit Capitain
    Replies:
    11
    Views:
    162
    Pit Capitain
    Dec 28, 2006
  4. Blackie
    Replies:
    2
    Views:
    67
    Ari Brown
    Oct 19, 2007
  5. Iñaki Baz Castillo

    Redefine "method" method

    Iñaki Baz Castillo, Aug 13, 2008, in forum: Ruby
    Replies:
    6
    Views:
    119
    Iñaki Baz Castillo
    Aug 13, 2008
Loading...

Share This Page