2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




На страницу 1, 2, 3  След.
 
 Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение09.02.2014, 22:51 
Аватара пользователя
Привет! У меня элементарный вопрос по языку C, словами задачу можно описать так: "Есть 2 несовместных условия (X и Y) и три блока команд (A, B, C), нужно выполнить A в обоих случаях, а также B в первом и C во втором. Порядок выполнения не важен".

Как я хочу заставить действовать программу
Проверить X и Y
Если верно X, то выполнить A и B
Если верно Y, то выполнить A и C

Код, один из вариантов:
Используется синтаксис C
if(X || Y) {A; if(X) B; else C;}
 
Однако мне не нравится, что условие X проверяется 2 раза вместо одного. Недостаточно красиво, ну и вроде как лишняя работа.
Я захотел это исправить! Но смог, используя только инструкции GOTO. Как это сделать без них? И возможно ли?

Сразу замечу, что мой вопрос именно по синтаксису языка, а не по оптимизации, которой тут и не пахнет.

Вариант с GOTO. Он описывает в полной мере то, как я хочу видеть работу программы, однако ну это же GOTO :evil:
Используется синтаксис C
if(X) goto labelX; else if(Y) goto labelY
...
labelX: B; goto label;
labelY: C; goto label;
label: A;
 
По сути, я хочу избавиться от GOTO в этом коде, сохранив его лаконичность (нигде ничего не написано по 2 раза).

Какие варианты не принимаются:
Используется синтаксис C
if(X) B; else if(Y) C;
A;
 
Потому что кроме X и Y могут быть и другие возможности, при которых не должно выполняться A. Код должен быть полностью контекстно-свободным.
Используется синтаксис C
if(X) {A; B;} else if(Y) {A; C;}
 
Потому что код A повторён 2 раза.

А также варианты с флагами! И прочие навороты. Моя цель - упростить самый первый отрывок кода, а не усложнить.

Возможно, ключ кроется в switch-case? Тем более, что C позволяет не писать break там, где не надо. У меня не получилось.

В общем, я в догадках. Неужели нельзя обойтись без GOTO?

P.S. Для того, чтобы придать задаче хоть какую-то мнимую практическую ценность, предлагаю положить, что A, B, C - большие куски кода, которые тем не менее нельзя засунуть в функцию (много локальных переменных и вообще непрактично). А условия X и Y очень долго вычисляются. И закэшировать значения X и Y мы не можем тоже. Такая вот сферическая программа в вакууме.

 
 
 
 Re: Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение09.02.2014, 22:59 
Можно тупо - завести булевы переменные, вычислить долгие условия заранее, и далее обращаться только к этим переменным, можно третью завести, куда положить их |. Но при неотключенной оптимизации компилятор имхо сам это сделает.

 
 
 
 Re: Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение09.02.2014, 23:02 
Аватара пользователя
Legioner93 в сообщении #824681 писал(а):
Привет! У меня элементарный вопрос по языку C, словами задачу можно описать так: "Есть 2 несовместных условия (X и Y) и три блока команд (A, B, C), нужно выполнить A в обоих случаях, а также B в первом и C во втором. Порядок выполнения не важен".
Используется синтаксис C
A; (X) ? B : C;
 


 
 
 
 Re: Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение09.02.2014, 23:13 
А я бы все-таки предложил вариант с флагом. По сути то же самое, что Ваши goto, но выглядит по-человечески:
код: [ скачать ] [ спрятать ]
Используется синтаксис C
#include <stdbool.h>

// ...

bool flag = false;

if (X)
{
    B;
    flag = true;
}
else
{
    if (Y)
    {
        C;
        flag = true;
    }
}
if (flag)
{
    A;
}

 
 
 
 Re: Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение09.02.2014, 23:23 
Аватара пользователя
Первый вариант, по-моему, читается гораздо приятнее варианта с goto, а переходы копилятор соптимизирует.

Кстати, эти варианты не равносильны в общем случае, так как A и B/C меняются местами. Но у Вас, видимо, по условию блоки независимы. В таком случае не очень понимаю, почему их нельзя засунуть в функции.

Legioner93 в сообщении #824681 писал(а):
И закэшировать значения X и Y мы не можем тоже.
Так не бывает. bool X_value = X; if (X_value) ... else ...

 
 
 
 Re: Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение09.02.2014, 23:37 
А почему бы не отделить логику управления от всех этих X, Y, A, B, C и не вызывать функцию_или_макрос_с_именем_получше(X, Y, A, B, C)? Тогда управляющий код не повторяется, и один раз проверить можно, даже если внутри он не совсем нравится кому-нибудь.

Это предложение, конечно, параллельно вопросу темы, но… :roll:

zvm в сообщении #824686 писал(а):
Используется синтаксис C
A; (X) ? B : C;
У вас семантика не та. Несовместность условий X и Y ничего не говорит об обязательной истинности какого-нибудь, и A потому не должен выполняться безусловно.

 
 
 
 Re: Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение10.02.2014, 00:18 
