Каким должен быть язык программирования? Анализ и критика Описание языка Компилятор
Отечественные разработки Cтатьи на компьютерные темы Компьютерный юмор Новости и прочее

Условные операторы

Примеры реализации условных операторов в некоторых языках программирования. Языки C, C++, Java, C#, Perl, PHP, D:

if (условие)
{
   операторы
}
else
{
   операторы
}
Algol, Pascal:
if условие then
   begin
     операторы
   end
else
   begin
     операторы
   end
Phyton:
if условие:
   операторы
else:
   операторы
Ruby:
if условие
   операторы
else
   операторы
endif
Euphoria:
if условие then
   операторы
else
   операторы
end if
            Синтаксический сахар виден невооружённым взглядом. Ключевые слова «begin» и «end» вычёркиваем из языка своей мечты. Совершенно не нужен «then», его тоже исключаем. Условный оператор легко вписывается в «симметричный скобочный» стиль:
( if условие
       операторы
else
       операторы )
            Надо заметить, что некоторые языки программирования имеют оператор «elseif» или «elif». Его назначение — проверить ещё одно условие внутри данного условного выражения. Например, так:
if a = 1
   b := 0
elseif a = 2
   c := 1
elseif a = 3
   d := 2
else
   b := -1
endif
            Отказываться от такой дополнительной проверки неразумно, но какое ключевое слово выбрать: «elseif» или «elif»? Предложение такое: ни то, ни другое. Можно взять вышестоящее ключевое слово, а именно «if». Дело в том, что первому «if», начинающему условное выражение, предшествуюет открывающая скобка, а вот последующие «if» (там где в других языках употребляется «elseif») этой скобки впереди себя не имеют.

            Что имеем в итоге? Ранее мы решили, что синтаксический сахар должен быть заменён графическим, который возникает «сам по себе» при вводе текста. И в итоге имеем в IDE примерно следующее (не ищите большого смысла в этом якобы коде, приведённое ниже — иллюстрация, пример отображения этого кода):

(       if a == b  
        a = 0  
  b = 1
(       if c == d  
        c += 2  
  d /= 2  
         else  
 
(       if a == d  
        c = a + b  
  d = d * 3 + c
(       if c > d  
        b = d + c * 2  
  c *= b * d + 1 )
 
  c += b  
         else  
  c *= b + 2 )
 
  c += 3 )
 
        if a > b           // Здесь оператор if аналогичен традиционному else if  
        a = b * 4  
  b /= 4  
         else  
  b *= 2 )

            Как видите, получилась очень неплохая замена синтаксическому сахару. Вложенные блоки выделяются другим фоном (как один из вариантов). Смысл этих нововведний очень прозрачен, большинству программистов его не придётся объяснять.

            Стоит так же отметить, что предложенный синтаксис условного оператора решает проблему «висячего else», на которую обратил внимание Никлаус Вирт:
if условие 1
   ...
if условие 2
   ...
else
   ...
К какому «if» относится «else»? Вирт предлагает использовать «end» для окончания таких конструкций. Наше предложение короче, надо заканчивать конструкции закрывающей скобкой.

Опубликовано: 2012.09.25, последняя правка: 2019.01.11    09:45

ОценитеОценки посетителей
   ███████████████ 5 (35.7%)
   ███████████████ 5 (35.7%)
   ████████████ 4 (28.5%)
   ▌ 0

Отзывы

     2013/04/14 09:59, Михаил          # 

В модуле, обероне, аде нет составного оператора begin end.
Там конструкции вида if elsif elsif ... [else] end.
Составной оператор не является синтаксическим сахаром это суровая необходимость для таких языков как Pascal, C, C++ и многих других. это особенность грамматики этих языков.

     2013/04/14 15:20, Автор сайта          # 

Да, в Си и Паскале — это суровая необходимость. В Си без фигурных скобок невозможно выполнить сразу несколько действий в операторе «if»: if (…) {оператор_1; … оператор_N}, без скобок выполнился бы только первый оператор. Но это не значит, что без составного оператора нельзя обойтись. Си и Паскаль в этом плане — жертвы неудачных задумок их авторов. Язык Питон ярко доказывает, что операторные скобки — это всё-таки синтаксический сахар.

Насчёт Модулы, Ады и Оберона — учёл, спасибо.

     2013/11/16 12:36, Noname          # 

В Форт (Forth)
<флаг_условия> IF слова_true_условия ELSE слова_false_условия THEN

     2015/01/23 23:25, rst256          # 

( if условие ...

может быть потенциально опасной конструкцией. В случае, если в синтаксисе языка найдется пара токенов, способных валидно соединится как end_expr + begin_stat, так и expr + end_expr. Программисту будет весело :-)
Помните у C/C++ был висячий else?

     2015/01/25 15:38, Автор сайта          # 

