Тут перевод TADS-мануала неожиданно натолкнул меня на мысль: что может заставить современнх программистов использовать оператор безусловного перехода a.k.a. goto? Речь, естественно, идет не о программировании на Ассемблере, Fortran 66 и т. п., а о более-менее структурированных языках, позволяющих теоретически вообще без него обойтись. Обращаюсь к программистам среди наших форумчан (их, к счастью, есть у нас:): пользуетесь ли вы оператором goto и в каких целях?
Начну, как положено, с себя. Я goto пользуюсь, пожалуй, исключительно при программировании на Visual Basic for Applications. Делаю это по следующим причинам: во-первых, ряд процедур удобнее генерировать при помощи встроенных "визардов", а они их генерят как раз с активным использованием goto. Править каждый раз такую процедуру вручную, убирая goto - значит сводить на нет все преимущества автоматизации;). Во-вторых, безусловный переход на метку в VBA удобно использовать при проверке на возникновение ошибки. В этом случае все обработчики ошибок локализуются в конце процедуры, что делает код в целом более читаемым. И, хотя теоретически подобной группировки можно добиться и другими средствами (и, например, программируя на Паскале, я бы совершенно точно организовал такую группировку без goto), в VBA такой способ кажется почему-то наиболее естественным и удобным.
Отредактировано uux (17.08.2007 21:40)
Неактивен
Использую goto в самых редких и крайних случаях, иначе говоря когда он либо упрощает алгоритм и тем сокращает затраты времени на выполнение кода алгоритма или, когда без него не обойтись. Одно точно известно, что повсеместное использование goto - дурной тон программирования в ЯВУ всех мастей. Это только программисты "старички", наученные еще с времен DOS, могут использовать goto правильно и при этом не портить и не усложнять алгоритм. В IF языках программирования и даже в УРКе goto имеет свою обоснованность и его использование нормальное явление, но уж мне то, точно сложновато читать огромный исходник написаный на урке с применением goto (хотя он там повсеместно
).
В данный период времени применяю goto, только в сложном алгоритме в синтаксическом анализаторе команд СТК для считывания постоянной строки (заключена между " ). В этом алгоритме с применением goto кол-во команд C# составило минимум 50, а без него получилось бы минимум 100, а о затратах памяти в этом случае вообще молчу (цифры условны и приведены для ощущения разницы).
Так что использовать goto рекомендуется тогда и только тогда, когда он действительно необходим. ![]()
Отредактировано Eten (21.08.2007 17:57)
Неактивен
Господа, а че вы к циклам то пристали >
. Если при написании цикла на языке Т нельзя вообще обойтись без goto, то это сильный минус для языка Т и его автора. И этому автору не помешает намекнуть, что его язык не может быть высокоуровневым если у него нет стандартных операторов, которые не могут не то, что выполнить команду цикл, даже позволить реализовать все команды основанные на общем алгоритмическом языке. А этот общий алгоритмический язык пишется схем-блоками. А раз уж в языке есть синтаксические конструкции основанные на определенных операторах, то уж точно, что goto будет использоваться в промежуточном коде, но самой программой. А вы господа, ломитесь на уровень промежуточного кода с примерами goto. Еще бы продемоснтрировали древную работу похожую на работу с массивами. ![]()
Мне чем C# нравится, так это возможностью не дать сделать те вещи, как это делалось в C++, которые потом губят всю прогу из-за простой нелепости. И goto там можно использовать только внутри одной функции, а не делать переход за ее границы, во время выполнения этой же функции. Поэтому, может показаться, что вариант C# строже и конкретней C++, но он дает гарантии разумного использования команд, так чтобы не было возможности нарушить логичность кода.
З.Ы.
Урку привел, как пример широкого использования goto.
Под языком Т, можно понимать любой язык, который реализует все стандартные действия алгоритма на уровне школьного.
И отмечу на последок, редко встречаются языки, где нет такого понятия в синтаксисе, как цикл. Его изучить не сложнее, чем оператор условного ветвления и возможностей он даст больше, нежели примение goto.![]()
Неактивен
Все спорим господа. Так вот аргумент все тем, кому goto не нравится:
// Распознавание десятичного числа
private bool isNumber()
{
bool btochka = false, bdigit = false;
Set_StartPosLexem();
tochka://проверка на точку
if (this.symbol == '.')
{
//если первым символом попалась точка, то записываем истина
btochka = true;
//запись символа в значение лексемы
this.lexvalue.Append(this.symbol);
// чтение следующего символа
this.NetxtSymbol();
//после точки всегда должна идти цифра
if (this.isDigit(this.symbol))
{
//запись символа в значение лексемы
this.lexvalue.Append(this.symbol);
// чтение следующего символа
this.NetxtSymbol();
}
else //в случае не пренадлежности к классу чисел символа после, выдать ошибку
{
this.lx = lexType.lexError;
this.er = ErrorCode.lexNumber;
Set_StartPosLexem();
this.lexvalue.Length = 0;
return true;
}
//случае истинности первого условия, записывать каждый следующий символ в значение лексемы, если он принадлежит к классу чисел
while (isDigit(this.symbol))
{
this.lexvalue.Append(this.symbol);
this.NetxtSymbol();
}
}
porjadok://проверка на порядок
//после числа может стоять только порядок или ничего
if ((this.symbol == 'E' || this.symbol == 'Е' || this.symbol == 'e' || this.symbol == 'е') && (btochka || bdigit))
{
this.lexvalue.Append('E');
this.NetxtSymbol();
//Дальше должен стоять только + или минус
if (this.symbol == '+' || this.symbol == '-')
{
this.lexvalue.Append(this.symbol);
this.NetxtSymbol();
}
else//в противном случае ошибка
{
this.lx = lexType.lexError;
this.er = ErrorCode.lexNumber;
Set_StartPosLexem();
this.lexvalue.Length = 0;
return true;
}
//последним должна стоять цифра, обзначающая показатель степени
if (this.isDigit(this.symbol))
{
//запись символа в значение лексемы
this.lexvalue.Append(this.symbol);
// чтение следующего символа
this.NetxtSymbol();
}
else //в случае не пренадлежности к классу чисел символа после, выдать ошибку
{
this.lx = lexType.lexError;
this.er = ErrorCode.lexNumber;
Set_StartPosLexem();
this.lexvalue.Length = 0;
return true;
}
//случае истинности первого условия, записывать каждый следующий символ в значение лексемы, если он принадлежит к классу чисел
while (isDigit(this.symbol))
{
this.lexvalue.Append(this.symbol);
this.NetxtSymbol();
}
goto konec;
}
else//условие гарантирующие переход на konec, в случае определения точки или числа, после проверки порядка
if (btochka || bdigit) goto konec;
//----------------------------------------------------------------------------------
//если, условие оба условия выше не выполнены (смотри условие с точкой) и порядком, то проверяем на принадлежность к классу чисел
if (this.isDigit(this.symbol))
{
//если первым символом попалось число, то записываем истина
bdigit = true;
//запись символа в значение лексемы
this.lexvalue.Append(this.symbol);
// чтение следующего символа
this.NetxtSymbol();
} else //в случае не пренадлежности к десятичному числу отклонить истинность возвращаемого значения
return false;//здесь откат не нужен (всего один смивол, проверен)
//случае истинности первого условия, записывать каждый следующий символ в значение лексемы, если он принадлежит к классу чисел
while (isDigit(this.symbol))
{
this.lexvalue.Append(this.symbol);
this.NetxtSymbol();
}
//если первая строка закочилась, то определить три случая:
//1) символ является точкой, тогда переход на tochka
//2) символ является Е или е(русская или английская), тогда переход на porjadok
//3) если оба условия отвергнуты и там не стоит буква, тогда выдать тип лексемы, в противном случае ошибка
if (this.symbol == '.') goto tochka;
if (this.symbol == 'E' || this.symbol == 'Е' || this.symbol == 'e' || this.symbol == 'е') goto porjadok;
if (isLetter(this.symbol))
{//если следом после последней цифры в числе стоит буква значит ошибка
this.lx = lexType.lexError;
this.er = ErrorCode.lexNumber;
Set_StartPosLexem();
this.lexvalue.Length = 0;
return true;
}
konec:
//перед выдачей лексемы проерить, что за число (слитно с ним) не стоит буква или еще одна точка
//Проверка осущевствляется во всех 6 вариантах десятичного числа (три из них с показателем степени)
if (this.isLetter(this.symbol) || (btochka && this.symbol == '.'))
{
this.lx = lexType.lexError;
this.er = ErrorCode.lexNumber;
Set_StartPosLexem();
this.lexvalue.Length = 0;
return true;
}
this.Unset_Odin();
//определяем тип лексемы и возвращаем истиность о пренадлежности к десятичному числу.
this.lx = lexType.lexInt; return true;
}Если найдете способ написать весь этот алгоритм разбора числа формата целого и десятичного (пример 2 2.3 2.3e+3 и еще три, всего шесть вариантов), без goto так, чтобы не занимало циклов больше, чем данный алгоритм и было также логичным по ходу действия.
Написано на C#, алгоритм работает и взят из исходников моего проекта LASOFTGAME (рабочее название СТК). ЛУЧШЕГО АЛГОРИТМА НЕ НАШЕЛ!!!
И заметьте в C#, goto можно применить только в текущей функции, что и приводилось, как хорошее использование, а здесь уже стандарт. Так, что логичность здесь не порушишь, как в C++. Если не согласны, то приводите контраргументы, а раз нечего саказать, то и мусолить соленный огурец не хера, лучше от этого не станет! ![]()
Неактивен
Добавлю к своему последнему посту.
Задача решается не тривиальная, алгоритм сложный, поэтому упростить его без goto никак. А, если те кто высказывался о своих программерских талантах, скажет, что ему лень разбирать код или он его разобрать не может (кроме не знающи не то, что C++, даже C#). То какого фига, спрашивается вы называете себя программистами, если не можете разобрать чужой, да еще с комментариями. ![]()
Неактивен
Вот, что значит читабельность на мой взгляд. Читабельность - это, когда приведенный код отформатирован отступами, именам переменных и объектов даны осмысленные имена и при этом не очень длинные, а также есть сопровождающие комментарие в самом коде. Однако, если код основан на обширном применении ООП, то лучше, когда при обращении к сво-вам объекта, методу и прочии частей самого объекта, само обращение написано полностью, например объект.список.текст[4] = объект.текст;.
Во всем остальном читабельный код, даже без изучения флагов и т.д. можно без проблем понять коментариям, хотя бы в общих чертах.
Неактивен
HzD_Byte:
Eten, реализация конечного автомата лексического анализатора занимает совсем немного) Без всяких goto. Если не забросишь - научишься всему)...
....приведённая Eten'ом реализация далеко не самая удачная....
Возмоно не удачная, но это только возможная. Не согласен со мной, тогда приведи лучший пример и без goto, но чтоб 6-ю вариантами форматов чисел или сделай пометки, где и как в моем коде не то или слишком широко шагнул. А то, я тоже, могу сказать, также по отношению к qsp не приведя должного сравнения. А так проверял свой кусок кода, даже на самые пакостные ситуации, так и обычные, итог код работоспособен ошибок не возникает. Заключение, с применением goto мне удалось не только упростить код, но и сократить число шагов. Так, что, раз нет весомых аргументов, то и не надо говорить, как говорится считаешь, что сделаешь, лучше, то покажи, либо не говори вообще.
А также, сколько бы стаж у тебя не был 10, 20, да хоть за 30 - это еще не о чем не говорит, потому как встречал детей, которые еще будучи семиклассниками, один из которых умудрился написать простой драйвер для монитора (или видюхи уже не вспомнишь 2-4 года назад было) и выйграл на конкурсе со своим творением. То задается вопрос причем тут стаж, раз и млад и стар может этим заниматься, главное, чтобы голова хорошо варила.
В окнец сие поста. Лексический анализатор не прямой, проект LASOFTGAME еще не достиг, той ситауции, когда требуется сделать прямой анализатор, т.к. нет четкой уверенности в постоянстве конструкции (в смысле не потребуются новые), а заодно такой кусок легче редактировать.
С одним соглашусь, что могут быть некоторые моменты в коде, которые можно модифицировать и сделать лучше.
Неактивен
Olegus t.Gl., в чем-то ты прав, но тоже отчасти. Намного проще читать переменную, когда знаешь откуда она и для чего (а этому помогут коменты, нормальное имя). Отступы в тексте помагют, различить где че стоит, а то, как кто-то ручкой по бумажке на коленке написал и херь поймешь, где читабельность?!
.
Вот к примеру в моем приведенном коде, если уж не взде, то хотя бы в сложных и нужных местах, у меня написан комментарий действий и их последствий, обо всем остальном догадаться можно и за так. К тому же, приведи я свой весь исходник, то ты обязательно нашел бы по нужному названию файла, класса или перечисления (и т.д.) и по коментам нужную тебе инфу. Тем паче, что инфа вне методов у меня автодокументирована xml тэгами, что кстати говоря ничуть не мешает его прочесть, вот:
/// <summary>
/// Тип ошибки
/// </summary>
protected ErrorCode er;
/// <summary>
/// Текущий читаемый символ.
/// </summary>
protected char symbol;или вот:
/// <summary>
/// Типы данных в СТК.
/// </summary>
public enum TypeVariable : int
{
/// <summary>
/// Пустой, не заданный тип данных
/// </summary>
tvNone = 0,
/// <summary>
/// Строка
/// </summary>
tvString = 1,
/// <summary>
/// Число
/// </summary>
tvNumber = 2,
/// <summary>
/// Булев
/// </summary>
tvBoolean = 3,
/// <summary>
/// Массив
/// </summary>
tvArray = 4
}последний не флаг, а перечисление, ну и чего тут не понятного, а вот теперь в коде фнукции
/// <summary>
/// Считывает следующий символ во входном коде.
/// </summary>
protected void NetxtSymbol()
{
//проверка на конец входного кода
if (this.current_pos.Line >= this.ec.Length)
{
this.Eof = true;
this.symbol = ' ';
return;
}
// Считывает символ в указанной позиции
this.symbol = this.ec[this.current_pos.Line][++this.current_pos.Column];
//кол-во считанных столбцов
this.unset_pos.Column++;
//если позиция столбца достигла конца строки, то переходим на следующую строку
//и устанавливаем перо столбца на ноль
if (this.current_pos.Column >= this.ec[this.current_pos.Line].Length - 1)
{
this.current_pos.Line++;
this.unset_pos.Line++;
this.current_pos.Column = -1;
}
}Здесь чересчур будет, приводить на каждую строку кода комент и так хватает, но будь это очень нужно, я бы написал для каждой строки, так естественно проще. Был случай, когда приходилось читать код на совершенно не знакомом языке и с помощью комента, приведенного для каждой команды, разобрать его не составило особых проблем. Вот те и читабельность. А то, что я привел не только читабельность, а еще и программирование в хорошем тоне.
Неактивен
Gremour
Пример хорош, но он сделан для прямого анализатора и сразу вытаскивает значение числа, также есть ситуации, в которых могут возникнуть исключительные ситуации. Мой вариант, конечно не может разобрать число 1.e1, но только пока не может. ![]()
Через дня 2-4 выложу здесь другой вариант, твоей идеи, только алгоритм будет уже мой собственный.
Неактивен
(опустить ноль до или после точки,
Поясни на примере, плохо как-то представить такое с экспонентой понятно, только не забудь представить число и в полной обычной форме письма, чтобы понять было удобно. ![]()
Неактивен