Ruby가 i ++ 또는 i-(증가 / 감소 연산자)를 지원하지 않는 이유는 무엇입니까?


130

사전 / 사후 증가 / 감소 연산자 ( ++--)는 표준 프로그래밍 언어 구문입니다 (적어도 절차 및 객체 지향 언어의 경우).

루비가 왜 그것들을 지원하지 않습니까? 난 당신과 같은 일을 수행 할 수 이해 +=하고 -=있지만, 그냥 그렇게 간결하고 기존의 특히 이후, 그런 일을 제외 이상한 임의 보인다.

예:

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불변이라는 것을 이해 하지만 +=, 새로운 것을 instanciate Fixnum하고 설정할 수 있다면, 왜 그렇게하지 ++않습니까?

=캐릭터를 포함하는 과제의 일관성 이 이것의 유일한 이유입니까, 아니면 뭔가 빠졌습니까?


2
그런 연산자를위한 Ruby 소스 코드를 정리하십시오. 아무것도 없다면-Matz는 그들을 좋아하지 않습니다.
Eimantas

+=운영자 와 사전 증분을 수행 할 수 없습니다 . CI에서 사용하려고 ++/ --더 리터럴에 대한 선호 만 조건문 내부 +=/ -=기본 문에. 아마도 파이썬을 배웠기 때문에 (아마도 C 이후 ...)
Nick T

어제 파이썬에 대해 이와 같은 질문이 없었습니까?
BoltClock

@Eimantas는 분명히 언어를 만든 사람이 마음에 들지 않았습니다. 간과하기에는 너무 일반적입니다. 나는 왜 아래 답변에 의해 명확하게 밝혀 졌는지 궁금합니다.
Andy_Vulhop

1
나는 이것이 (거의) 모델 SO 질문이라고 생각합니다. 고려 된 답변을 얻는 것은 쉬운 일이 아닙니다. 어떤 대답이 필요한지가 명확하고 구체적이며, 질문의 핵심보다 더 광범위하게 생각할 수있는 프로그래밍 측면에 대한 답을 제시합니다.
PurplePilot

답변:


97

Matz (Yukihiro Matsumoto)가 옛날에 그것을 설명하는 방법은 다음과 같습니다. 스레드 :

Hi,

In message "[ruby-talk:02706] X++?"
    on 00/05/10, Aleksi Niemelä <aleksi.niemela@cinnober.com> 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.

10
2와 3은 모순되는 것처럼 보입니다. 자기 배정이 나쁘면 왜 +=/ -=괜찮습니까? 그리고 1+=1나쁘지 않을까요? (와 IRB에서 실패 syntax error, unexpected ASSIGNMENT)
Andy_Vulhop

2
(2)는 C에서 값 자체를 변경하지 않고 값을 보유하는 변수의 내용을 변경한다는 것을 의미합니다. 그것은 가치에 의해 전달되는 모든 언어에 비해 너무 메타입니다. 루비에서 참조로 무언가를 전달하는 방법이 없다면 (그리고 값으로 참조를 전달하지 않고 진정으로 "참조로"를 의미합니다) 변수 자체를 변경하는 것은 메소드 내에서 가능하지 않습니다.
cHao

5
어쩌면 여기에 뭔가 빠졌을 수도 있습니다. +=변수가 참조하는 객체를 완전히 새로운 객체로 바꿉니다. i.object_id이전과 이후 에 전화하여이를 확인할 수 있습니다 i+=1. 왜 기술적으로 더 까다로운 일 ++일까요?
Andy_Vulhop

6
@Andy_Vulhop : # 3은 일반적으로 할당이 불가능한 이유가 아니라 할당이 방법으로 기술적으로 불가능한 이유를 설명하고 있습니다 (포스터 Matz는 ++방법 을 만들 수 있다고 생각했습니다 ).

2
루비에서는 모든 리터럴도 객체입니다. 그래서 Matz는 1 ++를 진술로 다루는 아이디어를 좋아한다고 확신하지 못한다고 말하고 있다고 생각합니다. 개인적으로 @Andy_Vulhop이 1 + = 2가 똑같이 말하고 루비 가이 작업을 수행하면 오류가 발생하기 때문에 이것이 합리적이지 않다고 생각합니다. 따라서 1 ++는 다루기가 어렵지 않습니다. 아마도 구문 분석기가 그런 종류의 구문 설탕에 대처해야 할 필요는 없습니다.
Steve Midgley

28

한 가지 이유는 지금까지 모든 할당 연산자 (즉, 변수를 변경하는 연산자)에 포함 =되어 있기 때문입니다. 추가하면++-- 더 이상 그렇지 않습니다.

또 다른 이유는 사람들 의 행동 ++--종종 혼동 되기 때문입니다 . 적절한 i++예 : 예제에서 의 반환 값 은 실제로 2가 아니라 1입니다 ( i그러나 새 값은 2 임).


4
지금까지 다른 어떤 이유보다도“모든 과제가 =그들 안에있다”는 합리적 의미가있는 것 같습니다. 나는 일관성에 대한 엄격한 준수로서 그것을 존중할 수 있습니다.
Andy_Vulhop

