[py2rb] 多重継承の６

# はじめに
移植やってます。
( from python 3.7 to ruby 2.7 )
# 多重継承 (Python)
https://qiita.com/superrino130/items/a62568fe730f6ae04c09

前回の記事のコメントにて、@Nabetani さんより`Ruby3.1`では**クラス変数のオーバーライドがエラー**になることを教えていただきました。

https://docs.ruby-lang.org/ja/latest/doc/spec=2fvariables.html
> 親クラスに、子クラスで既に定義されている同名のクラス変数を追加した場合、子クラスが、そのクラス変数を参照した際に例外 RuntimeError が発生します。

また、クラス変数について興味深い記事を投稿されています。

https://qiita.com/Nabetani/items/bbd7fc95a9f006ab9136
# 失敗(Ruby)
```ruby
module Base
  def __init__
    @name = 'Base'
    @base = 'Base'
    puts 'Base'
  end
end

module C4
  include Base
  def __init__
    @name = 'C4'
    puts 'C4'
    super
  end
end
      
module C2
  include C4
  def __init__
    @name = 'C2'
    puts 'C2'
    super
  end
end

module C3
  include Base
  def __init__
    @name = 'C3'
    puts 'C3'
    super
  end
end

class C1
  include C2, C3
  attr_reader :name, :base

  def initialize
    __init__
  end

  def __init__
    @name = 'C1'
    puts 'C1'
    super
  end
end

c = C1.new
p [c.name, c.base]
p C1.ancestors

# output
C1
C2
C4
C3
Base
["Base", "Base"]
[C1, C2, C4, C3, Base, Object, Kernel, BasicObject]
```
継承チェーンで`Base`が`C3`の後から呼ばれています、よしよし。
![20220225a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/6c680655-e417-2405-68bc-c59f7f405e60.png)

https://ja.wikipedia.org/wiki/%E8%8F%B1%E5%BD%A2%E7%B6%99%E6%89%BF%E5%95%8F%E9%A1%8C

クラス変数からインスタンス変数に替えましたが、`@name`が継承元で`'Base'`に書き換えられています、ぐぬぬ。
# 成功(Ruby)
```ruby
module Base
  def __init__
    @name = 'Base'
    @base = 'Base'
    puts 'Base'
  end
end

module C4
  include Base
  def __init__
    puts 'C4'
    super
    @name = 'C4'
  end
end
      
module C2
  include C4
  def __init__
    puts 'C2'
    super
    @name = 'C2'
  end
end

module C3
  include Base
  def __init__
    puts 'C3'
    super
    @name = 'C3'
  end
end

class C1
  include C2, C3
  attr_reader :name, :base

  def initialize
    __init__
  end

  def __init__
    puts 'C1'
    super
    @name = 'C1'
  end
end

c = C1.new
p [c.name, c.base]
p C1.ancestors

# output
C1
C2
C4
C3
Base
["C1", "Base"]
[C1, C2, C4, C3, Base, Object, Kernel, BasicObject]
```
`super`の後でインスタンス変数を初期化することにより、正しいオーバーライドになるようです。
# 継承の実験
```diff_ruby
module C4
  include Base
  def __init__
    puts 'C4'
-    super
    @name = 'C4'
  end
end

# output
C1
C2
C4
["C1", nil]
[C1, C2, C4, C3, Base, Object, Kernel, BasicObject]
```
仮に、成功(Ruby)のコードで、`module C4`の`super`を削除した場合、継承チェーンの`C4`の次の`C3`の`def __init__`が呼ばれないため`puts 'C3'`が実行されないことが分かります。
また、その結果`Base`の`def __init__`も実行されないため、`@base`が初期化されていないこともわかります。
# 追記 成功(Ruby nilガード)
```ruby
module Base
  def __init__
    puts 'Base'
    @name ||= 'Base'
    @base ||= 'Base'
  end
end

module C4
  include Base
  def __init__
    puts 'C4'
    @base ||= 'newBase'
    super
  end
end
      
module C2
  include C4
  def __init__
    puts 'C2'
    super
  end
end

module C3
  include Base
  def __init__
    puts 'C3'
    super
  end
end

class C1
  include C2, C3
  attr_reader :name, :base

  def initialize(name = nil)
    @name = name || 'C1'
    __init__
  end

  def __init__
    puts 'C1'
    super
  end
end

c = C1.new("newC1")
p [c.name, c.base]
p C1.ancestors

# output
C1
C2
C4
C3
Base
["newC1", "newBase"]
[C1, C2, C4, C3, Base, Object, Kernel, BasicObject]
```
お馴染み`nilガード ||=`を`module`内で使用してみました。
これだと`super`のタイミングを気にしなくてよさそう。
# メモ
+ Python の 多重継承の６ を学習した
+ 百里を行く者は九十里を半ばとす