2009-07-08 16 views
7

Quindi ho capito che non si suppone di creare direttamente sottoclasse Fixnum, Float o Integer, in quanto non hanno un metodo #nuovo. Usare DelegateClass sembra funzionare, ma è il modo migliore? Qualcuno sa qual è il motivo dietro a queste classi che non ha #nuovo?Fixnum sottoclasse in rubino

ho bisogno di una classe che si comporta come un Fixnum, ma ha alcuni metodi in più, e mi piacerebbe essere in grado di fare riferimento al suo valore attraverso self dall'interno della classe, ad esempio:

class Foo < Fixnum 
    def initialize value 
    super value 
    end 

    def increment 
    self + 1 
    end 
end 

Foo.new(5).increment + 4 # => 10 
+0

Dicci cosa stai veramente cercando di fare (l'obiettivo finale), e cercheremo di dirti il ​​modo migliore per farlo. Non penso che la sottoclasse sia appropriata qui. –

+0

ha aggiornato la domanda. – cloudhead

risposta

17

Si può tranquillamente facilmente una rapida attuazione di inoltro da soli:

class MyNum 
    def initialize(number) 
    @number = number 
    end 

    def method_missing(name, *args, &blk) 
    ret = @number.send(name, *args, &blk) 
    ret.is_a?(Numeric) ? MyNum.new(ret) : ret 
    end 
end 

Quindi è possibile aggiungere qualsiasi metodo che vuoi sul MyNum, ma avrete bisogno di operare su @number in questi metodi, piuttosto che essere in grado di chiamare super direttamente.

+0

Hmm. Ma se hai fatto MyNum.new (2) + MyNum.new (3), non avresti recuperato un Fixnum invece di un'istanza MyNum? Penso che sia necessario eseguire il wrap @ number.send in MyNum.new –

+0

Ho aggiornato la mia risposta per assicurarmi di restituire un MyNum se la risposta originale era numerica. –

+0

È possibile implementare MyNum in modo che MyNum.new (5) == 5 AND 5 == MyNum.new (5)? – rcrogers

2

Non potresti estendere lo stesso FixNum? Come ...

class Fixnum 
    def even? 
    self % 2 == 0 
    end 
end 

42.even? 
+1

Potrei, ma preferirei di no. Inoltre, Fixnum non ha #new e devo essere in grado di aggiungere funzionalità a #initialize. – cloudhead

+1

Le patch di scimmia dovrebbero essere usate con attenzione. Per inquinare una classe di nucleo Ruby solo per un caso d'uso specifico, può essere pericoloso. –

4

IIRC, la principale implementazione di Ruby memorizza Fixnums come valori immediati, utilizzando alcuni dei bassi bit della parola per contrassegnare come Fixnum invece di un puntatore ad un oggetto sul mucchio. Ecco perché, su una macchina a 32 bit, i fixnum sono solo 29 bit (o qualunque cosa sia) invece di una parola completa.

Quindi, per questo motivo, non è possibile aggiungere metodi a una singola "istanza" di Fixnum e non è possibile creare una sottoclasse.

Se hai un dead-set per avere una classe "tipo Fixnum", probabilmente dovrai creare una classe che abbia una variabile di istanza Fixnum e le chiamate del metodo di inoltro appropriatamente.

+0

ah vedo. C'è qualche altra classe che potrei sottoclasse? Numeric ha #new, ma non accetta argomenti, quindi suppongo sia una classe astratta. – cloudhead

+0

Hmm. Non ho toccato Ruby per un po ', e non ricordo esattamente come sia strutturato l'albero della classe numerica. –

+0

L'unico candidato ovvio è BigDecimal. –