この現象を解き明かしたい。
文字列は足せない。
"a" + "a" #> Error in "a" + "a": non-numeric argument to binary operator
character
用のメソッドを作ってもディスパッチしてくれない。
`+.character` <- paste0 "a" + "a" #> Error in "a" + "a": non-numeric argument to binary operator
のに、なぜかcharacter
以外のクラスのメソッドにするといける。
x <- structure("a", class = c("foo", "character")) `+.foo` <- paste0 x + x #> [1] "aa"
あと、これでもいけた。implicit classじゃだめってことか?
`+.character` <- paste0 x <- structure("a", class = "character") x + x #> [1] "aa"
non-numeric argument to binary operator
というエラーは、以下の2つにdefine
されている。
- https://github.com/wch/r-source/blob/159998b30dd728abc8a0324fff28d3b6ba9d6c02/src/main/arithmetic.c#L43
- https://github.com/wch/r-source/blob/af7f52f70101960861e5d995d3a4bec010bc89e6/src/library/stats/src/distn.c#L42
ので、このR_MSG_NONNUM_MATH
に行くまでの流れを探せればいい(けど見つけられなかった)
#define R_MSG_NONNUM_MATH _("non-numeric argument to mathematical function")
+
の中身、.Primitive("+")
は
do_primitive
を呼び、そのなかでさらにR_Primitive
を呼ぶ。
- https://github.com/wch/r-source/blob/039f1d93ebbd08f1f92df6901ab154b9d161efee/src/main/names.c#L1025-L1037
- https://github.com/wch/r-source/blob/039f1d93ebbd08f1f92df6901ab154b9d161efee/src/main/names.c#L1013-L1023
R_Primitive
はR_FunTab
から指定した名前のものを探してきてmkPRIMSXP
で関数をつくるらしい。
+
はこの行。do_arith
というやつらしい。
do_arith
はこれ。
1つめの引数がINTSXP
かREALSXP
のスカラなら即座に処理されるけど、そんなことはないのでここは通り抜けて、もうちょい下にR_binary
っていうのがあるのでそこに落ちるはず。
R_binary
はこれ。
array
とかts
だったら別の処理があるけど、その辺は通り抜ける。
数値型であればここでreal_binary
に落ちる。それ以外ならinteger_binary
に行く:
integer_binary
はこれ。
PLUSOP
なのでここに行くはずだけど、もうSEXP
をint
に変換しちゃうので、ここまでくるともうR_MSG_NONNUM_MATH
に行くような処理はなさそう。
INTEGER_RO
の中身を一応覗いておくと、実態はDATAPTR_RO
で、特殊な処理はなさそう。
- https://github.com/wch/r-source/blob/e5224406b25b49a8112b2216ded7c71e5425d32c/src/include/Rinternals.h#L420
- https://github.com/wch/r-source/blob/80071c9d309b2244f7b1d18e4e5e590bcc0a29d1/src/include/Rinlinedfuns.h#L110-L116
ALTREP
はなんか独自のベクトルを定義するときに便利、みたいなやつだった気がする。ということでふつうはSTDVEC_DATAPTR
に行くはず。
- http://blog.revolutionanalytics.com/2017/09/altrep-preview.html
- https://github.com/wch/r-source/blob/e5224406b25b49a8112b2216ded7c71e5425d32c/src/include/Rinternals.h#L409
てことで、流れを追えてない気がする。フックみたいなのがあるのかな。。
追記:
ドキュメントを見たらちゃんと書いてあった。やっぱりimplicit classではむりらしい。。
However, group generics dispatch on the oldClass for efficiency, (R: Object Classes)
というのを踏まえてもう一度見直してみると、ここが重要っぽい。引数のいずれかにattributeがあったらDispatchGroup()
でメソッドディスパッチが行われる。どちらにもなければそのまま進む。