ruby instance_variable_set はなぜ @ マークのリテラルが必要？


ruby で、 `attr_reader :foo` のように、 reader のみを定義した変数に対して、  
別のメソッドの中で、上の `attr_reader` で用いたシンボルである `:foo` を用いて、 set_variable したくなりました。

その際に、 `Object#instance_variable_set` は、`:foo` は引数として受け付けずに、  
`:@foo` とする必要があることを知りました。

[code]

    obj.instance_variable_set(:foo, 1)
    #=> `foo' is not allowed as an instance variable name
    
    obj.instance_variable_set(:@foo, 1)
    #=> OK
    
[/code]

そこで生じた疑問が次です。

  * `instance_variable_set(:foo, 1)` で @foo に bind してくれた方がシンプルな気がしたのですが、関数がこのような動作になっている、何か特別が理由があったりするのでしょうか？

というのも、今やりたいことを、今自分が持っている知識でやろうとすると、こうなりました。

[code]

    class Foo
      attr_reader :foo
      def set_var_by_sym(sym, val)
        var_sym = ('@' + sym.id2name).intern
        instance_variable_set(var_sym, val)
      end
    end
    
[/code]

なんというか、少し、無駄に面倒なコードになっている気がしたので。。




`instance_variable_set`は引数として文字列を受け付けるので単に文字列の中で式展開でシンボルを埋め込むだけでよさそうです。

参考: <https://docs.ruby-lang.org/en/2.4.0/Object.html#method-i-
instance_variable_set>

[code]

    class Foo
      attr_reader :foo
      def set_var_by_sym(sym, val)
        instance_variable_set("@#{sym}", val)
      end
    end
    
[/code]

またSymbolに値を式展開して埋め込みたいなら以下のようにも書けます。

[code]

    class Foo
      attr_reader :foo
      def set_var_by_sym(sym, val)
        instance_variable_set(:"@#{sym}", val)
      end
    end
    
[/code]

> instance_variable_set(:foo, 1) で @foo に bind
> してくれた方がシンプルな気がしたのですが、関数がこのような動作になっている、何か特別が理由があったりするのでしょうか？

何をもってシンプルと捉えるかは人それぞれだと思いますが`:@foo`を渡すと`@foo`に値が入る方が直接対応していてシンプルではないでしょうか?

Rubyの動作については以下のサイトからバグレポートやフィーチャーリクエストを送ることが出来ます。  
`:foo`で`@foo`にbindしてほしいユースケースがあるのであれば、フィーチャーリクエストを送ってみるとよさそうです。  
<https://bugs.ruby-lang.org/>




`instance_variable_set`は引数として文字列を受け付けるので単に文字列の中で式展開でシンボルを埋め込むだけでよさそうです。

参考: <https://docs.ruby-lang.org/en/2.4.0/Object.html#method-i-
instance_variable_set>

[code]

    class Foo
      attr_reader :foo
      def set_var_by_sym(sym, val)
        instance_variable_set("@#{sym}", val)
      end
    end
    
[/code]

またSymbolに値を式展開して埋め込みたいなら以下のようにも書けます。

[code]

    class Foo
      attr_reader :foo
      def set_var_by_sym(sym, val)
        instance_variable_set(:"@#{sym}", val)
      end
    end
    
[/code]

> instance_variable_set(:foo, 1) で @foo に bind
> してくれた方がシンプルな気がしたのですが、関数がこのような動作になっている、何か特別が理由があったりするのでしょうか？

何をもってシンプルと捉えるかは人それぞれだと思いますが`:@foo`を渡すと`@foo`に値が入る方が直接対応していてシンプルではないでしょうか?

Rubyの動作については以下のサイトからバグレポートやフィーチャーリクエストを送ることが出来ます。  
`:foo`で`@foo`にbindしてほしいユースケースがあるのであれば、フィーチャーリクエストを送ってみるとよさそうです。  
<https://bugs.ruby-lang.org/>

