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

[ブログ記事](http://secret-garden.hatenablog.com/entry/2020/04/13/233925)からの転載です。

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

* [Ruby の開発版に右代入演算子とエンドレスメソッド定義構文が入った](http://secret-garden.hatenablog.com/entry/2020/04/10/195207)

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


## `def hoge(value) = value => @value`

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

```ruby
def hoge(value) = value => @value
```

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

```ruby
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` へと代入されています。  
ただし、この挙動はすでに修正されており最新版では以下のように意図する動作となります。

```ruby
def hoge(value) = value => @value

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

となります。  

* 修正コミット：https://github.com/ruby/ruby/commit/67bcac879a2e0ddfb4e7bbd7cb5e5401422de76a

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

```ruby
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` メソッドとして定義したいという意図になります。  
これも先程の[修正コミット](https://github.com/ruby/ruby/commit/67bcac879a2e0ddfb4e7bbd7cb5e5401422de76a)よりも前はシンタックスエラーになっていたんですが現状では動作するようになっています。  

```ruby
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` に代入したい…という感じなんですがもうよくわかりませんね…。  
これは以下のような動作になります。  

```ruby
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つの変数に代入したいってことですが…。  
これは実行時エラーになります。  

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

これは

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

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


## 所感

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


## その他

### `42 => result1 => result2`

```ruby
42 => result1 => result2

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


### `[1, 2] => result1, result2`

```ruby
[1, 2] => result1, result2

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


### if 式で `=>` を使う

```ruby
# OK
if result = value
end

# Error
if value => result
end
```

### `42 => a = b => c`

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

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


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

```ruby
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
```

## 参照

* https://docs.google.com/document/d/1Gcs38tvI6_dQ5sgy8CNUIVZbt0c_y_Z2GrCAoDwh5wg/edit#heading=h.gias3pb645mg