Почему «был»? Он до сих пор есть! О нём нельзя говорить только в прошедшем времени. О нём можно уверенно говорить в будущем времени! Новые языки типа Go или Rust вполне успешно имеют у себя висячий else. Можно с уверенностью предсказать, что он будет и в ещё неродившихся языках. Готов держать пари!
Могли бы привести пример опасной конструкции «(if …»?

     2016/04/16 11:08, rst256          # 

Могли бы привести пример опасной конструкции «(if …»?

Каким образом? Эта конструкция содержит в себе как минимум все конструкции уровня "блок кода", а то и уровня "функции" (если они об. 1-го класса). Дайте описания синтаксиса всех входящих в неё конструкций, я попробую дать ответ.

     2016/04/16 12:19, rst256          # 

А насчет висячего else вы правы, разрешение неоднозначности тут делается "костылем", оказывается нельзя слепо верить стандартам языка, запомнил что де-юре проблемам решена, но де-факто она таки да, осталась:

Эта неоднозначность разрешается в языке Си с помощью правила, в соответствии с которым часть else оператора всегда относится к синтаксически самому правому, игнорируя любые отступы, оператору if без части else. Следовательно, первая интерпретация является интерпретацией, принятой в языке Си.

Был у меня один веселый случай
if() some() else ...
А some был макросом оператора if без части else... Отдаю предпочтение в данном вопросе синтаксису языка lua:
if ... then 
do -- это не цикл, do-end операторные скобки, только для работы со scope
while ... do ... end 
end
...
elseif ... then ...
else
x=5+5+5
print(x, 7, function() end)
end
Блок else тут содержит реальный код, синтаксис не нуждается в разделителе операторов (по желанию можно ставить ";" но это сахар), а выражение может содержать анонимную функцию.

     2015/04/16 15:48, Автор сайта          # 

А then зачем нужен? Это же мусор. Условный оператор вида (if ... else ...) исключает все неоднозначности.

     2016/11/02 10:25, rst256          # 

А then зачем нужен? Это же мусор. Условный оператор вида (if ... else ...) исключает все неоднозначности.

Неоднозначности да, но скобка в начале это то же мусор, и усложняет исправление ошибок типа "пропущена скобка...".

     2017/02/02 16:50, Михаил          # 

Лишить автора сахара! Операторные скобки улучшают понятность и читабельность кода.

     2017/05/03 08:59, rst256          # 

Лишить автора сахара! Операторные скобки улучшают понятность и читабельность кода.

В тех языках, где они есть, их польза несомненна. Но в языках без операторных скобок понятность и читабельность кода гораздо выше. Как понятнее так
if(...){...}
if(...){...}else{...}
или так
if ... then ... end
if ... then ... else ... end
?
Способ соединить несколько операций в одну в виду того, что циклы, условия и прочие конструкции принимают изначально только одну операцию? Или же конструкции, которые изначально были рассчитанные на работу с несколькими операциями, что логичнее?

P.S. Если не ошибаюсь для одиночных операций сейчас тоже принято использовать операторные скобки. Так, на всякий пожарный...

     2017/05/18 11:29, Автор сайта          # 

для одиночных операций сейчас тоже принято использовать операторные скобки.

В языке Rust операторные скобки обязательны.

     2017/09/21 00:32, Comdiv          # 

Плохое решение. Забыл о скобках у вложенного условного оператора — и он оказывается частью объемлющего. Вы, конечно, рассчитываете на IDE, которая расставит отступы, но зависимость от IDE — это тоже плохое решение. Там же отделение условия от операторов переводом строки.

     2017/09/21 23:05, Автор сайта          # 

Да, «elseif» хоть и можно заменить на «if» при скобочном обособлении ветвей, но без среды разработки это и вправду будет создавать проблемы. С «elseif» — надёжнее.

     2017/11/05 15:39, rst256          # 

Почему «был»? Он до сих пор есть! О нём нельзя говорить только в прошедшем времени. О нём можно уверенно говорить в будущем времени! Новые языки типа Go или Rust вполне успешно имеют у себя висячий else. Можно с уверенностью предсказать, что он будет и в ещё не родившихся языках. Готов держать пари!

Хорошо давайте поспорим, что я уберу висячий else, просто переставив один символ. Вот наглядный пример вреда исключений в синтаксисе, т.к. код в операторных скобках обрабатывается также, как единичное действие, то и синтаксис его должен быть таким же, как у всех единичных действий, а именно:
 <некое действие> ';'
Теперь в условном операторе код блока "тогда" оканчивается разделителем тогда, когда ветвь "иначе" опущена. И для вящего порядка разделитель после последнего действия внутри в операторных скобок убираем в ввиду его бессмысленности (что впрочем не мешает при желании его там использовать, пустую операцию ';' ведь никто не отменял).

Пример:
if( !v ){ printf(fmt, v); v=0;return(v);  };
if( !v ){ printf(fmt, v) } else { v=v+1; return(v) };

if( !v ) return(null);
if( v ) printf(fmt, v) else return(v);

if( !v ) ; /* если тут пропустить разделитель то нижестоящий блок будет присоединен к данному условию. */

{ printf(fmt, v); v=0;return(v); };
{ printf(fmt, v); v=0;return(v) };
Описание грамматики для парсера packcc:
statements <- 
( _ statement _ ';' )+

statement <-
block
/ callstat { printf("callstat: %s\n", $0); }
/ call { printf("call: %s\n", $0); }
/ assign
/ define_var_stat


ifstat <-
'if' _ '(' _ expression _ ')' _ statement _ 'else' _ statement
/ 'if' _ '(' _ expression _ ')' _ statement
/ 'if' _ '(' _ expression _ ')'


block <-
'{' _ statement _ ( ';' _ statement _ )* ';'? _ '}' { printf("block: %s: %d %d\n", $0, $0s, $0e); }


assign <-
< ident > _ '=' _ < expression >


define_var_stat <-
te:type_expr _ ':' _ ( assign / < IDENT > )
Исходник целиком доступен по ссылке https://github.com/rst256/packcc_lc/blob/master/lc.cc

     2021/03/26 15:51, Виталий Монастырский          # 

Очень плохое решение. Курс мысли верный, но решение никуда не годится. Во-первых, автор просто вывернул наизнанку уже существующий синтаксис. Поменял один вид скобок на другой — вместо {} стал использовать (). Потом взял скобки из области определения и вынес за неё. Было:
if
{
...
}
Cтало:
(if
...)
Что поменялось, кроме угла поворота? Ничего. Те же яйца только в профиль.

Итак, начнем с первого.

1) Действительно много лишних операторов можно просто убрать. Оставляем только if и else.

2) Принимаем общую форму записи как у Python-а — она наиболее читабельна и быстра в написании. То есть разделение ветвления производим с помощью отступов.