Аватара пользователя
_Ivana
Булевые переменные не вариант. Те же флаги, я их упомянул.
Я просто нутром чувствую, что должна быть какая-то красивая конструкция. Недавно, например, узнал о тернарном операторе и сразу же в него влюбился, также порой очень изящны конструкции switch-case, а инструкции break и (особенно) continue стали моими лучшими друзьями.
Последний шаг до полного дзена (прогр. говнокод) - это, как я
понимаю, GOTO :D
zvm
Вы уловили мою мысль, именно что-нибудь такое минималистично-эстетичное я и хочу написать. Но, как уже заметил arseniiv, в коде ошибка.
EtCetera
С флагами и прочими финтифлюшками легко, а вы попробуйте без них
Xaositect
Я знаю что поменял местами куски. И в условии даже специальную оговорку добавил. Мол, порядок A и B/C не важен. Это от бессилия. Я был очень озадачен, что в моём любимом языке нельзя сделать красиво такую простую вещь. Или самоповторения, или флаги, или goto, или...
И сделал вот такое вот послабление сам себе. А без него у меня даже с goto что-то совсем уродское вышло, стыдно показывать.
Насчёт кэширования - несомненно можем. И даже, наверное, без лишней переменной - какой-нибудь умный компилятор догадается запомнить значение X и Y и не вычислять их снова. А без кэша как?
arseniiv
Про макросы утром прочитаю, не дошёл пока до них в Кернигане.

 
 
 
 Re: Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение10.02.2014, 00:22 
Аватара пользователя
arseniiv в сообщении #824703 писал(а):
У вас семантика не та.
Виноват. Лажанулся.

 
 
 
 Re: Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение10.02.2014, 00:27 
Хорошо, зайдем с другой стороны.
Legioner93 в сообщении #824718 писал(а):
Я был очень озадачен, что в моём любимом языке нельзя сделать красиво такую простую вещь.
Приведите пример на другом, нелюбимом вами языке, в котором эта простая вещь делается красиво. Чтобы было видно, что вы хотите. Я, например, могу на ассемблере написать, без гоуту, без рджампов, красиво и стройно (с моей точки зрения), с рколлами (если нужны функции). А вы, в свою очередь, можете посмотреть ассемблерный листинг вашего кода, как компилятор расписал и соптимизировал инструкции. Просто в конечном итоге все равно все сведется к ассемблеру, об этом не надо забывать. А вот что вы хотите - визуальную красоту кода на языке высокого уровня или его оптимальность, вы и скажите.

 
 
 
 Re: Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение10.02.2014, 00:45 
Аватара пользователя
Вообще, конечно, в C можно использовать конструкцию do while false
Код:
do {
  if (X) B;
  else if (Y) C;
  else break;
  A;
} while(0);
Но это кривее всех вариантов ТС, по-моему. Лучше честный goto, чем стыдиться и прятать его вот так

-- Пн фев 10, 2014 01:47:48 --

_Ivana в сообщении #824721 писал(а):
Приведите пример на другом, нелюбимом вами языке, в котором эта простая вещь делается красиво.
Поддерживаю вопрос. Чего Вам хочется? А то булевы переменные - они для того и существуют, чтобы в них хранить значения для ветвлений, почему они Вам не нравятся, я не понимаю.

 
 
 
 Re: Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение10.02.2014, 01:48 
Аватара пользователя
Вот конструкция:
if( x?B():( y?C(): false))
{ A(); }

Пример реализации:
Код:
#include <stdio.h>
enum bool {
    false, true
};

int A(){
   printf( "A" );
   return 1;
}
int B(){
   printf( "B" );
   return 2;
}
int C(){
   printf( "C" );
   return 3;
}

int  main(){
int x,y;
x = true;
y = false;

if( x?B():( y?C(): false))
{ A(); }
return 0;
}

Только не знаю, подходит ли она для ТС.

 
 
 
 Re: Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение10.02.2014, 02:14 

(Оффтоп)

NT2000 в сообщении #824740 писал(а):
Вот конструкция:
if( x?B():( y?C(): false))
{ A(); }

О боже :facepalm: Не дай бог увидеть в какой-нибудь библиотеке такое. Проще понять 2 раза условие.

 
 
 
 Re: Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение10.02.2014, 02:36 
Аватара пользователя
Эстетам:
Код:
if( x ) B();
else if( y ) C();
else return 0;
A();
return 0;

 
 
 
 Re: Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение10.02.2014, 05:02 
Хм. Мне ваш первый вариант понравился больше. Надо только проследить, чтоб B/C не вернули ненароком нуль.

 
 
 
 Re: Как обойтись без GOTO, но максимально красиво соблюсти D.R.Y
Сообщение10.02.2014, 09:42 
Аватара пользователя
Мне милее всего 4-й вариант, максимально приближённый к текстовому описанию. Почему я легко дублирую большой кусок кода A? Мой опыт подсказывает, что:
1) Если A будет меняться, то это хороший повод для рефакторинга, который всё равно понадобится.
2) Далеко не факт, что A будет меняться синхронно в обеих ветках.
Зато соответствие между требованиями и кодом более полное, что для меня ценнее абстрактного DRY.

На втором месте — 1-й вариант.

 
 
 [ Сообщений: 40 ]  На страницу 1, 2, 3  След.


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group