Итак, давайте поговорим о Ruby WAT!
В этой статье я расскажу о нескольких конструкциях языка программирования Ruby, которые могут сделать код неясным / нечитаемым. Примеры, которые я приведу, представляют собой довольно сложные случаи, но я использую их исключительно для демонстрации концепции.
В прошлом меня просили написать синтаксический анализатор для Ruby, после того как я написал его, я решил, что Ruby не является для меня языком.
Прежде всего, я хочу дать вам несколько примеров правильных конструкций ruby, прежде чем продолжить, чтобы объяснить, что не так с тем фактом, что эти конструкции допустимы.
Оператор if-modifier
if-modifier-statement ::
statement [ no line-terminator here ] if expression
Вышеприведенное определение означает, что вместо обычного оператора if, например,
if y == 3 then
statement1
end
также эта эквивалентная форма будет действительной:
statement1 if y == 3
Эта форма известна как модификатор if.
Вызовы метода
Аргументы метода не должны быть заключены в скобки:
method-invocation-expression ::= primary-method-invocation
| method-invocation-without-parentheses
| local-variable-identifier
В строке 2 мы видим ссылку на метод method-invocation-без скобок ниже.
method-invocation-without-parentheses :: command
| chained-command-with-do-block
| chained-command-with-do-block ( . | :: ) method-name
| argument-without-parentheses
| return-with-argument
| break-with-argument
| next-with-argument
В строке 4 мы видим ссылку на конструкцию аргумента без скобок ниже:
argument-without-parentheses ::
[ lookahead ∈/ { { } ] [ no line-terminator here ] argument-list
Заявления не должны заканчиваться точкой с запятой, если только в одной строке. Однако оператор if может быть записан в одну строку, а начало может быть заменено разделителем, как показано в следующем фрагменте грамматики:
if-expression ::
if expression then-clause elsif-clause∗ else-clause? end
ElseIf придаточного и еще придаточного не являются обязательными.
then-clause ::
separator compound-statement
| separator ? then compound-statement
Тогда положение может или не может включать в себя то.
separator :: ;
| [line-terminator here]
Разделитель определяется как новая строка или точка с запятой.
Учитывая вышеприведенную информацию, как бы вы интерпретировали следующее, учитывая, что examplePrint является именем метода как isFalse:
print "foo"; if isTrue; print "bar" end
Это правильная строка кода, но здесь очень неясно, каково ожидаемое поведение для того, кто читает код. Очевидно, это напечатало бы или foo, bar или оба.
Итак, давайте посмотрим на это подробно:
print "foo"
это утверждение, как упоминалось ранее
if isTrue
может применяться к этому заявлению. Однако в этом случае
if isTrue
относится к
print "bar"
потому что
print "bar"
сопровождается
end
Другой пример, когда язык может быть неправильно понят, — это когда переменная и функция имеют одно и то же имя, но метод не принимает аргументов. Примером этого может быть:
number = 3
sum = 0
def number()
return 6
end
sum = number
print sum
print number()
print number
Вывод при запуске кода выглядит следующим образом: 363
В строке 8 не ясно, имеем ли мы в виду нумерацию переменную или нумерацию функции. В этом случае практически невозможно понять, на что ссылается идентификатор, поскольку вызов метода или функции не требует наличия круглых скобок. Очевидно, что это делает код очень сложным для чтения и обслуживания.
Здесь я только что изложил два случая, которые я обнаружил при написании парсера для Ruby. Очевидно, что такое программирование не было бы наилучшей практикой, поэтому вряд ли это будет проблемой. Тем не менее, эти проблемы очень затрудняют понимание и поддержку этих языков. Если бы язык рассматривал пробелы так же важно, как это делает Python, это было бы не такой проблемой.
Назовите меня старомодным, но если это относится к утверждениям, на которые оно влияет. Я также думаю, что для завершения операторов всегда должна использоваться и использоваться только одна форма терминатора операторов. Эти мелочи делают язык намного чище и яснее.
На следующей неделе я расскажу на другом языке.