From: Christoph Rippel Date: 2001-01-24T00:09:07+09:00 Subject: [ruby-talk:9764] A generic prototype This in response to [ruby-talk:9761] Thank you very much this is exactly what I wanted - except you you got the math wrong - i.e the return type of + is wrong ;-) (given my wrong input of course ..). Thanks to your hint I cooked up a generics interface. As usual I have eat my words - i.e. the thing is entirely based on mixin - at least it maintains a bit of the template flavor ... (the type qualifier are necessary and there is no lose of speed to access class constants like this if I remember correctly). I wished that something like this would end up in the official class interface to encourage people to use generics - when appropriate. (there are unsurprisingly a lot of warnings, generic_bucket is obviously not thread save and there are other issues but its a start.) Christoph class Module protected :append_features end class Class def Class.generic (aModule,theConstants, aSuperclass = Object) klass = Class.new aSuperclass aModule.append_features klass # klass.extend aModule mk = klass.constants theConstants.each_index { |c| klass.class_eval "#{mk[c]} = theConstants[c] " } klass end def Class.generic_bucket (aModule,theConstants, classes, aSuperclass = Object) if classes.key? theConstants classes[ theConstants ] else klass = Class.new aSuperclass aModule.append_features klass # klass.extend aModule mk = klass.constants theConstants.each_index { |c| klass.class_eval "#{mk[c]} = theConstants[c] " } classes[theConstants] = klass klass end end end module Test W = 6 X = 56 def ops p [type::W, type::X] end end $class = {} test1 = Class.generic_bucket(Test,[5,'a'], $class) test2 = Class.generic_bucket(Test,[5,'a'], $class) test3 = Class.generic_bucket(Test,['r','l'], $class) p test1.id == test2.id # true test3.new.ops # ["l", "r"] # Ruby correct ? class Ring def Ring.mod_ZZ (n) Class.generic_bucket(M_mod_ZZ,[n],@@__mod_ZZ) end private module M_mod_ZZ N = 1 # default def initialize (n) @rep = n % type::N end def + (r) type::new (@rep + r.rep) end def inspect @rep end protected attr_reader :rep end @@__mod_ZZ ={} end A = Ring.mod_ZZ 13 B = Ring.mod_ZZ 23 C = Ring.mod_ZZ 13 a1 = A.new 11 a2 = B.new 11 b1 = C.new 10 p A.id == C.id # true b2 = B.new 11 p a1 + b1 # 8 p a2 + b2 # 22 p a1 + a2 + a2 # 7 > -----Original Message----- > From: ts [mailto:decoux@moulon.inra.fr] > Sent: Tuesday, January 23, 2001 02:44 AM > To: ruby-talk ML > Cc: ruby-talk@netlab.co.jp > Subject: [ruby-talk:9761] Re: 101 Misconceptions About Dynamic Languages > > > >>>>> "C" == Christoph Rippel writes: > > C> class A > C> N = 13 # this is the crucial part > > The problem here is that N is resolved at compile time > > C> def initialize n > C> @rep = n % N > C> end > C> def + (r) > C> (@rep + rep.r) % N > ^^^^^ > r.rep > > no ? > > C> end > C> attr_reader :rep > C> ... > C> end > > > C> The import thing is that the type information is attached to the object ... > > C> a1 = A.new 11 > C> a2 = B.new 11 > C> b1 = C.new 10 # definitely want A.id == C.id > C> b2 = B.new 11 # is nor hard but is not natively supported > > C> than the internal representation of > > C> a1 + b1 and a2 + b2 > > C> won't be equal. > > Probably this not what you want (I know nothing about math :-)) > > pigeon% cat b.rb > #!/usr/bin/ruby > class Ring > @@class = {} > def Ring.mod_ZZ(n) > return @@class[n] if @@class.key? n > a = Class.new(self) > a.module_eval "N = #{n}" > @@class[n] = a > a > end > def initialize( n) > @rep = n % self.class::N > end > def + (r) > (@rep + r.rep) % self.class::N > end > attr_reader :rep > end > > > A = Ring.mod_ZZ 13 > B = Ring.mod_ZZ 23 > C = Ring.mod_ZZ 13 > a1 = A.new 11 > a2 = B.new 11 > b1 = C.new 10 > p A.id == C.id > b2 = B.new 11 > p a1 + b1 > p a2 + b2 > pigeon% > > pigeon% b.rb > true > 8 > 22 > pigeon% > > > Guy Decoux >