3) Исправляем ошибку автора и в качестве разделителя блока используем не сам блок, а только его условный оператор, ибо такой код намного читабельней и очевидней — исполняемые операторы отделяются от условия и точек начала/конца блока.

4) Заменяем предлагаемый автором вторичный if на вторичный else. Это избавит нас от необходимости городить забор из скобок ради определения вторичных проверок ifelse. При этом с точки зрения логики будет четко понятно, что мы имеем дело с продолжением того же набора проверок. Последний else без условий оставляем в качестве оператора по умолчанию, если он нужен в данном списке условий. Получаем:
if условие      # проверка 1.1
...
...
if условие # проверка 2.1
...
...
else условие # проверка 2.2
...
... # конец 2 без умолчания
else условие # проверка 1.2
...
...
else # умолчание 1
...
... # конец 1
Вот и все дела. Никаких тебе скобок, никаких тебе лишних операторов, никакой тебе путаницы, никаких проблем с разделением уровней ветвления как визуально, так и для синтаксического анализатора.

     2021/03/27 12:52, Автор сайта          # 

Синтаксис Питона хорош, спору нет. Но и он не идеален. В нём есть проблема висячего else:
if условие
// ветка then
if условие
// ветка then
else
// к какому if относится этот else?
Проблему висячего else решают правилом, что он относится к последнему if. Однако с визуальной стороны проблема всё равно остаётся.

Если взять синтаксис Си, то моё предложение явно не хуже того, что есть в Си. По количеству скобок оно точно не проигрывает Си и точно выигрывает у Rust, где фигурные скобки обязательны. В Си мало того, что есть проблема висячего else, так в нём возможно вот такое:
if (условие);
операторы
или такое
while (условие);
{
операторы
}
Мой вариант лишён недостатков как Питона, так и Си. Да, в нём сеть лишняя скобка (перед if), но количество скобок, как правило, меньше чем в Си. А вот жалоб, что в Си слишком много скобок, я никогда не встречал. А какие могут быть претензии к скобкам в моём варианте, кроме того, что они существуют? Какие потенциальные неоднозначности может спровоцировать такой синтаксис?

     2021/03/27 21:42, Виталий Монастырский          # 

Простите, но Вы кажется, то ли не прочитали, то ли не поняли мой комментарий. При чем тут Питон? У Питона есть проблема висячего else, потому что её там никто не собирается исправлять. А в моем варианте этой проблемы нет АБСЧЕ. Посмотрите, пожалуйста, внимательно код — где там висячие else, которые не понятно к чему относятся???

     2021/03/27 22:00, Виталий Монастырский          # 

Жалобы на скобки как раз есть и множественные. Я лично тоже к ним спокойно отношусь, но есть многие, которые их не переваривают. Вы же сами ратуете за отсутствие в коде begin-end-ов, а {} это те же бигин-енды по умолчанию. А в Вашем случае это ещё и круглые скобки — что вообще беда, ведь это во-первых перегрузка операторов, а во-вторых кромешный скобочный ЛиспАд. Круглые скобки в блоках проверки, круглые скобки в формулах, круглые скобки в операторах присваивания перечислений, круглые скобки в структурах, круглые скобки... "наше все". Это же нарушение принципа читаемости кода, а так же принципа однозначности синтаксиса операторов.

Нет, уважаемый автор, в разумном языке программирования все должно быть разумно. В том числе и использование круглых скобок. "Шо занадто — то нэ здраво" говорят поляки. Так что если уж разрабатываем универсальный язык программирования, то давайте будем строго следовать всем его принципам. Никакой перегрузки операторов. Один оператор — одно использование. Все. Допустимы только смежные использования, которые не выходят за рамки концепции, иначе пострадает как не один, так другой принцип.

