0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Crystalでは文字列を継承できない - inherited マクロ

Last updated at Posted at 2024-01-06

はじめに

タイトルの通りです。RubyとCrystalは文化が違うので、ところどころ挙動が違います。
面白いことにCrystalはStringを継承できません。たとえば、

class MagicSpell < String
end

を実行すると、次のようなエラーがでます。

Error: Cannot inherit from String

これがどのように実現されているのかというと、

inherit マクロ

inheritマクロを使って書かれていました。使い方はとても簡単で、こんな感じです。

class String
  macro inherited
    {{ raise "Cannot inherit from String" }}
  end
end

RubyでもClass#inheritedがありますが、それと同じように使えるようですね。

このマクロがどのように定義されているのか調べようと思いましたが、よくわかりませんでした。Crystalでは、マクロは

macro define_method(name, content)
  def {{name}}
    {{content}}
  end
end

このような感じで定義します。そのため macro inherited という記法はそれ自体がマクロの定義になってしまいます。

ここのコードを見ると、inherited マクロは、他のいくつかのマクロ(included, extended, method_added, method_missing)などとともに名前のレベルで特別扱いされているようです。そんな用語はないですが、マクロの予約語といった感じでしょうか。

    def add_macro(a_macro)
      a_macro.owner = self

      case a_macro.name
      when "inherited"
        return add_hook :inherited, a_macro
      when "included"
        return add_hook :included, a_macro
      when "extended"
        return add_hook :extended, a_macro
      when "method_added"
        return add_hook :method_added, a_macro, args_size: 1
      when "method_missing"
        check_macro_param_count(a_macro, 1)
      else
        # normal macro
      end

このうち method_missing に関しては、開発者によって追加したことを後悔している発言もあったはずで、あまり推奨ではないと思いますし、これらの特別なマクロについてAPIリファレンスをググってもあまり出てきませんので、Crystalでも一応できるけど推奨はされていない黒魔術ということになると思います。

Stringが継承できないことの意味

私はRubyの動的な性質やダックタイピングが好きです。しかし静的言語のCrystalで、Stringを継承したライブラリが無数に作られると、型の不整合で問題が発生しやすくなる気はします。文字列に関しては、標準ライブラリのStringを拡張せずそのまま使ってほしいというメッセージだと理解しました。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?