2021/06/10 今週の気になった bugs.ruby のチケット

今週は TypeScript のようなコンストラクタを Ruby に導入したい、というチケットなどがありました。

[Feature #17942] Add a initialize(public @a, private @b) shortcut syntax for defining public/private accessors for instance vars as part of constructor

  • TypeScript だと以下のようにコンストラクタのショートハンドを記述できる
class Foo {
    constructor(public a:number, public b:number, private c:number) {
    }
}
  • 上記は以下と同じ意味
class Foo {
    constructor(a, b, c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }
}
  • これと同じような形で Ruby#initializeインスタンス変数に割り当てるようにする提案
class Thing
  def initialize(public @a, public @b, @c)
  end
end
  • 上記は以下と同じ意味
class Thing
  attr_accessor :a, :b

  def initialize(a, b, c)
    @a = a
    @b = b
    @c = c
  end
end
  • 個人的には強く #initialize に依存してしまっている機能なのでちょっとイマイチ
    • #initialize はただのコールバックメソッドに過ぎない
    • メソッドでしかないので他のメソッドでも使えないと一貫性がない
    • 仮引数はどうやって参照するの?
    • アクセッサまで定義されてるのは意味が強すぎる
  • Ruby ではあとから #initialize も再定義できるのでその場合にどうなるのかが気になる
class Thing
  def initialize(public @a, public @b, @c)
  end
end

class Thing
  # こう再定義したらどうなるの?
  def initialize(@a, public @a)
  end
end
  • どうせやるなら宣言的にやったほうがいい気はする
    • が、これやるなら gem でいいじゃんって思う
class Thing
  initialize(public: [:a, :b], private: :c) do
  end
end
class Thing < Struct.new(:a, :b, :c)
end

[Feature #17938] Keyword alternative for boolean positional arguments

  • bool 値を渡している位置引数をキーワード引数に置き換えようという提案
  • 例えば以下のメソッドは true / false で挙動を制御できるがそれが何を意味しているのかがわからない
object.respond_to?(:symbol, false) # what does `false` mean?
object.methods(true) # what does `true` mean?
  • なので以下のようにキーワード引数にしようという提案
object.respond_to?(:symbol, include_all: false)
object.methods(regular: true)
# or
object.methods(only_public: true)
# or
object.methods(include_all: false)
  • 実装案は以下のように非互換にならないようするイメージ
def respond_to?(symbol, include_all_positional=false, include_all: nil)
  include_all ||= include_all_positional

  # ...
end
obj = Object.new
obj.respond_to?(:symbol, include_all = false)
# or
obj.methods(include_inherited = true)
  • これは Ruby の問題じゃなくてエディタ側でカバーすべきでは?みたいなコメントもある
  • キーワード引数にした場合のキーの名前をどうするのかとパフォーマンスの懸念点が上げられている

[Bug #17925] Pattern matching syntax using semicolon one-line

  • case expression in 42; end とワンラインでパターンマッチを記述した場合にエラーになるのは意図する挙動なのか?というバグチケット
  • case expression when 42; end みたいに when だおt問題ない
  • case expression; in 42; end みたいに ; で区切ると問題ない
  • これは case (expression in 42); end と解釈されてしまっているのが問題らしい

[Bug #17937] Segmentation fault in Enumerator#next on Apple M1, Mac OS Big Sur 11.2.2

  • Ruby 2.7.1 + Apple M1, Mac OS Big Sur 11.2.2 で [1,2,3].to_enum.next を実行すると Segv するというバグ報告
    • どうして…
  • Ruby 2.7.2 以降と 3.0.1 以降では直っている

[Feature #17930] Add column information into error backtrace

def target
  # caller_locations[0] は自身のメソッドの呼び出し元の情報を保持している
  RubyVM::AbstractSyntaxTree.of(caller_locations[0])
end

p target #=> #<RubyVM::AbstractSyntaxTree::Node:VCALL@5:2-5:8>
# ^^^^^^ Line 5, Column 2--8