이것에 대해 : a. 자본화! (a의 암시 적 할당)
Luís Soares

1
@ LuísSoares a.capitalize!는 재지 정하지 않으며 a, a참조 하는 문자열을 변경합니다 . 동일한 문자열에 대한 다른 참조가 영향을받으며을 a.object_id호출하기 전후 capitalize에 동일한 결과를 얻을 수 있습니다 ( a = a.capitalize대신 수행 한 경우 둘 중 어느 것도 해당되지 않음 ).
sepp2k

1
@ LuísSoares 내가 말했듯 a.capitalize!이 동일한 문자열에 대한 다른 참조에 영향을 미칩니다. 그것은 실질적인 차이입니다. 예를 들어, def yell_at(name) name.capitalize!; puts "HEY, #{name}!" end다음과 같이 호출하면 다음과 같이 호출합니다. my_name = "luis"; yell_at(my_name)의 값 my_name은 이제 "LUIS"이고, 사용 capitalize하고 할당 한 경우에는 영향을받지 않습니다 .
sepp2k

1
와. 무서워 ... 자바 문자열에서 변할 수 없다는 것을 아는 것 .. 그러나 힘에는 책임이 따른다. 설명 주셔서 감사합니다.
Luís Soares

25

OO 언어에서는 일반적이지 않습니다. 실제로 ++스몰 토크에는 "객체 지향 프로그래밍"이라는 용어가 사용 된 언어 가 없습니다 (그리고 루비 언어가 가장 큰 영향을받는 언어). 당신이 의미하는 바는 그것이 C 에서 일반 적이고 C 를 밀접하게 모방하는 언어 라는 것입니다 . 루비는 다소 C와 유사한 구문을 가지고 있지만 C 전통을 고수하는 데 노예가 아닙니다.

왜 루비가 아닌지에 관해서 : Matz는 그것을 원하지 않았습니다. 이것이 정말로 궁극적 인 이유입니다.

스몰 토크에 그러한 것이 존재하지 않는 이유는 변수를 할당하는 것이 근본적으로 다른 종류 라는 언어의 우선 철학의 일부이기 때문입니다 객체에 메시지를 보내는 의 다른 수준에 있습니다. 이 생각은 아마도 루비 디자인에서 Matz에 영향을 미쳤을 것입니다.

루비에 포함시키는 것은 불가능하지 않습니다 . 모두 ++로 변환하는 전처리기를 쉽게 작성할 수 있습니다 +=1. 그러나 Matz는 "숨겨진 과제"를 수행 한 운영자의 아이디어를 좋아하지 않았을 것입니다. 내부에 숨겨진 정수 피연산자가있는 연산자가있는 것도 조금 이상합니다. 그 언어의 다른 연산자는 그런 식으로 작동하지 않습니다.


1
전 처리기 제안이 효과가 있다고 생각하지 않습니다. (전문가는 아니지만) i = 42, i ++는 42를 반환하고 i + = 1은 43을 반환한다고 생각합니다. 따라서이 경우 귀하의 제안은 ++ i가 일반적으로 사용되므로 i ++를 사용하는 것입니다.
AturSams

12

또 다른 이유가 있다고 생각합니다. ++Ruby에서는 C와 그 후속 작업처럼 원격으로 유용하지 않을 것입니다.

그 이유는 for키워드입니다. C에서는 필수적이지만 루비에서는 대부분 불필요한 것입니다. 루비 반복 대부분 Enumerable에서와 같은 방법으로 수행 each하고 map순회 통해 어떤 데이터 구조 및Fixnum#times 당신이 루프 시간의 정확한 수를 필요로 할 때, 방법.

실제로, 내가 본 한, 대부분의 시간 +=1은 C 스타일 언어에서 Ruby로 새로 이주한 사람들이 사용합니다.

요컨대, 방법 ++--사용 여부는 실제로 의문의 여지 가 있습니다.


1
이것이 가장 좋은 답변입니다. ++는 종종 반복에 사용됩니다. 루비는 이런 유형의 반복을 권장하지 않습니다.
AturSams

3

나는 그들이 좋아하지 않는 Matz의 추론이 실제로 변수를 새로운 것으로 대체한다고 생각합니다.

전의:

a = SomeClass.new
데프 a.go
  '여보세요'
종료
#이 시점에서 a.go를 호출 할 수 있습니다
#하지만 당신이 a ++를했다면
#는 a = a + 1을 의미합니다.
# 더 이상 a.go를 호출 할 수 없습니다
# 원본을 잃어 버렸을 때

이제 누군가가 #succ를 호출해야한다고 설득 할 수 있다면! 또는 그렇지 않은 것이 더 합리적이며 문제를 피할 수 있습니다. 루비 코어에서 제안 할 수 있습니다.


9
... "당신은 루비 코어를 제안 할 수 있습니다" 읽은 그 전에 그 전에 시간, 그 전에 시간, 시간이 마지막으로 제안 된 모든 다른 스레드의 인수를 이해하고, 그리고 그 이전의 시간, 그리고 ... 나는 루비 공동체에 오래 가지 않았지만, 단지 나의 시간 동안, 적어도 20 개의 그러한 토론을 기억합니다.
Jörg W Mittag