К тому же мое предложение ничем не хуже Вашего и даже лучше, ведь в нем даже скобок нет — никаких, ни круглых, ни квадратных, ни фигуристых. И никаких висячих else. По сути — это идеализированная и вылизанная форма Питоновского подхода без его недостатков. А вот Ваша форма — плохо читаемая, да и наличие в ней скобок я лично считаю просто излишеством — они там попросту не нужны.

Однако... я зашел сюда по-другому поводу. Дело в том, что я тут хорошо подумал, и за сегодняшний день решил, что нужно ещё оптимизировать мое предложение по операторам условного перехода. Теперь я их модифицировал и они стали ещё лучше, проще для компилятора и в тоже время — дают более широкие возможности программисту.
Вот все служебные операторы, которые нам нужны для организацию условных переходов абсолютно любой конфигурации:
if, sw, xor, and, or, else.
Все, их всего шесть, и из них только! 3 — новые, остальные — это логические операторы, которые уже есть в языке.
С помощью этого набора организовывается следующее подмножество условных переходов:
if — однострочное исполняемое ветвление
sw — однострочный исполняемый переключатель
or if else — многострочное прерываемое по true ветвление
xor if else — многострочное прерываемое по false ветвление
and if else — многострочное непрерываемое по true ветвление
or sw — многострочный прерываемый по true переключатель
xor sw — многострочный прерываемый по false переключатель
and sw — многострочный непрерываемый по true переключатель
Все. И писать можно в таком же стиле, как я изначально показывал. Запись получилась весьма компактной, а возможности ещё шире.

Ну для примера...

Это ветвитель:
а : 5
xor if a > 3
команды 1
else a > 4
команды 2
else а > 5
команды 3
else а > 6
команды 4

А это переключатель:
a, b, c, d : 3, 2, 3, 5
z : 3
and select z
a команда 1
b команда 2
c команда 3
d команда 4
else команда 5
Вот чем плохой вариант? И зачем к нему ещё и скобки лепить?

     2021/03/27 22:04, MihalNik          # 

Проблему висячего else решают правилом, что он относится к последнему if. Однако с визуальной стороны проблема всё равно остаётся.

А в чем это проблема? Если бы он относился не к последнему, то все промежуточные должны быть с отступом. Ведь Вы же не говорите о проблеме висячих закрывающих скобок. Так можно докопаться до любого блочного оператора.

     2021/03/27 22:04, Виталий Монастырский          # 

Ох, простите, я кажется незаметно для себя sw (от сокращенного switch) на select заменил. В принципе и тот и другой вариант неплох, хотя sw намного короче, нагляднее и лучше сочетается с if.

     2021/03/27 22:20, Виталий Монастырский          # 

Условный переход

В языке Cup принято условные переходы делятся на два вида: "ветвления" и "переключатели". Ветвления определяются оператором "if", а переключатели оператором "sw". Так же они делятся на два типа: множественные и одиночные.

Одиночные операторы не требуют дополнительных операторов для обозначения, содержат в одной строке условие и команду, которая выполняется по условию оператора условного перехода. Если команд несколько, они должны быть выделены в отдельный блок кода, на который в операторе условного перехода должна стоять команда выполнения этого блока "doit". Но в любом случае эта команда должна находится в одной строке с оператором условного перехода и она должна быть одна.

Множественные операторы требуют дополнительных операторов для указания типа множественного оператора. Так же они должны содержать не менее двух наборов команд, а значит иметь не менее двух выборов по условию. Множественные операторы условного перехода содержат в одной строке с собой только условие и не должны содержать команды. Команды, которые необходимо выполнить по данном условию, должны размещаться со следующей строки с отступом на 1 tab вправо от уровня оператора условного перехода.

Множественные операторы условного перехода могут иметь множество дополнительных проверок условий, который устанавливаются на одном уровне с основным оператором и обозначаются оператором "else". Так же все множественные операторы условного перехода могут иметь условие "по умолчанию", которое выполняется в том случае, если ни одно из предыдущих условий не сработало. Оно так же обозначается оператором "else", однако он идет в самом конце своего блока условного перехода и не имеет условия. Однако для него так же соблюдается правило отсутсвия команд в одной строке с ним. Даже если оператор по умолчанию нуждается всего в одной команде, она должна быть перенесена на следующую строку с отступом в 1 tab от уровня операторов условия.

Ветвление "if" используется для проверки сложных условий и может обрабатывать множество различных элементов в одном условии, используя логические операторы. Общая схема одиночного ветвления следующая:
if условие команда
Переключатель "sw" используется для проверки только простых условий, связанных с одним элементом. В нем вместо условия используется указание на тот элемент, относительно которого будет выполняться проверка значения. Если это единичный оператор, то после элемента проверки следует значение, с которым нужно сравнить значение данного элемента, а затем команда, которую необходимо выполнить, если значения совпали. Общая схема одиночного переключателя такова:
sw элемент значение команда
По сути это эквивалентно записи:
if элемент = значение команда
однако в виду особенностей оператора переключения знак "равно" не пишется, а подразумевается.

     2021/03/27 22:23, Виталий Монастырский          # 

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

