web-dev-qa-db-ja.com

なぜRuby i ++またはi--(インクリメント/デクリメント演算子)をサポートしないのですか?

事前/事後のインクリメント/デクリメント演算子(++および--)は、かなり標準的なプログラミング言語の構文です(少なくとも手続き型およびオブジェクト指向言語の場合)。

なぜRubyをサポートしないのですか?+=-=で同じことを達成できると理解していますが、そのようなものを除外するのは奇妙にarbitrary意的です。特に簡潔で従来型だからです。

例:

i = 0    #=> 0
i += 1   #=> 1
i        #=> 1
i++      #=> expect 2, but as far as I can tell, 
         #=> irb ignores the second + and waits for a second number to add to i

Fixnumは不変であることは理解していますが、+=が新しいFixnumをインスタンス化し、それを設定できるのであれば、++に対して同じことをしないのはなぜですか。

=文字を含む割り当ての一貫性がこの唯一の理由ですか、それとも何か不足していますか?

127
Andy_Vulhop

古い thread でMatz(Matsumoto Yukihiro)が説明する方法は次のとおりです。

Hi,

In message "[Ruby-talk:02706] X++?"
    on 00/05/10, Aleksi Niemelä <[email protected]> writes:

|I got an idea from http://www.pragprog.com:8080/rubyfaq/rubyfaq-5.html#ss5.3
|and thought to try. I didn't manage to make "auto(in|de)crement" working so
|could somebody help here? Does this contain some errors or is the idea
|wrong?

  (1) ++ and -- are NOT reserved operator in Ruby.

  (2) C's increment/decrement operators are in fact hidden assignment.
      They affect variables, not objects.  You cannot accomplish
      assignment via method.  Ruby uses +=/-= operator instead.

  (3) self cannot be a target of assignment.  In addition, altering
      the value of integer 1 might cause severe confusion throughout
      the program.

                            matz.
90
Brian

1つの理由は、これまでのすべての代入演算子(つまり、変数を変更する演算子)に=が含まれているためです。 ++--を追加した場合、それは当てはまりません。

別の理由は、++--の動作がしばしば人々を混乱させることです。事例:i++の戻り値は、実際には2ではなく1です(ただし、iの新しい値は2になります)。

28
sepp2k

OO言語では一般的ではありません。実際、「オブジェクト指向プログラミング」という用語を生み出した言語であるSmalltalkには++はありません(言語Rubyは最も強く影響を受けます)。つまり、[〜#〜] c [〜#〜]およびCによく似た言語では慣習的です。Rubyには多少C-構文に似ていますが、Cの伝統を順守しているわけではありません。

Rubyに含まれていない理由については、Matzはそれを望んでいませんでした。それが本当に究極の理由です。

Smalltalkにそのようなものが存在しない理由は、変数を割り当てることはメッセージを送信することとは根本的に異なるkindであるという言語の最優先哲学の一部であるためですオブジェクトに—それは異なるレベルにあります。この考え方はおそらく、Rubyの設計においてMatzに影響を与えました。

Rubyに含めることは不可能ではありません。すべての+++=1に変換するプリプロセッサを簡単に書くことができます。しかし明らかにMatzは、「隠された割り当て」を行う演算子のアイデアを好まなかった。また、内部に隠れた整数オペランドを持つ演算子があるのは少し奇妙に思えます。その言語の他のオペレータはそのようには機能しません。

23
Chuck

別の理由があると思います:++ in Rubyは、Cやその直接の後継者のように、リモートでは役に立ちません。

理由は、forキーワードです。Cでは必須ですが、Rubyではほとんど不要です。 Rubyの繰り返しのほとんどは、データ構造を繰り返し処理するときのeachmapなどのEnumerableメソッド、およびFixnum#timesメソッド、正確な回数ループする必要がある場合。

実際、私が見た限りでは、ほとんどの場合+=1は、Cスタイル言語からRubyに新たに移行した人々によって使用されます。

要するに、メソッド++および--がまったく使用されます。

11

Matzがそれらを好まない理由は、変数を実際に新しい変数に置き換えるからだと思います。

例:

 a = SomeClass.new 
 def a.go 
 'hello' 
 end 
#この時点で、a.go [ .____。オリジナル

誰かが#succを呼び出すだけだと彼に納得させることができたら!またはそうでない場合、それはより意味があり、問題を回避します。 Ruby core。

3
rogerdpack

.+自己インクリメント演算子を定義できます。

class Variable
  def initialize value = nil
    @value = value
  end
  attr_accessor :value
  def method_missing *args, &blk
    @value.send(*args, &blk)
  end
  def to_s
    @value.to_s
  end

  # pre-increment ".+" when x not present
  def +(x = nil)
    x ? @value + x : @value += 1
  end
  def -(x = nil)
    x ? @value - x : @value -= 1
  end
end

i = Variable.new 5
puts i                #=> 5

# normal use of +
puts i + 4            #=> 9
puts i                #=> 5

# incrementing
puts i.+              #=> 6
puts i                #=> 6

「クラス変数」の詳細については、「 Fixnumオブジェクトをインクリメントするクラス変数 」で参照できます。

3
Sony Santos

そして、彼の本「The Well-Grounded Rubyist」からのDavid Blackの言葉で:

Rubyのオブジェクトは、即値として変数に保存されます。これらには、整数、シンボル(:thisのように見えます)、およびtrue、false、nilの特別なオブジェクトが含まれます。これらの値を変数(x = 1)に設定すると、変数は値への参照ではなく、値自体を保持します。実際には、これは重要ではありません(繰り返し綴られるのではなく、暗黙的に残されます)本書の参照および関連トピックの議論で。Rubyオブジェクト参照の参照解除を自動的に処理します。以下を含むオブジェクトにメッセージを送信するために追加の作業を行う必要はありません。たとえば、即値整数値を含むオブジェクトとは対照的に、文字列への参照ですが、即値表現ルールには、特に整数に関しては、いくつかの興味深い影響があります。即値は、変数iの数に関係なく、常にまったく同じオブジェクトですtが割り当てられています。オブジェクト100は1つだけ、オブジェクトは1つだけ偽などです。整数にバインドされた変数の直接的でユニークな性質は、Rubyにプリインクリメント演算子とポストインクリメント演算子がないことの背後にあります。つまり、Rubyではこれを実行できません。x = 1 x ++#そのような演算子はありませんxに1が直接存在する場合、x ++は1 ++のようになります。つまり、数値1を数値2に変更することになりますが、これは意味がありません。

2
Alexander Swann

これは、fixnumまたはIntegerクラスに新しいメソッドを追加することで達成できませんでしたか?

$ Ruby -e 'numb=1;puts numb.next'

2を返します

「破壊的」メソッドには、!が追加されている可能性があるユーザーに警告するように見えるため、next!という新しいメソッドを追加すると、要求されたとおりになります。

$ Ruby -e 'numb=1; numb.next!; puts numb' 

2を返します(numbがインクリメントされているため)

もちろん、next!メソッドは、オブジェクトが実数ではなく整数変数であることを確認する必要がありますが、これはshouldが利用可能である必要があります。

1
Sjerek