Почему выражение (true == true == true) вызывает синтаксическую ошибку?

Рубин:

true == true == true

синтаксическая ошибка, неожиданный tEQ

по сравнению с JavaScript:

true == true == true
// => true

по сравнению с C:

1 == 1 == 1
// => 1

person Rrr Rrr    schedule 09.01.2018    source источник
comment
Интересно, что это делают только операторы равенства (==, === и !=). Даже < и > анализируются правильно, а затем выдают ошибку времени выполнения, как и следовало ожидать. Кроме того, только sources Я могу найти, какое утверждение о наличии полной грамматики для Ruby указывает на то, что этот синтаксис допустимый.   -  person Silvio Mayolo    schedule 09.01.2018
comment
это также работает без скобок, как это, с явным вызовом, true .== true .== true   -  person potashin    schedule 09.01.2018
comment
Интересно, сколько других людей недоверчиво вводили ошибочный код в irb, ожидая другого результата?   -  person Brad Werth    schedule 09.01.2018
comment
stackoverflow.com/a/21060235/2864740 - == указан как неассоциативный (A=N)< /b> в ответе, что означает, что такая продукция X==Y==Z недействительна (ассоциативность — это то, что добавляет неявные круглые скобки вокруг операторов с одинаковым приоритетом). В вопросе есть много ссылок, которые могут вести к более официальному источнику, который можно было бы четко процитировать. (Этот вопрос скорее касается конкретного подмножества/применения грамматических правил в этом вопросе/ответе.)   -  person user2864740    schedule 09.01.2018
comment
@SilvioMayolo Согласно приведенному выше ответу, < и друзья являются левоассоциативными.. поэтому должны анализироваться (и работать, учитывая действительные входные данные во время выполнения). Я не уверен, какова грамматическая рациональность в отношении того, почему < будет ассоциативным, а == — нет, хотя изменение этого может сломать многие ожидания.   -  person user2864740    schedule 09.01.2018
comment
Итак, мы знаем, что это предполагаемое поведение, согласно предоставленной ссылке. Тогда это просто сводится к тому, почему. Я не вижу причин делать == неассоциативным, но все же позволять < и компании иметь ассоциативность.   -  person Silvio Mayolo    schedule 09.01.2018
comment
@SilvioMayolo Почему грамматика часто не по теме :) Тем не менее, практический пример синтаксиса, который работает, хотя и не работал бы, если бы была ассоциативность (т.е. неассоциативность позволяет этой другой форме конструкции [путем удаления другая двусмысленность]) было бы интересно посмотреть.   -  person user2864740    schedule 09.01.2018


Ответы (3)


Направление ассоциации, которое управляет порядком операторов, оценивающих свои аргументы, не определено для метода ==, так же как и для методов ===, !=, =~ и <=> (все они имеют одинаковый приоритет и образуют отдельную группу приоритета исключительно ).

Документация

Таким образом, порядок вычислений в случае, когда несколько операторов из списка, упомянутого выше, выстраиваются в цепочку в строке, должен быть установлен явно через либо

  • скобка ():

    (true == true) == true # => true
    true == (true == true) # => true
    
  • или оператор точки . (можно опустить для последней проверки на равенство в строке):

    true .== true == true # => true
    
person potashin    schedule 09.01.2018
comment
Мне было бы интересно узнать, почему, но я думаю, что это выходит за рамки вопроса и вашего ответа. - person Cary Swoveland; 09.01.2018
comment
@CarySwoveland, возможно, потому, что 1 == 1 == 1 будет оцениваться как false в Ruby, если == будет левоассоциативным, что, вероятно, приведет к нескольким ошибкам. И это тоже не имело бы особого смысла — единственными разумными значениями для третьего операнда являются true и false, то есть a == b == true и a == b == false, которые можно выразить как a == b и a != b. - person Stefan; 09.01.2018
comment
@Stefan: есть только одна ситуация, когда его можно использовать таким образом, чтобы это имело смысл, хотя я должен сказать, что пример несколько надуманный: == можно переопределить в пользовательском классе, и, таким образом, проверка на равенство может вернуть что-то отличное от true или false (например, nil) - person potashin; 09.01.2018
comment
@CarySwoveland Я думаю, что это можно решить с точки зрения дизайнера языка, например это - person Rrr Rrr; 12.01.2018
comment
javascript-truthiness-in-boolean-to-numbers-comparison почему мы все должны прекратить использовать 0 или 1 в примерах javascript, сравнивающих целые числа с целые числа или логические значения - person Arye Eidelman; 19.04.2018

