ブログ記事からの転載です。
さてさて、先日 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 => nil
を private
メソッドの引数として渡しているから…ですかね。
もうよくわからない。
所感
とにかく =>
と 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