Текущий архив: 2004.08.29;
Скачать: CL | DM;
Вниз
Нужно ли бороться с хинтами и ворнингами? Найти похожие ветки
← →
Григорьев Антон © (2004-08-08 08:47) [0]Вопрос навеян постом [369] Юрия Зотова в ветке http://delphi84.valuehost.ru/cgi-bin/forum.pl?id=1090676641&n=3 (Калькулятор). Там Юрий утверждает, что все хинты и предупреждения компилятора надо вычищать (в смысле, подправлять код так, чтобы их не было). Я с таким подходом не совсем согласен, потому что бывает немало кусков корректного кода, которые компилятору в силу его ограниченности кажутся подозрительными. Вот два примера, которые мне уже глаза намозолили:
procedure ...
var A:TSomeType;
begin
...
if Некторое условие then
begin
// Какие-то действия, в т.ч. инициализация A
end;
// Здесь ещё какие-то действия
if То же самое условие then
begin
// Здесь снова используется A
end;
...
end;
Переменная A используется только внутри первого и второго if"ов. Во втором if"е получаем предупреждение: переменная, возможно, не инициализирована. Но я-то не компилятор, я понимаю, что второй if будет выполнен, только если перед этим был выполнен первый, и переменная всё-таки будет инициализирована. Ну и что мне делать? Вставлять в начало функции бессмысленную инициализацию A произвольным значением? А зачем? Лишний код, лишнее время работы процедуры. Конечно, издержки мизерны, но важен сам принцип.
Другой пример (кусок кода, кстати, из моего калькулятора).
Val(Copy(S,P,255),R,D);
J:=D;
Val(Copy(S,P,J-1),R,D);
Суть здесь вот в чём: в результате предыдущего анализа я знаю, что в строке S начиная с символа с индексом P записано число. А после числа идёт ещё что-то. Первый раз я вызываю Val для того, чтобы определить, на каком символе закнчивается число (его индекс заносится в D). Второй вызов нужен для того, чтобы получить это число. Так вот, на первом вызове получаем хинт: значение, присвоенное R, нигде не используется. А как я могу его использовать, если в документации нет информации о том, какое значение получит R, если строка не представляет собой корректное число. Зачем мне использовать переменную со случайным значением? Можно, конечно, вставить фиктивный код для этого, но опять же, я не компилятор, я понимаю, что здесь всё в порядке.
А если отклюяать хинты и варнинги (хотя бы локально), то можно и в самом деле что-то важно пропустить.
Одним словом, вопрос такой: нужно ли бороться с хинтами и варнингами ценой вставки бесполезного кода, или фиг с ними, пусть живут?
← →
Думкин © (2004-08-08 09:24) [1]
> procedure ...
> var A:TSomeType;
> begin
> ...
> if Некторое условие then
> begin
> // Какие-то действия, в т.ч. инициализация A
> end;
> // Здесь ещё какие-то действия
> if То же самое условие then
> begin
> // Здесь снова используется A
> end;
> ...
> end;
Если выделенное жирным соответствует написанному то, что мешает сделать так:procedure ...
var A:TSomeType;
begin
...
if Некторое условие then
begin
// Какие-то действия, в т.ч. инициализация A
//end;
// Здесь ещё какие-то действия
//if То же самое условие then
begin
// Здесь снова используется A
end;
...
end;
Если все-же условия не эквивалентны, то компилятор прав в том, что предупреждает.
Второе пока не анализировал, но вполне вероятно и там можно что-то нарыть.
Я в Д7 отключаю только 3 предупреждения - которые включили в предверии .Net - а нафига, я не знаю.
Все остальное и варнинги и хинты - включено. Пишу и всегда делаю так, что ни одного варнинга и хинта не имею, сколько бы строчек кода не было.
Кстати, не раз спасало. Потму как по зеленому, нарывался - ошибка, а оказывается компилятор меня вполне честно предупреждал.
Видимо так. Для начала. :)
← →
Ihor Osov'yak © (2004-08-08 10:15) [2]2 [1] Думкин © (08.08.04 09:24)
Комментарий один перед последним begin потерял.
2 Григорьев Антон © (08.08.04 08:47)
Относительно первого примера. Как говорилось не раз, и не одним человеком - хинт, как минимум, намекает на неаккуратность кода, что, и было продемонстрировано Думкиным. А во вторых, Вы бы полностью привели "Некоторое условие" - в вдруг у Вас там или глобальная переменная или поле класса используется. Откуда компилятору знать, однопоточное у Вас приложение, или многопоточное. Хотя компилятор наверное даст предупреждение и для чисто "локального" условия - но догда снова см. [2].
Относительно второго примера. Имхо, снова случай неаккуратного (непрозрачного) кода. Без вашего комментария трудновато понять, что делают эти три строчки. Конечно, если несколько минут подумать... Но согласитесь, что если думать по несколько минут над несколькими тривиальными строчками.. То есть снова имеем случай "как минимум, намекает на неаккуратность кода".. И даже может на то, что калькулятов пишется без теории :-) Но если серьезно - в определенных случаях, второй пример имеет право на жызнь. Только нужно дополнить его локальными директивами подавления соотв. предупреждения и сопроводить соответсвующим комментарием. Чтобы потом не возникало вопросов. Ни у Вас через полгода, ни у того, кому может придется со временем разгребать Ваш код. Это совсем небольшая плата за кучу сохраненного времени и нервов, которое нам порою обеспечивает очередной хинт компилятора. И который мы точно не провороним в случае работы по правилу - "хинтов и варнингов быть не должно"
← →
Думкин © (2004-08-08 11:16) [3]> [2] Ihor Osov"yak © (08.08.04 10:15)
> 2 [1] Думкин © (08.08.04 09:24)
>
> Комментарий один перед последним begin потерял.
Да, запаостив тоже увидел. Но уже не стал править, а оно вылилось бы - в Error. Все-таки стоит прислушаться иногда и к компилятору и к старперам. %)))
← →
Григорьев Антон © (2004-08-08 11:26) [4]
> Думкин © (08.08.04 09:24) [1]
> Если выделенное жирным соответствует написанному то, что
> мешает сделать так:
Мешает то, что в случае, если условие истинно, между первым и вторым if"ом бывает необходимо выполнить какие-то действия, которые так же должны выполняться и в том случае, если условие ложно.
> Ihor Osov"yak © (08.08.04 10:15) [2]
> 2 Григорьев Антон © (08.08.04 08:47)
>
> Относительно первого примера. Как говорилось не раз, и не
> одним человеком - хинт, как минимум, намекает на неаккуратность
> кода, что, и было продемонстрировано Думкиным. А во вторых,
> Вы бы полностью привели "Некоторое условие" - в вдруг у
> Вас там или глобальная переменная или поле класса используется.
> Откуда компилятору знать, однопоточное у Вас приложение,
> или многопоточное. Хотя компилятор наверное даст предупреждение
> и для чисто "локального" условия - но догда снова см. [2].
Как я уже написал выше, пока Думкин это не продемонстрировал. Не всегда всё удаётся запихнуть в один if, иногда в середине нужны какие-то действия, выполняющиеся безусловно. Компилятор, конечно, прав, когда указывает мне на это, но ведь человек умнее компилятора и может понять то, что компилятору просто недоступно. И я просто не хочу вставлять лишний код там, где это не нужно.
> Относительно второго примера. Имхо, снова случай неаккуратного
> (непрозрачного) кода. Без вашего комментария трудновато
> понять, что делают эти три строчки. Конечно, если несколько
> минут подумать... Но согласитесь, что если думать по несколько
> минут над несколькими тривиальными строчками..
Буду крайне благодарен, если вы предложите мне решение аналогичной задачи, столь же короткое и эффективное, но более очевидное. Мне и самому эти строчки не нравятся, но всё, что мне приходит в голову, будет более громоздко. На всякий случай - в строке там не целые числа, а вещественные, т.е. просто пройти по символам и найти первую не-цифру не получится.
← →
Думкин © (2004-08-08 11:41) [5]> [4] Григорьев Антон © (08.08.04 11:26)
> Мешает то, что в случае, если условие истинно, между первым
> и вторым if"ом бывает необходимо выполнить какие-то действия,
> которые так же должны выполняться и в том случае, если условие
> ложно.
....
> недоступно. И я просто не хочу вставлять лишний код там,
> где это не нужно.
Оно понятно. Это также как и ..
1. Return value of function "-----" might be undefined
2. Variable "--" might not have been initialized
Человек очень многое подразумевает. К сожалению, при использовании другими это знание не всегда сразу воспроизводится. И может приводить к жутким глюкам, примеры я думаю были почти у всех. Когда рассматриваешь код, - ага тут он подразумевал это, а тут это, а тот второй этого не заметил, ага - а чтот мне теперь делать - видимо рефакторинг по Российски?
Но все-таки
И я просто не хочу вставлять лишний код там, где это не нужно.
это для быстрого и на уровне кратких утилит, либо о жестком документировании как и пишет Игорь.
Если я пишу что-то для 3-х мминутного использования, то и не на такое можно бы положить, но уже и тут привычка, хотя не без греха, каюсь, но последнее время - даже не помню.
← →
Anatoly Podgoretsky © (2004-08-08 11:47) [6]Абсолютно правильные сообщения компилятора, а что делать, так ведь уже давно решил, ну его побоку этот компилятор.
А стоит подумать и сделать перепроектирование.
← →
VID © (2004-08-08 11:59) [7]>>Григорьев Антон © (08.08.04 11:26) [4]
>>На всякий случай - в строке там не целые числа, а вещественные, т.е. просто пройти по символам и найти первую не-цифру не получится.
Вещественное число от целочисленного отличается одной лишь точкой или запятой! Так что не надо драматизировать, не грех и по символьной пройтись по строке S, и проанализировать её.
А как сформировать вещественное число, зная её целую и дробную часть, я думаю ты и сам в курсе ;)
← →
Ihor Osov'yak © (2004-08-08 12:37) [8]2 [7] VID © (08.08.04 11:59)
>отличается одной лишь точкой или запятой!
Если говорить в контексте ф-ци Val - не только. Всякие там $, e, етс.. Ради интетера - см. исходники, модуль system - _ValExt, _ValLong, _ValInt64.. Ох, эти compile magic, или как их там.. Вот, если бы можно было напрямую вызвать _ValExt - не страдал-бы Антон ерундой.
2 [4] Григорьев Антон © (08.08.04 11:26)
немного прелюдии - имхо, "неприятность" с Val спровоцирована не очень уместным желанием разрешить "выбрасывание" знака умножения. Кстати, не задумывались почему даже в довольно терпимых к разного рода вольностям языках, той же си, все же символ умножения указывать обязательно?
По теме. При возникновении такой проблемы я бы еще раз проанализировал постановку задачи, спецификацию. В случае "позно, дядя - закомпосировали" - все же директивы компилятора локальные убивающие один этот варнинг с подробным комментарием. Ну, если было <укр>"час та натхнення"</укр> - может написал-бы процедуру, "более громоздкую" но зато более прозрачную.
Еще. см. [5] и очень подумайте над [6]
← →
VMcL © (2004-08-08 12:58) [9]>>Ihor Osov"yak © (08.08.04 12:37) [8]
>Вот, если бы можно было напрямую вызвать _ValExt...
Выдам страшную тайну:asm
// ...
call System.@ValExt
end;
← →
Ihor Osov'yak © (2004-08-08 13:07) [10]2 [9] VMcL © (08.08.04 12:58)
во, век учись...
и что обидно, похожие вещи в общем-то делал..
← →
DiamondShark © (2004-08-08 14:00) [11]
> Григорьев Антон © (08.08.04 08:47)
> procedure ...
> var A:TSomeType;
> begin
> ...
> if Некторое условие then
> begin
> // Какие-то действия, в т.ч. инициализация A
> end;
> // Здесь ещё какие-то действия
> if То же самое условие then
> begin
> // Здесь снова используется A
> end;
> ...
> end;
procedure ...
procedure Unconditional;
begin
// независимые от условия;
end;
procedure Conditional;
begin
// Какие-то действия
Unconditional;
// Здесь снова
end;
begin
...
if Некторое условие then
Conditional
else
Unconditional
end;
И никаких переменных с аномальным временем жизни.
← →
Aldor. (2004-08-08 14:20) [12]Вот свежий пример, только что вылезло:
function FuncName: Boolean;
begin
Result := False;
...
try
...
finally
...
end;
Result := True;
end;
(выдать True только в случае удачного завершения)
получаем: [Hint] uEngine.pas(193): Value assigned to "FuncNam" never used
Как сделать такой код более грамотным, в голову не приходит, поэтому и пришел сюда за советом (не для того чтобы что-то доказать).
← →
DiamondShark © (2004-08-08 14:26) [13]
> Aldor. (08.08.04 14:20) [12]
Этот код вообще не должен быть функцией.
← →
Aldor. (2004-08-08 14:43) [14]> Этот код вообще не должен быть функцией.
Почему? Функция выполняет свои действия и возвращает True если они все выполнены успешно. Except, насколько я понимаю, это не очень хорошо в данном случае.
← →
Anatoly Podgoretsky © (2004-08-08 14:50) [15]Aldor. (08.08.04 14:20) [12]
Правильно верхнее значение не используется, а в случае ошибки не используется и нижнееResult := True;
finally
← →
Ihor Osov'yaka (2004-08-08 14:54) [16]2 [14] Aldor.
> Почему?
Потому что в случае возникновения исключительной ситуации в месте вызова функции присваивания результата работы функции соотв. перевенной вообще происходить не будет - там уже будет стремительный бег по цепочке секций exception/finally. То есть действительно результаты деятельности
Result := False;
нигде использоваться не будут.
Зы. Протрассируйте небольшой тестовый пример. Либо на ассемблере, либо поставив точку прерывания на изменение переменной, которая получает значение функции.. Если то или то затруднительно - в роли переменной, принимающей значение поставте свойство с методом Set (на входе которй ставим точку прерывания).
← →
VID © (2004-08-08 14:59) [17]function FuncName: Boolean;
begin
try
try
...
Result := True;
except
Result := False;
end;
finally
...
end;
end;
← →
Ihor Osov'yak © (2004-08-08 15:11) [18]2 [17] VID ©
А это уже совсем другие пироги. Корректные в плане возвращения результата.. А вот относительно финишного файнели и отсутствия троеточия перед первым try нехорошие ассосиации возникают :-).
Зы - приходилось видеть и такой код -
try
mObj := TMyObj.Create;
...
finally
mObj.Free;
end;
и что удручает - не единыжды.. И в общем - не в совсем начинающих..
← →
Aldor. (2004-08-08 15:12) [19]Anatoly Podgoretsky © (08.08.04 14:50) [15]
Result := True;
finally
Да, именно это имелось в виду. И тоже, кстати, варнинг (тот же).
VID © (08.08.04 14:59) [17]
function FuncName: Boolean;
begin
try
try
...
Result := True;
except
Result := False;
end;
finally
...
end;
end;
А хорошо ли здесь юзать except? Я помню советы о том, что использование except нужно минимизировать.
← →
Григорьев Антон © (2004-08-08 15:17) [20]
> VID © (08.08.04 11:59) [7]
> >>Григорьев Антон © (08.08.04 11:26) [4]
> >>На всякий случай - в строке там не целые числа, а вещественные,
> т.е. просто пройти по символам и найти первую не-цифру не
> получится.
>
> Вещественное число от целочисленного отличается одной лишь
> точкой или запятой! Так что не надо драматизировать, не
> грех и по символьной пройтись по строке S, и проанализировать
> её.
Одной только точкой? Ну-ну... Стало быть, 2.56E-28 уже вещественным числом не является?
Впрочем, разбор и такой строки я написал бы без проблем, если б мне надо было. Вопрос-то в другом. Есть код из трёх строчек, который делает то, что мне нужно. Делает вполне корректно и безошибочно. И производительность у него достаточно высока. Единственный его недостаток - по глупости своей компилятор выдаёт на нём хинт. А мне тут предлагают заменить его на код из пары десятков строчек, который вряд ли будет работать быстрее, и всё это только для того, чтобы убрать хинт. А стоит ли овчинка выделки?
> Ihor Osov"yak © (08.08.04 12:37) [8]
> 2 [4] Григорьев Антон © (08.08.04 11:26)
>
> немного прелюдии - имхо, "неприятность" с Val спровоцирована
> не очень уместным желанием разрешить "выбрасывание" знака
> умножения. Кстати, не задумывались почему даже в довольно
> терпимых к разного рода вольностям языках, той же си, все
> же символ умножения указывать обязательно?
А вот щаз возьму и обижусь! :))))) Возмущён до глубины души - приписывать мне такие глупые идеи! :)) Будет время - загляните в ветку "Калькулятор" - именно я больше всех убеждал там GrayFace"а, что писать калькулятор, допускающий умножение без знака, глупо. А задача такая возникает и при выделении чисел из строки "2+2", и беззнаковое умножение тут ни при чём.
> Ну, если было <укр>"час та натхнення"</укр> - может написал-бы
> процедуру, "более громоздкую" но зато более прозрачную.
Да я бы её тоже написал, если б понимал, зачем. Просто я не считаю убирание хинтов из корректно работающего кода самоцелью. А других причин переделывать данный код я не вижу. Вот и интересуюсь: может быть, у других глаза получше?
А что касается прозрачности, то это во многом субъективный критерий. Я вот привык к такому коду, мне он кажется вполне понятным.
Кстати, кому интересно, примеры кода взяты из модуля ExprMake, который можно скачать здесь: http://www.delphikingdom.com/asp/viewitem.asp?catalogid=718
Другая версия того же алгоритма разбора выражения, более простая, но с подробными комментариями, лежит здесь: http://www.delphikingdom.com/treasury/s003.htm#link7
> DiamondShark © (08.08.04 14:00) [11]
Ещё раз прочитайте, что я написал: некоторый код должен выполняться безусловно обязательно между if"ами! В вашем примере я этого не увидел. У меня что-то с глазами?
← →
Piter © (2004-08-08 15:23) [21]Ну насчет подавления ВСЕХ warning и hint"ов - даже сами модули VCL компилируются с предупреждениями. Так что ответ очевиден - борландовцы явно не глупее нас с вами и если считают, что компиляция с warning осуществима - значит, так оно и есть.
Хотя, конечно, я лично стараюсь подавить все высказывания компилятора, зачастую просто раздражают строки снизу, создается какая-то неполноценность продукта :) Даже не знаю как объяснить...
← →
Григорьев Антон © (2004-08-08 15:59) [22]
> Piter © (08.08.04 15:23) [21]
> Хотя, конечно, я лично стараюсь подавить все высказывания
> компилятора, зачастую просто раздражают строки снизу, создается
> какая-то неполноценность продукта :) Даже не знаю как объяснить...
Это ты в точку. Очень раздражают :)) Но пользу они тоже очень часто приносят.
← →
Ihor Osov'yak © (2004-08-08 16:18) [23]2 [20] Григорьев Антон ©
> именно я больше всех убеждал там GrayFace"а,
Прошу извинения :-). Но только по этому пункту..
> и при выделении чисел из строки "2+2", и беззнаковое умножение тут ни при чём.
ну, лично бы я "множители" (используя Вашу же терминологию с http://www.delphikingdom.com/treasury/s003.htm#link7 ) я бы все же по другому выделял.. Но это уже в сторону, мы же флеймим вокруг Val.
Я бы наверное, пожертвовал все же 2-3 строчками, и сделал что-то типа{$HINTS OFF}
function FindPosAfterNumber(const aStr: string): integer;
var
r: extended;
i: integer;
begin
Val(aStr, r, i);
if i = 0 then
result := length(aStr) + 1
else
result := i;
end;
{$HINTS On}
а в случае наличия времени and so on -function FindPosAfterNumber2(const aStr: string): integer;
var
i: integer;
begin
asm
lea edx, i
lea eax, aStr
mov eax, [eax]
call System.@ValExt
end;
if i = 0 then
result := length(aStr) + 1
else
result := i;
end;
В случае испосльзования специализированной процедуры и комментировать особо ничего не нужно..
← →
Ihor Osov'yak © (2004-08-08 16:22) [24]хотя здесь финт if i = 0 then наверное лишний, зависит от контескта..
Ну и i - тоже, можно использовать result, так что реальный код будет компактнее.
← →
имя (2004-08-08 16:26) [25]Удалено модератором
← →
имя (2004-08-08 16:26) [26]Удалено модератором
← →
имя (2004-08-08 16:26) [27]Удалено модератором
← →
имя (2004-08-08 16:26) [28]Удалено модератором
← →
имя (2004-08-08 16:26) [29]Удалено модератором
← →
имя (2004-08-08 16:26) [30]Удалено модератором
← →
имя (2004-08-08 16:26) [31]Удалено модератором
← →
имя (2004-08-08 16:26) [32]Удалено модератором
← →
имя (2004-08-08 16:26) [33]Удалено модератором
← →
имя (2004-08-08 16:26) [34]Удалено модератором
← →
имя (2004-08-08 16:26) [35]Удалено модератором
← →
имя (2004-08-08 16:26) [36]Удалено модератором
← →
имя (2004-08-08 16:27) [37]Удалено модератором
← →
имя (2004-08-08 16:27) [38]Удалено модератором
← →
имя (2004-08-08 16:27) [39]Удалено модератором
← →
имя (2004-08-08 16:27) [40]Удалено модератором
Страницы: 1 2 3 4 вся ветка
Текущий архив: 2004.08.29;
Скачать: CL | DM;
Память: 0.59 MB
Время: 0.035 c