1) Для обозначения непрерывного условного перехода, перед его основным оператором устанавливается логический оператор "and". Он обозначает, что в блоке этого условного перехода проверяются все условия и выполняются все блоки команд, которые идут за теми условиями, которые соответствуют Истине.

2) Для обозначения прерываемого условного перехода, с выбором по Истине, перед его основным оператором устанавливается логический оператор "or". Он обозначает, что в блоке этого условного перехода проверяются все условия подряд до тех пор, пока не будет встречено условие, которое соответствует Истине. После этого выполняется только тот блок команд, которые стоят после этого условия и осуществляется выход из данного блока проверки условия.

3) Для обозначения прерываемого условного перехода, с выбором по Лжи, перед его основным оператором устанавливается логический оператор "xor". Он обозначает, что в блоке этого условного перехода проверяются все условия подряд до тех пор, пока не будет встречено условие, которое соответствует Лжи. При этом выполняются все блоки команд, которые идут за теми условиями, которые соответствуют Истине. После нахождения ложного условия сразу осуществляется выход из данного блока проверки условия и тот блок команд, которые стоят после этого условия не выполняются.

Общая схема множественного ветвления следующая:
тип if условие 1
команды 1
команды 1
else условие 2
команды 2
команды 2
else условие 3
команды 3
команды 3
else (если все условия не верны)
команды по умолчанию
команды по умолчанию

     2021/03/27 22:26, Виталий Монастырский          # 

Давайте рассмотрим на примерах, как работают разные типы множественного ветвления. Для начала рассмотрим работу непрерывного оператора ветвления.
а : 5
and if a > 7
команды 1
else a > 3
команды 2
else а < 3
команды 3
else а < 7
команды 4
В этом случае программа выполнит команды группы 2 и группы 4.
Теперь рассмотрим работу прерываемого оператора ветвления с выбором по Истине.
а : 5
or if a > 7
команды 1
else a > 3
команды 2
else а < 3
команды 3
else а < 7
команды 4
В этом случае программа выполнит команды группы 2 и сразу выйдет из данного блока проверки условия.
Теперь рассмотрим работу прерываемого оператора ветвления с выбором по Ложному условию.
а : 5
xor if a > 3
команды 1
else a > 4
команды 2
else а > 5
команды 3
else а > 6
команды 4
В этом случае программа выполнит команды группы 1 и группы 2, а затем сразу выйдет из этого блока проверки условия, не выполняя команды из группы операторов 3.

     2021/03/27 22:32, Виталий Монастырский          # 

Теперь давайте рассмотрим вложенные множественные проверки условия. Разграничение отдельных веток проверки осуществляется отступами. Общая схема вложенных множественных проверок условия такова:
and if условие 1.1
команды 1.1
else условие 1.2
команды 1.2.1
or if условие 2.1
команды 2.1.1
or sw элемент 3.1
a команда 3.1.1
b команда 3.1.2
c команда 3.1.3
d команда 3.1.4
else команда 3.1.5 (ветка sw 3 если все значения не верны)
команды 2.1.2
else условие 2.2
команды 2.2.1
if условие 3.2 командa 3.2
команды 2.2.2
else (ветка 2 если все условия не верны)
команды
команды 1.2.2
else условие 1.3
команды 1.3
else (ветка 1 если все условия не верны)
команды 1.4
Если необходимо выполнить целый блок команд, который нужно вынести отдельно, то его нужно поместить внутрь именованного блока и выполнить через оператор безусловного перехода "doit". Выполняемый участок кода может находиться в любом месте программы.

Эта методика используется для того, чтобы явно отделить всю логику программы от оперативной рутины, вынося исполняемые участки кода в отдельные именованные блоки. Таким образом в начале программы мы сможем получить полное (для небольших программ) или базовое древо программы, которое позволяет более удобно охватить суть процессов, происходящих в программе. Пример:
x : 5
a, b, c : 1, 2, 3
or if x > 7
doit calc
else
doit hard
{ calc
a + 2
b + 7
c + 22
} calc
{ hard
z : ((a * (2 + b)) / ((a + 4) * b)) …
— ((((c * 8) + (b * 9)) / 24) + …
((a ** 4) + (a * b)))
} hard

     2021/04/01 14:07, Александр Коновалов aka Маздайщик          # 

Отзыв на отзывы Виталия.

По-моему, это похоже на необузданное фантазёрство на ровном месте. Мне не очевидны на практике случаи, когда нужны все эти три разновидности ветвлений (and, or, xor).

«and if» отличается от нескольких отдельных if’ов подряд только тем, что у него может быть ветка «else» без условия, которая выполнится, когда ни одно из условий не истинно. Применение мне не очевидно. Было бы интересно получить от Виталия пример алгоритма, где «and if» показывал преимущество перед традиционными управляющими конструкциями. Это может быть какой-нибудь классический алгоритм поиска, сортировки, работа с классической структурой данных вроде списка или дерева…

«or if» — это привычный нам if других языков программирования.

