[C++] оператор ',' - хорошо или плохо? [Re: C++ синтаксис]

gopnik1994

пиздец синтаксис!
это ж надо было такое уебище придумать! (я про С)

Zoulla

Ну и что такого? Напишешь это пару раз и вполне нормально воспринимается. К тому ж такой способ написания достаточно специфичен, никто не заставляет запятой пользоваться где не надо.

a10063

зря
запятая имеет удобное применение в специфических ситуациях, где очевиден приоритет (у нее самый низкий, кстати просто так ее не использует (нарушает читабельность)
а пример автора весьма надуман

gopnik1994

да это все фигня, что можно использовать, когда очень хочется.
проблема в том, что это во первых ВООБЩЕ НЕ ЧИТАБЕЛЬНО, и во вторых НЕ УСТОЙЧИВО К ОШИБКАМ - простая опечатка < на , и ищи ее потом дебагером...
Я за жесткий синтаксис, а не вольности типа
for(;P("\n"R-;P("|"for(e=C;e-;P("_"+(*u++/8)%2P("| "+(*u/4)%2);

Удобно? Да! Но так писать нельзя! Такие извраты имеют право на существование, только во всяких извратных языках-экспериментах (типа, а давай вот так извратнемся! но никак не в языках, которые предназначены для написания реального сложного софта. Человека, который будет писать такой код в комерческом продукте уволят очень быстро.
Вывод - подобная "гибкость" синтаксиса - только источник лишних ошибок и более ничего!

zzzzzzzzzzz

Зато очень наглядный оператор скалярного произведения можно определить

gopnik1994

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

a10063

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

psihodog

+1
Для практикума по программированию реально так прям и писал.

psihodog

опять же, удобно писать в for'е:
for (i=0; i<n; ++i, ++p) *p=s[i];
ну или чего-нть в этом роде...

gopnik1994

ну про указатели я вообще молчу
неиссякаемый источник багов и дыр!

bleyman

Ты не видишь ортогональности.
Введение запятой как оператора один раз позволяет избежать введения запятой как части другого оператора много раз.
Если бы запятая не была оператором, то синтаксис того же for стал бы абсолютно невменяемым. Конструкция вида for (int i = 0, j = zz; i < 10; i++, j++) {...} достаточно часто используется.
Если ты общаешься с С как шаман (зазубрив несколько частных случаев а не как техник, то тогда да, тогда некоторые проявления оператора "запятая" наверняка кажутся тебе дикими. Однако поверь мне, если _понять_ этот замечательный язык, то всё выглядит настолько же стройным и простым как линейная алгебра %)

maggi14

это офигенно удобная задумка. Если я хочу оформить какую-нить хрень навроде цикла или ?:-оператора, чтобы внутри вызывалось что-нибудь одно, а возвращалось другое.

Chupa

> Зато очень наглядный оператор скалярного произведения можно определить
несколько лет назад один чувак защитил дисер на технологии встраивания диалекта языка лисп в программы на C++
там перегрузка запятой использовалась для построения списков

Olyalyau

ну про указатели я вообще молчу
неиссякаемый источник багов и дыр!
Ты просто не умеешь их готовить
Пока не научишься, Васик программируй.
А как научишься, перегрузи все восемь глобальных new/delete для сборки мусора или шаблон-указатель забацай. Как сделаешь, сразу все memleak'и куда-то исчезнут. А когда коллекции перепишешь, в Лету канут срывы буфера.

gopnik1994

Введение запятой как оператора один раз позволяет избежать введения запятой как части другого оператора много раз.
Если бы запятая не была оператором, то синтаксис того же for стал бы абсолютно невменяемым. Конструкция вида for (int i = 0, j = zz; i < 10; i++, j++) {...} достаточно часто используется.
дык я как раз о том, что такие удобные с точки зрения программирования вещи сильно уменьшают читабельность кода.
Объясни мне, тупому, чем такой вариант написания плох?

j = zz;
for (int i = 0; i < 10; i++) {
...
j++
}

тем что длинее? За то тут я сразу вижу, не вчитаваясь, что есть цикл по i и параллельный инкремент с инициализацией по j, и не надо вчитываться в последовательность и символов , ; = < ++ и проч...
конструкция "for (int i = 0; i < 10; i++) {" сразу целиком без разбирания мозгом на составляющие ассоцируется с циклом и все. Не говоря уже о ОПЕЧАТКАХ типа
for (int i = 0; i < 10; j++) {

которые копилятор опять же молча съест...
Офигенно удобная конструкция for(...)! Можно с ней столько всего сделать! Можно даже ввод-вывод туда встроить! Только ЗАЧЕМ? Кому от этого легче жить станет?
писать короче удобнее, но ты же сам месяц спустя забудешь, для чего это все было, не говоря уже о человеке, котрый будет твой код читать с нуля...

gopnik1994

Хотя Си - это не самый изврат...
Вот мне тут по работе скоро придется APL заботать,
Так вообще жопа
Придумали его когда каждый байт был на счету, вот и получилось нечто вообще угробищное.
Не многим лучше машинных кодов. Пока все не просмотришь, вообще не поймешь, о чем там.
А между прочим очень удобный язык! Писать на нем одно удовольствие! И алгоритмы можно такие реализовывывать в пару строк (хотя, афаик, строго говоря строки для APL не имеют смысла - там матрица кода которые на всех других языках займут не одну сотню строк...
Офигенно короткие записи. Циклы, сортировки и прочая шелупонь - вообще языковые примитивы.
Только вот под все примитивы ASCII не хватило...

maggi14

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

gopnik1994

Ты просто не умеешь их готовить
Пока не научишься, Васик программируй.
А как научишься, перегрузи все восемь глобальных new/delete для сборки мусора или шаблон-указатель забацай. Как сделаешь, сразу все memleak'и куда-то исчезнут. А когда коллекции перепишешь, в Лету канут срывы буфера.
я тебе один очень умный вещь скажу, только ты не обижайся.
(с) Мимино
Какого черта я этим должен заниматься? Я и без них прекрасно живу. И даже не представляю, зачем я должне искать себе лишнего геморроя с искусственными проблемами ненужного языка. То что указатели, например, никому не нужны, показали например Java и тот же C# хотя и слизали все это с Smalltalk'а.
Кстати о последнем:. Несколько цитат на тему:
"Я придумал термин "объектно-ориентированный", и вот что я вам скажу, я не имел ввиду С++."
-- Алан Кей, OOPSLA '97
"Основная проблема в сообществе программистов на С++, это попытки использовать стандартный С++ либо как облагороженный С, либо как Smalltalk для бедных."
-- Бьярн Страуструп (создатель С++).
А пока я не вижу ни одного довода почему я должен переходить с более удобного языка на менее удобный. Только если на работу устраиваться и там это будет условие разве что... Но это не про меня.
И напоследок информация к размышлению:
Тут, конечно, присутствует экономический фактор что, для примера, разработчики на C++ по два за пени, а Eiffel и Smalltalk программисты далеко нет.
Это одно из наиболее сбивающих с толку неправильных применений статистики. Только то, что высока вероятность попасть в C++ программиста, кинув камень в толпу, не означает более высокую вероятность его способности заменить Вашего C++ программиста, нежели поиск подходящей замены для Eiffel или Smalltalk программиста. Оттого, что Вы вынуждены просеять толпы идиотов, которые заявляют, что они знают C++, усилия, необходимые для поиска настоящей замены могут быть значительно меньше в случае Eiffel и Smalltalk. Кроме того, если вы можете найти хорошего программиста, высок шанс, что он сможет в достаточной мере выучить любой язык программирования, который вы используете, за время поиска хорошего C++ программиста. И, в общем случае, обучение по исходным текстам предыдущего программиста намного проще, чем изучение языка с нуля.

gopnik1994

ну насчет воспринимания, могу согласиться - это дело привычки
А вот про правку не соглашусь... Найди различия в 2 строчках:
for (int i = 0, j = zz; i < 10; i++, j++) {...}
и
for (int i = 0, j = zz; k = yy, i < 10; i++, j++, k++) {...}
номальная опечатка при правке кода...

maggi14

злоупотреблять не надо естественно, не стоит доводить использование мелких приятных фич до абсурда

gopnik1994

фичи вредные

a10063

тем что длинее?
нет. все правильно написал.
Офигенно удобная конструкция for(...)! Можно с ней столько всего сделать! Можно даже ввод-вывод туда встроить! Только ЗАЧЕМ? Кому от этого легче жить станет?
могу добавить, что for разрабатывался как наиболее общий цикл (инит, логическое условие перехода, инкрементальное выражение т.е. из него можно сделать такой цикл, как душе угодно, иногда весьма элегантный, хотя всегда есть место извращениям, как ты успел заметить (хотя ввод-вывод не всегда является извращением).
то, что привычные тебе простые циклы по одной переменной записываются несколько сложнее, чем в других языках, это нормально (при желании ты можешь сделать простой цикл макросом, записав в удобной "привычной" форме)

gopnik1994

все так, но во вервых элегантный - не всегда есть понятный
а во вторых, если for наиболее универсальный, то где тут написать условие, которое будет проверяться после итерации, а не перед?
и нафига тогда нужен действительно универсальный while{} ?

evgen5555

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

bleyman

> все так, но во вервых элегантный - не всегда есть понятный
Ещё раз указываю тебе на очевидную (как мне кажется) вещь: "понятность" есть субъективная величина. Пока я не умел общаться с тернарным оператором, запись
if (a > b)
{
max = a;
}
else
{
max = b;
}
_казалась_ мне понятнее чем запись
max = (a > b) ? a : b;
Теперь я очень люблю тернарный оператор, и считаю вторую запись намного более понятной, чем первую. Потому что "понятность" - это субъективная величина.
Язык С отличается своим крайне логичным и простым синтаксисом, поэтому если изучать его не на чужих прогах (авторы которых тоже изучали С точно так же а внимательно прочитав референс (а то и какую-нибудь умную книжку (типа "Краткое справочное пособие по языку С для инженеров", 30 страниц то этот синтаксис легко запомнить и понять.
"Элегантность" означает что данная конструкция может стать совершенно понятной и ясной, если приложить некоторые усилия.
А вот на ВБСкрипте элегантно писать вообще невозможно, я пробовал.
Честно говоря, я не в состоянии оценить степень фимоза головного мозга у человека, выдвигающего претензии вида "на языке С можно написать совершенно непонятную программу". Ну да, а хуём можно изнасиловать младенца, например. Или замороженного молодого самца лосося.

rosali


Объясни мне, тупому, чем такой вариант написания плох?
code:--------------------------------------------------------------------------------
j = zz;
for (int i = 0; i < 10; i++) {
...
j++
}
Объясняю тупому Это другая программа. j++ не отработает при continue.

rosali

Нет, вы не подумайте, что мне нравится Сишная запятая. Мне было бы намного спокойнее, если бы через ',' обозначался встроенный tupling которого к моему удивлению в С(++) нет. А насчет "сделать одно, вернуть другое" так тут я принципиально ен согласен. Для того, чтобы что-то сделать существуют statements, а для того, чтобы что-то вернуть, существуют expressions, и зачем их смешивать неясно. Всякие ++ меня просто бесят, всегда дело заканчивается каким-нибудь
 
p[i] = q[i++];

поведение которого НЕ РЕГЛАМЕНТИРУЕТСЯ СТАНДАРТОМ! А потом удивляемся, на одном компиляторе работает, на другом нет, debug работает, release нет...

bleyman

Ну
Ты прав, наверное...
Хотя разделить expressions и statemens полноценно практически невозможно, потому что тогда нужно требовать константости всех функций (в смысле слова const).

gopnik1994

про coontinue я в курсе
нигде не указывалось, что "..." содержит continue

gopnik1994

ну оператор ?: я тоже люблю, потому что он удобен. Но старюсь без необходимости этого не делать.

Как-то давно был прикол: программисту предлагалось написать простейший алгоритм
если а равно 0, то присвоить ему 1 и наоборот.
Вот некотрые варианты в синтаксисе Си:
a = 1 - a;
a = a == 0 ? 1 : 0;
a = a ^ 1;
и т.д. и т.п. со всякими извратами, у кого на сколько фантазии хватает.
помню там было даже что-то типа:
printf("Current value of a is %d. Enter new value: ", a);
scanf("%d",a);
так вот самым правильным был признан вариант типа

if (a == 0)
a = 1;
else if (a == 1)
a = 0;
else
printf("Error! Wrong initial value of a!");



Честно говоря, я не в состоянии оценить степень фимоза головного мозга у человека, выдвигающего претензии вида "на языке С можно написать совершенно непонятную программу"
Это ты о ком? Лично я такого не говорил. Или у тебя сложности с пониманием смысла написанного?

bleyman

> так вот самым правильным был признан вариант типа
Я очень рад за тех, кто признал этот вариант "самым правильным". Они не рождены для программирования. Могу обосновать.
> Это ты о ком? Лично я такого не говорил. Или у тебя сложности с пониманием смысла написанного?
Цитата!
for(;P("\n"R-;P("|"for(e=C;e-;P("_"+(*u++/8)%2P("| "+(*u/4)%2);
Удобно? Да! Но так писать нельзя! Такие извраты имеют право на существование, только во всяких извратных языках-экспериментах (типа, а давай вот так извратнемся! но никак не в языках, которые предназначены для написания реального сложного софта. Человека, который будет писать такой код в комерческом продукте уволят очень быстро.
Вывод - подобная "гибкость" синтаксиса - только источник лишних ошибок и более ничего!
В данной цитате ты утверждаешь, что гибкость синтаксиса С позволяет написать такой код, и это плохо. Или тебя можно понять как-то по другому?

a10063

все так, но во вервых элегантный - не всегда есть понятный
а во вторых, если for наиболее универсальный, то где тут написать условие, которое будет проверяться после итерации, а не перед?
и нафига тогда нужен действительно универсальный while{} ?
не совсем ясно, что имеется в виду... есть только "между" итерациями
"перед" и "после" имеют смысл только для первой итерации, причем и "перед" и "после" у for заданы
while менее универсален, т.к. while (cond) === for (;cond т.е. есть подмножество вариантов для for и служит только для удобства записи, т.к. простой цикл типа while встречается часто

gopnik1994

В данной цитате ты утверждаешь, что гибкость синтаксиса С позволяет написать такой код, и это плохо. Или тебя можно понять как-то по другому?
Теперь ты правильно меня понял. Излишняя свобода синтаксиса - это полохо. А вот "непонятную программу" _можно_ написать на любом языке.

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

psihodog

при всей моей любви к циклу for, позволю себе не согласиться.
по твоему рассуждению цикл super_for вида
super_for (init; after_frist_iteration; before_last_iteration; condition; step) { ... }
будет более универсальным. Это не так.

gopnik1994

while менее универсален
да универсальнее while только goto!
for - это частный случай цикла, while - общий.
Просто в синтаксис while не входит инициализация и инкремент. Для удобства сделали сокращение for, но слишком увлеклись с его универсализацией.

psihodog

не слишком. как раз столько, сколько нужно.

gopnik1994

запятам точно лишняя
(вернусь к истокам )

a10063

before_last_iteration - это как? мы ведь не можем до итерации определить, последняя она или нет...
вообще, понятие универсальности также субъективно
написав "while менее универсален", я включил долю субъективизма, объективнее было бы "while не более универсален"
на мой взгляд, for отражает цикл (в некотором смысле) вполне, т.к. есть 3 (в опр. смысле) независимых параметра: инит, условие, инкремент
в super_for появляются "зависимые" с condition условия(?) after_frist_iteration; before_last_iteration

a10063

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

Olenenok

Я недавно использовал goto! Дело было так:
Можно было писать:
if (..)
{
if (...)
{ ... }
else
{ ... }
}
else
{ ...}

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

if (...)
{ ...
goto ThatsEnough;
}
if (...)
{ ...
goto ThatsEnough;
}
...
ThatsEnough:

И программа сразу стала читабельнее!

dimabel

ничуть....
Зато нижний вариант подаёт дурной пример. А сдвиг внутреннего ветвления на одну табуляцию не снижает читабельности.

Olenenok

Это тебе кажется что ничуть, а я лучше знаю, я смотрел на это.

Olyalyau

То что указатели, например, никому не нужны...
Ну-ка сейчас же прекращай пользоваться операционкой! Они все без указателей просто не пишутся!
Явой и До Диезом, тоже прекращай пользоваться -- сборку мусора без указателей не напишешь.
Про передачу по ссылке забудь -- она в языке реализуется через передачу указателя (просто ты этот указатель своими грязными лапками испортить не сможешь).
Про качественную оптимизацию забудь нафиг: если всё проверять на выход за границы диапазона,
программы будут работать так: H... e... l... l... o... ,... w... o... r... l... d... !... \n... ...............
Вобщем, оставь указатели людям, которые пишут серьёзные программы, и не пользуй языки, которыми
не владеешь. Программируй Васик.
А пока я не вижу ни одного довода почему я должен переходить с более удобного языка на менее удобный. Только если на работу устраиваться и там это будет условие разве что... Но это не про меня.
А кто уговаривал тебя писать на С или C++? Уж точно не я.
Было:
ну про указатели я вообще молчу
неиссякаемый источник багов и дыр!
Ты просто не умеешь их готовить
И ты действительно не умеешь их готовить, если для тебя это "неиссякаемый источник багов и дыр!"
PS.
Мне тоже C++ очень многим не нравится. Но, это практически единственный нормальный компилируемый объектно-ориентированный язык. Ява плоха тем, что все объекты наследует от одного класса; в результате в коллекцию можно запихать и слона и табуретку; и уж очень она смахивает на очередную реинкарнацию Васика. До Диез -- версия Явы от M$, не многим лучше.
Есть ещё язык D, многим он лучше С++, но с ним мне пока не довелось поработать.

sergei1969

До Диез -- версия Явы от M$
ну приехали...

bleyman

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

while (...)
{
while (...)
{
for(...)
{
if (...)
{
goto found:
}
}
}
}
throw new ItemNotFoundException;
found:
...

В каком-то языке вроде как были брейки с указанием вложенности, но это говно. Заводить булевскую переменную - это а) трата лишних ресурсов и времени (компайлер её никогда не уоптимизирует б) лишний код, то есть уменьшение читабельности.
Ещё goto бывает приятно использовать вместо ексепшена внутри функции, которая что-то вычисляет и проверяет долго и много.

bleyman

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

bleyman

> А ты пока обоснуй ради хохмы...

a ^= 1;

Если человек не способен с полувзгляда понять, что делает этот код, то он не рождён для программирования. Два ифа длиннее и непонятнее.
Задача о проверки допустимости значения не должна смешиваться с оригинальной задачей. Лучше всего её вообще куда-нибудь засунуть, ИМХО. Тем не менее я бы и её реализовал вот так:

assert(a & ~1); // must be 0 or 1.

Тем, кто постиг Дао, и понимает даже этот код с полувзгляда, комментарий не будет мозолить глаза. Всем остальным комментарий всё прояснит. С полувзгляда.
Обосновал?

dimabel

Достаточно при закрытии скобок писать коммантарии, что закрываем... Это можно считать признаком хорошего тона.

a10063

мне кажется, что во всех случаях, которые вы приводите в защиту goto, можно улучшить читабельность, запихнув такие сложные участки в функции с адекватным названием и использовать return

bleyman

Мне тоже C++ очень многим не нравится. Но, это практически единственный нормальный компилируемый объектно-ориентированный язык. Ява плоха тем, что все объекты наследует от одного класса; в результате в коллекцию можно запихать и слона и табуретку; и уж очень она смахивает на очередную реинкарнацию Васика. До Диез -- версия Явы от M$, не многим лучше.
Ну приехали. Во-первых, С++ не объектно-ориентированный. Отсутствие GC убивает метафору объекта как самостоятельной сущности, а то, что класс не является объектом, убивает метафору объекта как универсальной сущности. Конечно, это не сильно мешает писАть ОО код на плюсах, но и на чистом С это не слишком сложно на самом деле.
Во-вторых, ты, видимо, не знаешь ни жавы, ни шарпа, ни бейсика, а позволяешь себе нести чушь про то, что в них можно, а что нельзя.
Я уж не говорю о том, что отсутствие общего предка всех классов существенно половинит полиморфизм.

Olenenok

мне кажется, что во всех случаях, которые вы приводите в защиту goto, можно улучшить читабельность, запихнув такие сложные участки в функции с адекватным названием и использовать return
Можно, но у меня модуль и так распух, так что мне не хотелось писать функции-недомерки.

bleyman

С чего бы вдруг, интересно, повысится читабельность?
goto OsmyslennayaMetka исключительно читабельно само по себе.
А вот вынося код в функцию ты получаешь геморрой с передачей параметров, получением результата, в большинстве случаев у тебя получатся сильносвязанные функции ибо логически монолитный кусок кода разнесётся на две функции.
Вот, кстати, ещё один пример необходимости goto:

RetryDialog:
// Reset state so multiple load dialogs don't show
applicationState = ApplicationState.Startup;
System.Windows.Forms.DialogResult result = dlg.ShowDialog;
if( result == System.Windows.Forms.DialogResult.OK )
{
SimulatorOptions options = dlg.GetOptions;
prtMesh.LoadMesh( device, options.InputMesh );
SetRadii;
Simulator.Run( device, options, prtMesh );
applicationState = ApplicationState.SimulatorRunning;
}
else if (result == System.Windows.Forms.DialogResult.Retry)
{
goto RetryDialog;
}

Dasar

так чем плохо?
наглядность повышается, т.к. мы сразу видим, что есть попытка делать действие несколько раз

for (;;)
{
applicationState = ApplicationState.Startup;
System.Windows.Forms.DialogResult result = dlg.ShowDialog;
if (result == System.Windows.Forms.DialogResult.Retry)
continue;
SimulatorOptions options = dlg.GetOptions;
prtMesh.LoadMesh( device, options.InputMesh );
SetRadii;
Simulator.Run( device, options, prtMesh );
applicationState = ApplicationState.SimulatorRunning;
break;
}

зы
хорошие исходники - это такие исходники, которые можно читать с любого места в любом направлении.
goto - этой концепции мешает.

Olenenok

С чего бы вдруг, интересно, повысится читабельность?
goto OsmyslennayaMetka исключительно читабельно само по себе.
А вот вынося код в функцию ты получаешь геморрой с передачей параметров, получением результата, в большинстве случаев у тебя получатся сильносвязанные функции ибо логически монолитный кусок кода разнесётся на две функции.
В моём случае бы повысилась, лишь бы у функции было подходящее название. Но модуль бы ухудшился.
ЗЫ. На Паскале бы так написал:

procedure ReadDate (HeaderLine :string);
function ChooseDateType (HeaderLine :string, var ResponseHeader: SHttpResponseHeader): Integer;
begin
....
end
begin
...
case (ChooseDateType a) do
begin
a = 1 ...
a = 2 ...
....
end
end

Паскаль лучше!

a10063

+1
если goto вперед еще можно объяснить недостатком времени разрулить if-ы или из нелюбви к недофункциям, то goto назад обычно легко превращаются в циклы, которые очень хорошо подчеркивают логику кода

a10063

Паскаль лучше!

статическую функцию надо было сделать в модуле (если он на C)?

dimabel

Нафиг передавать к внутренней функции, если это будет фактически переменная внешней функции? Извращение, если только ты не собираешься строить рекурсию. Так внутренняя функция имеет доступ к параметрам и переменным внешней, если только они не подлежат вырезанию при оптимизации (уж параметры-то точно не вырезаются).
Паскаль лучше!
Не сомневаюсь... Да к тому-же.. При дефолтных настройках у меня простенькая прога, использующая 3-5 вызовов WinAPI функций, скомпиленная на Delphi 7 получилась где-то в полтора раза меньше, чем аналогичная прога, скомпиленная на MS Visual Studio 6.0

bleyman

Пащитаим строчки нах!
RetryDialog:
вместо
for (;;)
(я бы, кстати, использовал while(1 но это неважно)
В моём случае нахаляву получаем описание того, зачем мы сюда прыгаем. Кстати, выполнение много раз, в данном контексте, это как бы Исключительная Ситуация, типа ненормальная. На мой вкус.
Опять же вместо безликого continue получаем явное описание того, зачем мы прыгаем.
У тебя есть дополнительный брейк в конце, абсолютно нелогичный и неуместный и неизящный и некрасивый. Мы хотим в случае неудачи повторить попытку, а вовсе не повторять
попытку, иногда прекращая процесс. Кстати, ты хотел написать

for (;;){
applicationState = ApplicationState.Startup;
System.Windows.Forms.DialogResult result = dlg.ShowDialog;
if (result != System.Windows.Forms.DialogResult.Retry)
break;
...

Не правда ли? Но изначально порочная идея заменять прыжок циклом тебе помешала.
Читать исходники с любого места - это маза, конечно. Другое дело, что твой цикл вовсе не очевиден, поэтому понять, что именно ты в нём делаешь, можно только воткнув в его начало, а потом хотя бы в один "прыжок", а вот лабель+гото сами себя документируют. Если придерживаться определённого стиля, конечно же.
Вообще удивительно, как нападки Вирта на привычку неграмотных бейсик-программеров залезли в мозг к большинству остальных.
Нет, я не спорю, конечно можно обойтись вообще без goto. Но код получится хуже.

dimabel

Не согласен с тем, что код хуже. И число строчек само по себе ничего не значит.
Впрочем, я не согласен и с предложенным кодом в качестве контраргумента. По моему, для таких вещей лучше использовать конструкцию вида (как я понял, то, что делать: выход или повторение цикла - решается в конце данного блока):
do {
....
} while (...);

Часто приходится делать что-то типа: делаем действие1, если всё_ок, продолжаем программу, иначе делаем _откат и спрашиваем_что-то у юзера, при ответе ок - продолжаем программу, иначе - опять переходим к попытке выполнения действия1 и т.д., до посинения. Замечу, что _до_посинения_ тут - ключевое слово.
Имхо, следующая конструкция вполне читабельна в таком случае:
do{
действие1;
if(всё_ок) break;//усё ок, иначе - откат
_откат;
} while(!спрашиваем_что-то.ok_state);

a10063

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

do
{
applicationState = ApplicationState.Startup;
System.Windows.Forms.DialogResult result = dlg.ShowDialog;
}
while (result == System.Windows.Forms.DialogResult.Retry);
SimulatorOptions options = dlg.GetOptions;
prtMesh.LoadMesh( device, options.InputMesh );
SetRadii;
Simulator.Run( device, options, prtMesh );
applicationState = ApplicationState.SimulatorRunning;

имхо, здесь лучше показано, где же зарыт цикл

a10063

во! независимо сошлись в идее!

dimabel

Да... Кстати, еще одна демонстрация того, что двумя основными типами циклов являются цикл с предусловием и цикл с послеусловием.
Замещение одного цикла на другой в рамках одного типа мало чего изменит (кроме некоторых исключительных случаев однако замещение одного типа цикла на другой может заметно понизить читабельность.
И, не смотря на это, к сожалению, часто некоторые программисты забывают о существовании do {} while; и пользуются почти исключительно циклом с предусловием... Даже в какой-то книжке по С++ видел утверждение, что этот цикл редко используется... Хотя достаточно часто конструкция с этим циклом выглядит более изящно.
(В Паскале, так вообще - писать repeat ...until удобнее, так как не нужно begin ... end вписывать внутри).

rosali

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

rosali

про coontinue я в курсе
нигде не указывалось, что "..." содержит continue
lol? Основная беда даже не в том, что "..." возможно содержит continiue, а в том что он его возможно будет содержать через год.

dimabel

Был только один единственный раз, когда я вынужден был его использовать.
Но процедура, в которой он был представляла из себя жуткую смесь ассемблерных вставок и обычного кода (ну не хотел компилятор компилить часто вызываемый кусок так, как мне хотелось)... Так что особой читабельности у той части кода небыло. Правда, этот недостаток был сглажен обильными комментами.

garikus

'Я заметил некоторую культурную тенденцию, которая, по всей вероятности, своими корнями уходит в эпоху Возрождения. Она состоит в том, чтобы не замечать этого влияния, считать человеческий ум высшим и независимым хозяином всего, что он порождает. Но если я начинаю анализировать свои собственные мыслительные привычки, а также и привычки своих коллег, то независимо от своей воли прихожу совсем к другому выводу, а именно, что инструменты, которые мы пытаемся использовать, а также язык или обозначения, применяемые нами для выражения или записи наших мыслей, являются главными факторами, определяющими нашу способность хоть что-то думать или выражать!'
Из речи Эдгара Дейкстры при вручении ему премии Алана Тьюринга. Бостон, США, 14 августа 1972 г.

Dasha30

дык я как раз о том, что такие удобные с точки зрения программирования вещи сильно уменьшают читабельность кода.
Объясни мне, тупому, чем такой вариант написания плох?
Задача: объяснить, почему цикл
for (i = 0; i < 5; ++i)
{ ... }
нельзя прямолинейно (т.е. сохранив текст, представленный многоточием) переписать в виде
i = 0;
while (i < 5)
{ ... ++i; }

Dasar

зато можно переписать так:

i = 0;
while (i < 5)
{
Incrementer inc(i);
...
}

bleyman

и он полностью сдохнет на вложенном цикле. И на следующем цикле.

Dasar

В честь чего это?

bleyman

а.
подумал.
Да, не сдохнет наверное.
О чём это мы?

bleyman

А ты уверен, что вызов деструктора жёстко зафиксирован на закрытии scope, кстати?

Olyalyau

Отсутствие GC убивает метафору объекта как самостоятельной сущности
GC тривиально реализуется через умные указатели, перегрузку компании new/delete, или определение пользовательских аллокаторов.
Во всех известных мне ОО-языках с Garbage Collection, она реализована непредсказуемой:
вы не знаете когда активируется GC и когда ваша программа начнёт подтормаживать в связи с этим.
С++ позволяет написать предсказуемый GC или не пользоваться GC совсем, или даже не пользоваться
динамической аллокацией совсем. В этом плане на С++ можно писать программы так, как вам нужно.
Java, C# или D из-за непредсказуемости GC не позволяют писать приложения реального времени, где
на каждую операцию должна быть гарантия работы не более определённого времени. В такой ситуации
непредсказуемые алгоритмы (например qsort или непредсказуемый GC) использовать нельзя.
Ещё раз -- C++ позволяет иметь GC, если он вам нужен и не иметь GC, если он вам мешает. Позволяет написать GC удовлетворяющий нужным вам требованиям, позволяет получить полный контроль над выделением памяти.

Dasar

> Ещё раз -- C++ позволяет иметь GC, если он вам нужен и не иметь GC, если он вам мешает. Позволяет написать GC удовлетворяющий нужным вам требованиям, позволяет получить полный контроль над выделением памяти.
порочная система утверждений.
маш. код позволяет строить красивые и оптимальные полиморфные программы, а C - нет, значит ли это, что надо программы писать на маш.код, а не на C?

Dasar

> Позволяет написать GC удовлетворяющий нужным вам требованиям, позволяет получить полный контроль над выделением памяти.
теоретическая возможность что-либо сделать - совсем не означает, что это можно сделать практически

Olyalyau

Я уж не говорю о том, что отсутствие общего предка всех классов существенно половинит полиморфизм.
Ещё раз, С++ не налагает на вас никаких ограничений, так как если вам нужен общий предок всех
классов, вы можете совершенно спокойно его завести.
По поводу Java, C# и Васика: на Васиках я писал. Васики были разные. Потом перешёл на Паскаль, по тому как тот был лучше. Аналогично, перешёл на C и С++ (ОО программы писал ещё на Паскале они мне больше понравились.
В C++ есть много вещей, которые мне не нравятся. По этому я интересовался и Явой и До Диезом.
Оба не понравились мне больше, чем C++. Сейчас наткнулся на D. Он больше мне подходит, чем Ява и До Диез, так что сейчас изучаю его.

Olyalyau

теоретическая возможность что-либо сделать - совсем не означает, что это можно сделать практически
Это легко сделать практически. Не говоря уж о том, что и делать скорее всего не придётся -- всё, обычно, уже украдено до нас.

Dasar

Есть, примеры, крупных успешных проектов на C++, в которых реализован GC?

Olyalyau

порочная система утверждений маш. код позволяет строить красивые и оптимальные полиморфные программы, а C - нет, значит ли это, что надо программы писать на маш.код, а не на C?
Машинный код как раз не позволяет писать "красивые" программы. Оптимальные и полиморфные -- да.
Но. Хорошие программы на машинном коде или ассемблере требуют огромного времени на написание,
C++ позволяет писать гораздо быстрее. При этом, не на всех других языках высокого уровня можно написать всё, что угодно. С моей точки зрения, языки делятся по степени своей выразимости на
1) языки на которых можно написать OS
2) языки, на которых можно написать сам язык (включая библиотеки но нельзя написать OS
3) все прочие языки
Например, Java относится к третьей группе.

korsar0156

В C++ легко сделать GC на счётчиках ссылок, но не более.
А для нормальной работв GC счётчика ссылок разумеется не достаточно.

Dasar

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

korsar0156

C++ позволяет писать гораздо быстрее
После того как ты что-то напишешь тебе это нужно ещё отладить и оттестировать
и вот тут то у C++ появляются болшии проблемы чем у тех же Java/C#

Olyalyau

Есть, примеры, крупных успешных проектов на C++, в которых реализован GC?
Ява написана на C/C++. Там есть GC. Успешность этого проекта спорна
А если серьёзно:
John R. Ellis & David L. Detlefs, Safe, Efficient Garbage Collection for C++, Usenix Proceedings, February, 1994,
www.boost.org и Boehm-Demers-Weiser conservative garbage collector for C/C++.
Дополнительные ссылки можно найти здесь.

Olyalyau

В C++ легко сделать GC на счётчиках ссылок, но не более.
А для нормальной работв GC счётчика ссылок разумеется не достаточно.
Не только, можно и через двойные указатели (как в Яве и D). Тормозить, разумеется, будет сильнее, чем через подсчёт ссылок.

Olyalyau

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

Dasar

> Ява написана на C/C++. Там есть GC. Успешность этого проекта спорна
демагогия. т.к. в самом C++ - GC не используется.
> А если серьёзно:
ссылок на конкретные крупные проекты, которые используют GC в C++ - там так и нет.

Dasar

> Неправда ваша. На языке без указателей невозможно написать свой менеджер памяти. Придётся пользоваться встроенным.
гон.
память - это всего лишь массив.
работать с массивами можно в любом алго-языке.

Dasar

> А ты уверен, что вызов деструктора жёстко зафиксирован на закрытии scope, кстати?
да, потому что сам страуструп - продвигает парадигму: захват ресурса, через объявление класса.

Olyalyau

гон.
память - это всего лишь массив.
работать с массивами можно в любом алго-языке.
Расскажи, как ты в Яве создашь объект в памяти, занятой массивом char'ов. Ещё более интересно, как ты сделаешь для него GC (заюзаешь стандартный Явовский или напишешь свой).
А иметь на каждый тип отдельный массив -- это сильно. Но комментс.

Dasar

перепишу компилятор Java-ы на java-е так, чтобы GC - был чуть другой.

Dasar

Расскажи, как ты в Яве создашь объект в памяти, занятой массивом char'ов.
Какое это отношение имеет к
2) языки, на которых можно написать сам язык (включая библиотеки но нельзя написать OS

bleyman

> GC тривиально реализуется через умные указатели, перегрузку компании new/delete, или определение пользовательских аллокаторов.
Эх. На макроассемблере тоже можно написать сборщик мусора, умные указатели, наследование с полиморфизмом етс. Макроассемблер это вообще страшная штука! Единственная проблема состоит в том, что на этапе компиляции не будут отслеживаться ошибки. Точно так же любой сборщик мусора в Языке Высокого Уровня Си Плюс Плюс пойдёт лесом после первого же нуля, записанного в левое место. GC, пойнтеры вместо ссылок и проверка границ массивов на уровне языка означает что для того, чтобы уронить прогу, нужно приложить специальные усилия, например, написать ключевое слово unsafe, или заняться Platform Invoke - но когда ты это делаешь, ты понимаешь, что нужно повысить внимательность, а во всех остальных случаях тебе не даёт накосячить компилятор. Аналогичные фишки на уровне библиотек означают что тебе нужно прилагать постоянные усилия, чтобы не ошибиться.
Понимаешь логику? В С++ есть GC точно так же, как и в ассемблере.
А вот то, что класс не является объектом, задолбаешься исправлять ручками.

bleyman

--------------------------------------------------------------------------------
C++ позволяет писать гораздо быстрее
--------------------------------------------------------------------------------
После того как ты что-то напишешь тебе это нужно ещё отладить и оттестировать
и вот тут то у C++ появляются болшии проблемы чем у тех же Java/C#
===
Тут чувак С++ сравнивает с ассемблером, и не вполне прав, кстати: макроассемблер - страшная вещь. А вот на шарпе ещё быстрее писать, между прочим.

bastii

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

Dasar

паттерн flyweight не помогает?

bastii

не знаю такой я пока финальные методы делаю, которые инкапсулируют упаковку данных в массивах, надеюсь будут инлайниться

bastii

flyweight не то, мне нужны два массива структур

gopnik1994

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

Dasar

так делаешь массив byte-ов, а поверх него делаешь FlyWeight.

bastii

хм, не всегда есть выбор, и потом такие проблемы возникают в очень маленьком фрагменте кода если сравнивать со всем объемом кода

gopnik1994

если не критична кроссплатформенность, то реализуй в виде dll на тех же сях.

bastii

Как такое переделать без структур
  
struct Var {
int rep;
int next;
}
struct Repx {
int size;
int rep;
...
}

есть два массива

Var[] vars;
Repx[] repxs;

связь между ними такая

int rep(int var) { return vars[var].rep < 0 ? var : vars[var].rep; }
int repx(int rep) { return -vars[rep].rep; }

Без структур приходиться заводить два массива интов и т.д. Проблема если типы в полях не только инты, пока получается это избегать.
Как тут flyweight поможет? Т.е в случае если нужен массив структуры с поле инт и полем стринг?

bastii

если не критична кроссплатформенность, то реализуй в виде dll на тех же сях.
JNI предлагаешь? ИМХО состыковка с нативным кодом слишком дорогая. Да и гемора больше, чем с массивами.

Dasar

объектный FlyWeight:

class Data
{
public int[] var;
public int[] rep;
}
class Var //Rep аналогично
{
public Var(Data data, int index)
{
this.index = index;
this.data = data;
}
Data data;
int index;
public rep {get {return data.var[2*index];}}
public next {get {return data.var[2*index+1];}}
}


int rep(int index)
{
Var var = new Var(data, index);
return var.rep < 0 ? index : var.rep;
}

функциональный FlyWeight:

public var_rep(Data data, int index)
{
return data.var[2*index+1];
}
int rep(int index)
{
int _rep = var_rep(data, index);
return _rep < 0 ? index : _rep;
}

Соответственно на этапе написания кода - удобнее работать с объектным FlyWeight-ом.
Далее во время процесса оптимизации, проверяется - стоит ли для объектного FlyWeight-а выполнить ручной inline-инг или нет.

bastii

Объектный вариант не катит, т.к. в первую очередь необходимо избежать промежуточных аллокаций. Функциональный -- это как раз то, что я и делаю.

abstract class VariableBinding {
public int allVars;
public int bindVars;// bindVars <= allVars
int classes; // next after last in reps
int[] binding; // +0 - representative, +1 - next in the class,
int[] reps; // +0 - class size, +1 - representative, +2 - use list sp1, +3 - use list sp2
int[] useLists; // +0 - a, +1 - a, +2 - c ( *(a,b)=c +3 - next1, +4 - next2
public final int rep(int i) {
int r = binding[2 * i];
return r < 0 ? i : r;
}
public final int repx(int i) {
int r = binding[2 * i];
return r < 0 ? -r : -binding[2 * r];
}
public final int repxFromRep(int r) {
return -binding[2 * r];
}
public final int classSize(int i) {
return reps[4 * repx(i)];
}
public final int classSizeFromRepx(int i) {
return reps[4 * i];
}
public final int repFromRepx(int i) {
return reps[1 + 4 * i];
}
public final int next(int i) {
return binding[1 + 2 * i];
}
public final int useList1(int i) {
return reps[2 + 4 * repx(i)];
}
public final int useList2(int i) {
return reps[3 + 4 * repx(i)];
}
}
Оставить комментарий
Имя или ник:
Комментарий: