Ruby の右代入とエンドレスメソッド定義文を組み合わせるといろいろとつらいことがわかった

さてさて、先日 Ruby の開発版に右代入とエンドレスメソッド定義構文が入りました。
この構文については以下を参照してください。

この2つの機能を組み合わせて使うといろいろとつらいことがわかってきたのでちょっとまとめてみました

def hoge(value) = value => @value

アクセッサ的に引数をそのままインスタンス変数に代入するコードはよく記述すると思います。
それを右代入とエンドレスメソッド定義で書くと

def hoge(value) = value => @value

のように記述する事ができます。
もうこの時点でよくわからん!!みたいなユーザがいると思うんですがまだ意図としてはわかりやすいと思います。
しかし、これは意図した動作を行いませんでした。

def hoge(value) = value => @value

# 42 が @value に代入されてほしい
p hoge 42

# しかし実際には @value にはなぜか :hoge が代入されている
p @value   # => :hoge

これはなぜかというと def = よりも => の方が優先順位が低く (def hoge(value) = value) => @value と解釈されている(と予想)からです。
なので (def hoge(value) = value) の結果である :hoge@value へと代入されています。
ただし、この挙動はすでに修正されており最新版では以下のように意図する動作となります。

def hoge(value) = value => @value

# 42 が @value に代入される
p hoge 42
p @value   # => 42

となります。

以降は以下の状態で動作確認しています。

p RUBY_VERSION       # => "2.8.0"
p RUBY_DESCRIPTION   # => "ruby 2.8.0dev (2020-04-13T13:57:10Z master c28e230ab5) [x86_64-linux]"

private def hoge(value) = value => @value

private def hoge(value) = value => @value のように書くこともできます。
これは hoge メソッドを private メソッドとして定義したいという意図になります。
これも先程の修正コミットよりも前はシンタックスエラーになっていたんですが現状では動作するようになっています。

class X
  # メソッドを定義しつつ private メソッドにする
  private def hoge(value) = value => @value

  def foo
    hoge(42)
    p @value
    # => 42
  end
end

p X.new.foo

def hoge(value) = value => @value => method_name

意図としては def hoge の結果を method_name に代入したい…という感じなんですがもうよくわかりませんね…。
これは以下のような動作になります。

def hoge(value) = value => @value => method_name

hoge 42
p method_name   # => :hoge
p @value        # => 42

意図する動作にはなっています、が…。

private def hoge(value) = value => @value => @value2

もう何がしたいのかよくわかりませんね…。
意図としては value@value@value2 の2つの変数に代入したいってことですが…。
これは実行時エラーになります。

# error: `private': {:hoge=>nil} is not a symbol nor a string (TypeError)
private def hoge(value) = value => @value => @value2

これは

private((def hoge(value) = value => @value) => @value2)

と解釈されて :hoge => nilprivate メソッドの引数として渡しているから…ですかね。
もうよくわからない。

所感

とにかく =>def = の優先順位がつらいって感じがしますね。
個人的には =>def == ぐらい優先順位が低いとわかりやすいのかあ、とは思うんですが => が Hash の定義として使えるのでいろいろとつらそう…。
このあたりを解決するには => の記号を変えるしかなさそうなのかなあ…。
ちなみに知り合いは def hoge(value) = @value = value みたいに = が連なってるのもつらいと言っていたので def = も記号としてはつらそう。
うーん、左から右に流れるようにかけるので書いてて気持ちよくはあるんですが上で書いたように凝った書き方をすると意図しない動作になりそうなのできびしそうですねえ…。

その他

42 => result1 => result2

42 => result1 => result2

p result1   # => 42
p result2   # => 42

[1, 2] => result1, result2

[1, 2] => result1, result2

p result1   # => 1
p result2   # => 2

if 式で => を使う

# OK
if result = value
end

# Error
if value => result
end

42 => a = b => c

これはシンタックスエラーになります。

# syntax error, unexpected '=', expecting end-of-input
42 => a = b => c

メソッドにネストした => を渡す

def hoge(h)
  p h
end

value = 42
# OK : Hash 渡しになる
hoge :key => value
# => {:key=>42}

# NG : syntax error, unexpected =>, expecting end-of-input
hoge 42 => value => value

参照