StringIOと継承

#define Check_IO(x) do { \
  if (!rb_obj_is_instance_of((x), rb_cIO)) { \
    rb_raise(rb_eTypeError, "wrong argument type %s (expected IO)", rb_class2name(CLASS_OF(x))); \
  } \
} while(0)

上記のようなマクロでIOクラスかどうかをチェックしていたんだけど、StringIOがチェックに引っかかる。
なんでーなんでーと思ってたら、StringIOってIOを継承してないのね・・・

仕方ないので次のように修正。

#define Check_IO(x) do { \
  const char *classname = rb_class2name(CLASS_OF(x)); \
  if (rb_obj_is_instance_of((x), rb_cIO)) { \
    rb_io_binmode(x); \
  } else if (strcmp(classname, "StringIO") != 0) { \
    rb_raise(rb_eTypeError, "wrong argument type %s (expected IO or StringIO)", classname); \
  } \
} while(0)

クラス名をチェックって、なんだかなー。*1


で。
ダックタイピングだと、ある種のメソッド群を実装していて欲しいときにチェックがめんどいなー、と思った。
継承以外でふるまいを表明/検査する手段ってないのかなぁ?


追記
使っているのはreadとwriteだけなんで、それをチェックすればいいのか、と考えたけど、メソッドって文脈(クラス)によって意味が違うような。

*1:「副作用がある」というのもアレですが