Применение «xor if» от меня ускользает. Аналогично, ждём примера.
А вот именованные блоки кода — вещь довольно интересная, в духе «литературного программирования» Кнута! Не просто в духе, а «литературное программирование» вообще на этом построено. Рекомендую ознакомиться.

Обычно говорят, что «подпрограмма — именованный блок кода», но тут это не подпрограммы. Это скорее макросы. Причём, в отличие от обычных макросов, они могут определяться после точки их использования, что иногда полезно для читабельности.

Однозначно одобряю!

     2022/07/21 15:26, zhus          # 

А не может pattern match по типу Скаловского полностью заменить if/else? Помнится, легко таким способом превращал многоэтажные и многовложенные if-ы в один матчер.

     2022/07/21 22:29, Автор сайта          # 

«match» — это «специализированный» условный оператор, у него единственный аргумент. В приведённом ниже примере — это «x»:
x match {
case 0 => "zero"
case 1 => "one"
case 2 => "two"
case _ => "many"
}
У «if» аргументов может быть больше («x», «y», «z»):
if (x > 0 && y < 0)
if (z == 0)
. . .
В этом плане он универсальнее. Думаю, одно другому не мешает.

     2022/07/25 13:54, zhus          # 

У match тоже может быть сколько угодно аргументов и даже не обязательно булевых.
val res = (x > 0, y < 0, z) match {
case (true, _, _) => "x>0"
case (true, true, _) => "x>0 && y<0"
case (_, _, 0) => "z == 0"
case _ => "other"
}
Такого плана конструкции мне оказались чрезвычайно полезны и при рефакторинге, и при дополнении логики программы. Неукладывающиеся в голове цепочки ифов сводятся к банальной комбинаторике. К тому же очень просто следить за ленивостью проверок. Всё мечтаю теперь, когда в джаву паттерн матчинг вкрутят.
Одно другому, действительно, не мешает, просто матчер, кмк, полностью перекрывает функционал if`а.

     2022/07/26 07:28, MihalNik          # 

А не может pattern match по типу Скаловского полностью заменить if/else?

Разумеется, сопоставление без if|else было ещё в дремучем Прологе.

     2022/07/27 00:49, Автор сайта          # 

Вы говорите

может быть сколько угодно аргументов

а res — таки единственный, хоть и является кортежем, содержащим 3 элемента. Если Ваш пример разложить на элементарные сравнения, чтобы стало ближе к машинному коду, то получится примерно так:
if (x > 0) {
ret = "x>0";
} else {
if (x > 0 && y < 0) {
ret = "x>0 && y<0";
} else {
if (z == 0) {
ret = "z == 0";
} else {
ret = "other";
} } }
Видно, что компилятору есть что оптимизировать. Хотя Ваш код позволяет меньше отвлекаться на детали, держа в голове более абстрактную картину. С этим не поспоришь.

     2022/07/29 12:25, zhus          # 

является кортежем, содержащим 3 элемента

Эдак можно постулировать, что любая функция принимает один и только один аргумент — кортеж параметров :))))

А ещё забавно, что ифы можно заменить оператором цикла:

if(a==b){print("a=b\n");}

эквивалентно

while(a==b){print("a=b\n");break;}

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

     2022/08/01 22:06, Автор сайта          # 

любая функция принимает один и только один аргумент — кортеж параметров

Можно даже конкретнее сказать — это массив. Налицо все признаки массива: все элементы занимают выделенный участок памяти целиком, без изъятий. И к этому массиву можно обращаться по индексу. Просто надо знать адрес его нулевого элемента.

все эти конструкции просто синтаксический сахар для ассемблерного jz

Согласен. Тем и подкупают языки высокого уровня — в них много сладостей. А в ассемблере — невкусный jz, грызть его неохота.

мы исключительно за выразительность текста на языках программирования

Эта выразительность зачастую бьёт по эффективности использования процессора. Взять те же «switch/match». В коде порядок рассмотрения возможных вариантов такой, какой удобен разработчику. Например, случаи выстроены в «естественном» для программиста порядке от «а» до «я». Так наглядно, это помогает ничего не упустить.

Но с точки зрения процессора в первую очередь надо рассмотреть наиболее частый вариант, во вторую — второй по частоте вариант и т. д. Это логично — выстраивание вариантов не в порядке от «а» до «я», а в порядке убывания вероятности уменьшает число условных переходов при исполнении кода и повышает производительность.

Компилятор же будет слепо следовать указаниям разработчика. Ведь он не владеет статистикой. Написано, что «а» в первую очередь, значит тому и быть. Было бы интересно каким-то образом «подсказать» компилятору, что порядок от «а» до «я» нужно оптимизировать перестановками вариантов в зависимости от их частоты. Но как организовать подсказку? Через опции компиляции невозможно. А давать указания компилятору в исходном коде — как-то не фонтан.

     2022/08/02 22:05, Неслучайный читатель          # 

«if» куда универсальнее, чем «switch». Последний обеспечивает проверку только на равенство. А как быть с неравенством, «больше» или «меньше»?
if (a > 4 && b < -1)		// напишите эквивалент, используя «switch»
А как сравнить переменную не с известным значением, а с неизвестным?
if (x == y)			// напишите эквивалент, используя «switch»
«if» легко сочетается с плавающими числами. А «switch»?
if (x > 0.5*Pi && x <= 1.5*Pi)	// напишите эквивалент, используя «switch»
Так что «switch» не может полностью заменить «if». Они дополняют друг друга.

     2022/08/03 13:35, zhus          # 

Можно даже конкретнее сказать — это массив

таки кортеж — в массиве же только однотипные элементы

А давать указания компилятору в исходном коде — как-то не фонтан.

явное лучше неявного, лучше уж в исходном коде. Во многих вариантах сложных матчеров я ставлю вперёд пусть редкую комбинацию, но требующую максимально оперативной реакции. Пусть аварийная ситуация происходит раз в год, но обработать её нужно с минимальной задержкой. Прям представляю, как компилятор, такой: "не, так не бывает" и убрал нафиг кусок кода :)))

«if» куда универсальнее, чем «switch»

Почему switch? Не switch, a match.
    val res = (x > 0.5*Math.PI, x <= 1.5*Math.PI) match {
case (true, true) => "это да"
case (true, _) => "почти :)"
case _ => "нет"
}
гораздо более удобно добавлять обработчики разных ситуаций.

В моём прошлом примере, кстати, косяк — первый кейз экранирует второй из-за более слабого условия, в матчере я это сразу увидел, но отправленное сообщение уже не исправить. А вот в ифах пойди разберись.

     2022/08/03 21:30, Автор сайта          # 

таки кортеж — в массиве же только однотипные элементы

Но это смотря с какой высоты рассматривать. С точки зрения языка высокого уровня — так оно и есть. Но если посмотреть в стек x86 (отладчиком, например), то все до единого параметры — это 32-битные ячейки. В одних — целые числа, в других — адреса. Но все одинаковой длины и вплотную друг к другу.

гораздо более удобно добавлять обработчики разных ситуаций.

В Вашем примере кортеж с «true/false» создаётся за пределами «match», это уменьшает удобство. Но тут всё индивидуально, кому-то это будет действительно удобнее.

Не switch, a match.

Особой разницы нет:
cond = (x > 0.5*Pi && x <= 1.5*Pi);
switch (cond) {
case true:
res = "это да"; break;
otherwise:
res = "таки нет";
}

В моём прошлом примере, кстати, косяк — первый кейз экранирует второй из-за более слабого условия

val res = (x > 0, y < 0, z) match {
case (true, true, _) => "x>0 && y<0"
case (true, _, _) => "x>0"
case (_, _, 0) => "z == 0"
case _ => "other"
}
Теперь правильно?

А вот в ифах пойди разберись.

Обычный условный оператор тоже неплохо смотрится (псевдокод):
res = "other"
(if x > 0
(if y < 0
res = "x>0 && y<0"
else
res = "x>0"))
(if z == 0
res = "z == 0")

     2022/08/04 10:56, zhus          # 

Сейчас только пришло в голову — иф и матч принципиально разные вещи, их нельзя обсуждать в одном контексте, они не взаимозаменяемы. Ибо. Иф — оператор, а Матч — выражение. Выражение можно использовать как оператор, а вот оператор как выражение неприменим. По мне так в эру функциональных языков операторы вообще не нужны, весь синтаксис можно (и нужно) построить на объявлениях и выражениях. => if'ы в топку :)
Интересно. Возьму-ка я в зубы Antlr и попробую... :)))

     2022/08/04 23:24, Неслучайный читатель          # 

Выражение
(x > 0.5*Pi && x <= 1.5*Pi)
выдаёт в качестве ответа флаг. Его куда-то сохраняют, чтобы потом ещё раз проверить на равенство. Неэффективно. Приведённый выше «match» только и делает, что опирается на сформированные вовне условия сравнения. Сам он может сравнивать только на равенство. Что я и писал выше. Да, «match», как и «switch», в каких-то моментах удобен.

     2022/08/04 23:55, Автор сайта          # 

Иф — оператор, а Матч — выражение. Выражение можно использовать как оператор, а вот оператор как выражение неприменим.

Это смотря в каком языке программирования. Кое-где можно примерно и так:
a = (if x < y
1
else
2)
Как тебе такое, Элон Маск?

     2022/08/05 15:51, zhus          # 

Обобщая. Матч — это функция с N+1 параметрами, где первый параметр — список из M предикатов, остальные параметры — лямбды (именованные блоки кода), выполняющиеся при соответствующей комбинации предикатов, а N — это число сочетаний из М по 2. Или по три? Лан. Тогда Иф — это тривиальный случай Матча — один предикат-условие и две лямбды: одна для true, другая для false. И всё, Иф как оператор, не нужен! :)) С операторами цикла ещё проще, так как break в цикле эквивалентен return в функции.

     2022/10/14 19:08, torgeek          # 

Пример на замену громоздкому условному оператору при совмещении с оператором выбора:
ключ правда {
a > b : оператор1;
a < b : оператор2;
_ : оператор по умолчанию
}
В простейшем вырожденном случае будет:
ключ правда a > b : оператор;
Можно и наоборот:
ключ a > b  {
правда : оператор1;
ложь : оператор2
}

     2022/10/15 11:24, Автор сайта          # 

Мысль, конечно, оригинальная. Однако такой условный оператор проигрывает в краткости синтаксису, который предложен выше. Сравните:
    (если a > b
оператор1
иначе если a < b
оператор2
иначе
оператор по умолчанию)
Это первый пример. А вот второй:
    (если a > b
оператор)
А вот третий:
    (если a > b
оператор1;
иначе
оператор2)
Такой способ записи компактнее, не содержит лишних сущностей («правда» и «ложь»), менее громоздок.

Добавить свой отзыв

Написать автору можно на электронную почту
mail(аt)compiler.su

Авторизация

Регистрация

Выслать пароль

Карта сайта


Содержание

Каким должен быть язык программирования?

Анализ и критика

●  Устарел ли текст как форма представления программы

●  Русский язык и программирование

●  Многоязыковое программирование

Синтаксис языков программирования

Синтаксический сахар

●  Некоторые «вкусности» Алгол-68

●  «Двухмерный» синтаксис Python

●  Почему языки с синтаксисом Си популярнее языков с синтаксисом Паскаля?

●  Должна ли программа быть удобочитаемой?

●  Стиль языка программирования

●  Тексто-графическое представление программы

●●  Разделители

●●  Строки программы

●●  Слева направо или справа налево?

●  Комментарии

●●  Длинные комментарии

●●  Короткие комментарии

●●  Комментарии автоматической генерации документации

●●  Нерабочий код

●●  Помеченные комментарии

●  Нужны ли беззнаковые целые?

●  Шестнадцатиричные и двоичные константы

●  Условные операторы

●  Переключатель

●  Циклы

●●  Продолжение цикла и выход из него

●  Некошерный «goto»

●  Изменение приоритетов операций

●  Операции присвоения и проверки на равенство. Возможно ли одинаковое обозначение?

●  Так ли нужны операции «&&», «||» и «^^»?

●  Постфиксные инкремент и декремент

●  Почему в PHP для конкатенации строк используется «.»?

●  Указатели и ссылки в C++

●●  О неправомерном доступе к памяти через указатели

●  Обработка ошибок

●  Функциональное программирование

●●  Нечистые действия в чистых функциях

●●  О чистоте и нечистоте функций и языков

●●  Макросы — это чистые функции, исполняемые во время компиляции

●●  Хаскелл, детище британских учёных

●●  Измеряем замедление при вызове функций высших порядков

●●  C vs Haskell: сравнение скорости на простом примере

●●  Уникальность имён функций: за и против

●●  Каррирование: для чего и как

●●  О тестах, доказывающих отсутствие ошибок

●  Надёжные программы из ненадёжных компонентов

●●  О многократном резервировании функций

●  Использование памяти

●  Почему динамическое распределение памяти — это плохо

●  Как обеспечить возврат функциями объектов переменной длины?

●●  Типы переменного размера (dynamically sized types, DST) в языке Rust

●●  Массивы переменной длины в C/C++

●●  Размещение объектов в стеке, традиционный подход

●●  Размещение объектов переменной длины с использованием множества стеков

●●  Размещение объектов переменной длины с использованием двух стеков

●●  Реализация двухстековой модели размещения данных

●●  Двухстековая модель: тесты на скорость

●●  Изменение длины объекта в стеке во время исполнения

●●  Размещение объектов переменной длины с использованием одного стека

●  Можно ли забыть о «куче», если объекты переменной длины хранить в стеке

●  Безопасность и размещение объектов переменной длины в стеке

●  Массивы, структуры, типы, классы переменной длины

●  О хранении данных в стеке, вместо заключения

●  Реализация параметрического полиморфизма

Описание языка

Компилятор

Отечественные разработки

Cтатьи на компьютерные темы

Компьютерный юмор

Новости и прочее




Последние отзывы

2024/03/19 02:19 ••• Ivan
Энтузиасты-разработчики компиляторов и их проекты

2024/03/18 23:25 ••• Автор сайта
Надёжные программы из ненадёжных компонентов

2024/03/18 22:44 ••• Автор сайта
О многократном резервировании функций

2024/03/17 17:18 ••• Городняя Лидия Васильевна
Раскрутка компилятора

2024/03/10 18:33 ••• Бурановский дедушка
Русской операционной системой должна стать ReactOS

2024/03/07 14:16 ••• Неслучайный читатель
«Двухмерный» синтаксис Python

2024/03/03 16:49 ••• Автор сайта
О неправомерном доступе к памяти через указатели

2024/02/28 18:59 ••• Вежливый Лис
Про лебедей, раков и щук

2024/02/24 18:10 ••• Бурановский дедушка
ЕС ЭВМ — это измена, трусость и обман?

2024/02/22 15:57 ••• Автор сайта
Русский язык и программирование

2024/02/19 17:58 ••• Сорок Сороков
О русском языке в программировании

2024/02/16 16:33 ••• Клихальт
Избранные компьютерные анекдоты

2024/02/10 22:40 ••• Автор сайта
Все языки эквивалентны. Но некоторые из них эквивалентнее других