TL; DR Синтаксис подразумевает, что все 3 значения равны, это не то, что он делает в javascript или C, поэтому, когда ruby ​​выдает синтаксическую ошибку, дверь открыта для реализации этого в будущем.

Если я правильно понимаю вопрос, value_a == value_b == value_c должен возвращать true только в том случае, если все они равны, используя == в качестве оператора сравнения, как показано в этом методе.

# version 1
def compare
#version 2
def compare_3_values(a, b, c)
  (a == b) == c
end
values(a, b, c) a == b && a == c && b == c end

хотя есть и другой возможный ожидаемый результат. чтобы реализовать это, как показано в предыдущем ответе:

#version 2
def compare_3_values(a, b, c)
  (a == b) == c
end

Результаты совершенно разные.

JavaScript всегда использует версию 2, что довольно бесполезно, так как 3-й элемент всегда сравнивается с истинным или ложным (0 или 1, если 3-й элемент является целым числом), поэтому false == false == true возвращает истину.

Хорошая новость заключается в том, что, поскольку ruby ​​выдает синтаксическую ошибку, это единственный язык, который может реализовать это, не нарушая общий код.

для любого другого языка это сломало бы так много кода, что даже если бы он был реализован в более поздней основной версии, потребовался бы флаг/настройка, чтобы включить или выключить это на долгие годы, поэтому это никогда не будет стоить.

Некоторые интересные результаты в Ruby

false .== false == true
=> true

false .== true == false
=> true

true .== false == false
=> true

false .== false == false
=> false

true .== true == false
false

И в джаваскрипте

false == false == true
=> true

false == true == false
=> true

true == false == false
=> true

false == false == false
=> false

true == true == false
=> false

Редактирование, также протестированное в C, действует аналогично JavaScript, поскольку сравнивает результат первых двух значений с третьим значением.

person Arye Eidelman    schedule 13.04.2018

первый ответ превосходен, но на случай, если он не совсем ясен (и люди спрашивают, почему), вот еще несколько примеров .


В C оператор == является ассоциативным слева направо, а логическое значение представлено как 1 (истина) и 0 (ложь), поэтому первый 1 == 1 оценивается как 1 (истина), а затем вы оцениваете результат первого выражения с помощью второй. Можешь попробовать:

2 == 2 == 2 // => 0

Который в C оценивается как:

(2 == 2) == 2
1 == 2 // => 0

В Javascript, как и в C, == ассоциативен слева направо. Давайте попробуем на этот раз с 0 (хотя тот же пример из C тоже сработает):

0 == 0 == 0
false

Опять таки:

0 == 0 == 0
true == 0 // => false

В Ruby == не имеет ассоциативных свойств, т.е. его нельзя использовать несколько раз в одном выражении, поэтому выражение нельзя вычислить. Почему было принято такое решение — вопрос к автору языка. Кроме того, Ruby не определяет число 1 как логическое значение, поэтому 1 == true оценивается как false.

Во втором ответе говорится, что в Ruby есть некоторые "странные" случаи, но все они оцениваются так, как ожидалось:

(1 == 1) == 1
true == 1 # => false

1 == (1 == 1)
1 == true # => false

1 .== 1 == 1
(1 == 1) == 1
true == 1 # => false

false .== false == true
(false == false) == true
true == true # => true

false .== true == false
(false == true) == false
false == false # => true

true .== false == false
(true == false) == false
false == false # => true

false .== false == false
(false == false) == false
true == false # => false

true .== true == false
(true == true) == false
true == false # => false
person Mayo    schedule 17.04.2018