3

.+자체 증가 연산자를 정의 할 수 있습니다 .

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

"class Variable"에 대한 자세한 정보는 " Fixnum 오브젝트를 증가시키기위한 클래스 변수 "에서 사용할 수 있습니다 .


2

그리고 그의 저서 "The Well-Grounded Rubyist"에서 David Black의 말에 따르면 :

Ruby의 일부 객체는 변수에 즉시 값으로 저장됩니다. 여기에는 정수, 기호 (: this 모양) 및 특수 객체 true, false 및 nil이 포함됩니다. 이 값 중 하나를 변수 (x = 1)에 지정하면 변수는 값에 대한 참조가 아니라 값 자체를 보유합니다. 실제적으로 이것은 중요하지 않습니다 (그리고이 책의 참고 문헌 및 관련 주제에 대한 논의에서 반복적으로 철자하기보다는 암시 적으로 남겨지는 경우가 많습니다). 루비는 객체 참조의 역 참조를 자동으로 처리합니다. 즉시 정수 값을 포함하는 객체와 달리 문자열에 대한 참조를 포함하는 객체에 메시지를 보내기 위해 추가 작업을 수행 할 필요가 없습니다. 그러나 즉각적인 가치 표현 규칙에는 몇 가지 흥미로운 결과가 있습니다. 특히 정수에 관해서는. 우선, 즉각적인 값으로 표시되는 모든 객체는 얼마나 많은 변수가 할당 되든지 항상 동일한 객체입니다. 하나의 객체 100, 하나의 객체 false 만 있습니다. 정수 바운드 변수의 즉각적이고 고유 한 특성은 Ruby의 증분 및 사후 증가 연산자가 부족하다는 것입니다. 즉, Ruby에서는이를 수행 할 수 없습니다. x = 1 x ++ # 해당 연산자는 없습니다. x에서 1이 바로 존재하게되면 x ++는 1 ++와 같을 것입니다. 즉, 숫자 1을 숫자 2로 변경한다는 것은 의미가 없습니다. 얼마나 많은 변수가 할당 되든지 상관 없습니다. 하나의 객체 100, 하나의 객체 false 만 있습니다. 정수 바운드 변수의 즉각적이고 고유 한 특성은 Ruby의 증분 및 사후 증가 연산자가 부족하다는 것입니다. 즉, Ruby에서는이를 수행 할 수 없습니다. x = 1 x ++ # 해당 연산자는 없습니다. x에서 1이 바로 존재하게되면 x ++는 1 ++와 같을 것입니다. 즉, 숫자 1을 숫자 2로 변경한다는 것은 의미가 없습니다. 얼마나 많은 변수가 할당 되든지 상관 없습니다. 하나의 객체 100, 하나의 객체 false 만 있습니다. 정수 바운드 변수의 즉각적이고 고유 한 특성은 Ruby의 증분 및 사후 증가 연산자가 부족하다는 것입니다. 즉, Ruby에서는이를 수행 할 수 없습니다. x = 1 x ++ # 해당 연산자는 없습니다. x에서 1이 바로 존재하게되면 x ++는 1 ++와 같을 것입니다. 즉, 숫자 1을 숫자 2로 변경한다는 것은 의미가 없습니다.


그렇다면 어떻게 "1.next"를 할 수 있습니까?
Magne

1

fixnum 또는 Integer 클래스에 새 메소드를 추가하여이를 달성 할 수 없습니까?

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

2를 반환

!가능한 사용자에게 경고하기 위해 "파괴적인"방법이 추가 된 것 같습니다 . 따라서 새로운 방법을 추가하면 next!요청한 것과 거의 같은 일을합니다.

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

2를 리턴합니다 (마비가 증가 했으므로)

물론이 next!방법은 객체가 정수 변수이고 실수가 아닌지 확인 해야 하지만이 변수 사용 가능 해야 합니다.


1
Integer#nextInteger#succ대신 ( '성공자'를 위해) 호출되는 것을 제외하고는 이미 존재합니다 . 그러나 Integer#next!(또는 Integer#succ!) 말도 안됩니다 : 메소드가 객체 에서 작동 하지만 변수가 . 따라서 numb.next!정확히 같을 것 1.next!입니다. 즉, 1을 2로 변경 합니다. ++과제의 구문 설탕 일 수 있기 때문에 조금 나아질 것입니다. 그러나 개인적으로 모든 과제가로 끝나는 현재 구문을 선호합니다 =.
철학 1

위의 주석을 완료하고 Integer#pred선행 작업을 검색하십시오.
Yoni

-6

Ruby의 irb에서 C 계열의 연산자를 확인하고 직접 테스트하십시오.

x = 2    # x is 2
x += 2   # x is 4
x++      # x is now 8
++x      # x reverse to 4

3
(x++)루비에서 유효하지 않은 문장 처럼, 이것은 분명히 잘못되었으며 작동하지 않습니다 .
anothermh
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.