HelloPhysicsWorld->vecmath-ruby->chapter7
で、overload。こっちは静的と動的言語の差異で、なかなか上手く実装できませんでした。
javaのポリモーフィズム(多態性)を、rubyでどう実装する*1かって事ですけど。
方法としては、
って、辺りでしょうかね。他にも良い方法あれば教えてください^^
型をチェック
rubyのkind_of?メソッドでクラスをチェックするか、
クラスのシンボルを返すメソッドを定義してチェックするか、です。
class Point2 def sym; :Point2; end end class Point3 < Point2 def sym; :Point3; end end class Point4 < Point3 def sym; :Point4; end end def match_kind_of? obj p :Point4 if obj.kind_of? Point4 p :Point3 if obj.kind_of? Point3 p :Point2 if obj.kind_of? Point2 end def match_sym? obj p :Point4 if obj.sym == :Point4 p :Point3 if obj.sym == :Point3 p :Point2 if obj.sym == :Point2 end match_kind_of?(Point2.new) #=>:Point2 match_kind_of?(Point3.new) #=>:Point3 #=>:Point2 match_kind_of?(Point4.new) #=>:Point4 #=>:Point3 #=>:Point2 match_sym?(Point2.new) #=>:Point2 match_sym?(Point3.new) #=>:Point3 match_sym?(Point4.new) #=>:Point4
う〜ん、アルファ版はともかく、リリース版でkind_of?使うのは避けたいですからね。
クラス名のシンボル返すメソッドなんて、普通にありそうだけど、まあ参考で書いてみました−wー
どちらにしても、型をチェックだけ処理量をくう*2ので、避けたい所ですけど><
関数名の置き換え
C++のmangle的*3に、引数の型情報をset_hogeって感じで追加するか、
alias_methodでクラス特有のアクセサメソッドを定義するか、です。
以下C++のmangle的方法ですが、set使う側が頑張ってくださいってことで><
class Matrix3 def set(m00,m01,m02,m10,m11,m12,m20,m21,m22) #todo end def set_mat3(mat) #todo end def set_mat3_mat3(mat1,mat2) #todo end def set_vec3_vec3_vec3(vec1,vec2,vec3) #todo end end
次はalias_method使う方法ですが、仮引数としてVector2クラスを想定しているなら、:vx,:vy,:vx=,:vy=を使用して@x,@yを操作する感じです。間違ってPoint2クラスを渡しても、Point2.vx等のアクセサメソッドが定義されてないので、実行時にエラーになります。
まあ実行時ってことで、型安全ではないんですけどw;
module Tuple2 attr_accessor :x,:y def initialize x=0,y=0 @x,@y = x,y end def add obj1,obj2 [obj1.x + obj2.x,obj1.y + obj2.y] end end class Vector2 include Tuple2 alias_method :vx, :x alias_method :vy, :y alias_method :vx=, :x= alias_method :vy=, :y= def add_vec vec1,vec2 [vec1.vx + vec2.vx,vec1.vy + vec2.vy] end end class Point2 include Tuple2 alias_method :px, :x alias_method :py, :y alias_method :px=, :x= alias_method :py=, :y= def add_point point1,point2 [point1.px + point2.px,point1.py + point2.py] end end a = Vector2.new b = Vector2.new p a.add(a,b) #=>[0, 0] x = Point2.new p a.add(a,p) #=>C:/freetool/xyzzy/__temp_6idm.rb:9:in `add': undefined method `x' for nil:NilClass (NoMethodError) #=> from C:/freetool/xyzzy/__temp_6idm.rb:46
メソッドの仮引数のデフォルト値
仮引数に、おかしいデフォルト値を設定する方法です。
func(hoge1),func(hoge1,hoge2),func(hoge1,hoge2,hoge3),...等みたいな感じでポリモーフィズムに対応できるのではと思ってます。
でも結局はチェックコード分処理が、かかる*4んですけどね><
class Vector2 attr_accessor :x,:y def initialize x,y @x,@y = x,y end def add vec1=nil,vec2=nil unless vec2 add self,vec1 else @x = vec1.x + vec2.x @y = vec1.y + vec2.y end self end alias_method :+, :add def to_s [@x,@y] end end a = Vector2.new(1,2) b = Vector2.new(3,4) c = Vector2.new(10,10) p (a + b).to_s #=>[4, 6] p (a.add(b,c)).to_s #=>[13, 14]
ざっと思いついているのはこんな感じです。
ただ、処理量的なものを気にしないならeval系を使う*5ことでかなり簡潔に書けそうな感じではあるのですけど、私魔法が使えないので><