Однако, на самом деле происходит очень неприятная штука (FPC 2.4.0, Debug/Normal mode, любой из режимов совместимости TP/ObjFPC/Delphi/FPC):
Running "f:\programs\pascal\tst.exe " No heap dump by heaptrc unit Exitcode = 201 Runtime error 201 at $00401481 $00401481 main, line 15 of F:/Programs/Pascal/tst.pp $004083C1
15 строка - это
if s[i] in myset then inc(count);
Как только очередной символ строки не входит во множество допустимых значений для myset - программа завершается аварийно при попытке проверить In. В багтрекере есть одна ошибка, связанная с множествами (она уже исправлена, в 2.5.1). Но этой нет. Вот я и думаю, это ж баг? Так быть не должно - не присутствует значение во множестве, значит надо вернуть False и все.
Вот я и думаю, это ж баг? Так быть не должно - не присутствует значение во множестве, значит надо вернуть False и все.
Другими словами, ты полагаешь, что тут должно работать автоматическое приведение типов? Но как?
Мне такое поведение представяется логичным.. То есть сравнение (выяснение принадлежности) происходит только для элементов множества. Не элемент - выяснение невозможно.
Сейчас пытался сделать нечто подобное для чисел и без множеств.. Не вышло )). Числовые типы приводятся, похоже, всегда. Например:
{$R+} type tN = 2..8;
var n: tN;
begin if n<5 then WriteLn('good'); if n<10 then WriteLn('bad'); ReadLn end.
- это отрабатывает на ура без всяких ошибок..
--------------------
я - ветер, я северный холодный ветер я час расставанья, я год возвращенья домой
, и надо выбрасывать критическую ошибку, да? В топку такое поведение. У меня не строка может состоять из символов 'a'..'z', а посторонняя переменная. И если символ из строки в ней не присутствует или не может присутствовать - то In должен вернуть False.
Заметь, подобное поведение было как минимум до версии 2.0.0 (на двойке не помню, на 1.0.10 проверил только что - работает), обратная совместимость где?
Да. И еще одно - что мне совершенно непонятно. Откомпилируем программу в Options -> Mode = Release, все прекрасно работает и в 2.4.0. То есть, все-таки баг в отладочных режимах.
И еще одно - что мне совершенно непонятно. Откомпилируем программу в Options -> Mode = Release, все прекрасно работает и в 2.4.0. То есть, все-таки баг в отладочных режимах.
Гм. А разве в моде Release включен Range Checking?..
Володь, я в целом согласен, что фича ненужная и бесполезная. Я не могу привести примера для себя, где оно бы помогло. Но все же логику тут отрицать пока не могу. Я еще подумаю над этим..
Добавлено через 4 мин.
Цитата(volvo @ 6.11.2010 2:59)
, и надо выбрасывать критическую ошибку, да?
Это обычный RangeCheck.. Выключи/включи его для этого куска кода - и проблема решена..
--------------------
я - ветер, я северный холодный ветер я час расставанья, я год возвращенья домой
Я подумал, как и обещал. И по-прежнему считаю, что это совершенно правильное поведение компилятора строго типизированного языка (каковым является объектный Паскаль в поздних реализациях). Справедливости ради, скажу, что я так и думал, что именно это произойдет еще при первом просмотре кода. Я понимаю, что это не довод, конечно )).
В твоем примере происходит обработка ВСЕХ входящих символов. Значит, конструкция для обработки должна принимать их ВСЕ. То, что в число "хороших" символов могут входить только буквы, еще не значит, что ты можешь ими ограничиться при обработке. Поэтому введение типа tset в этом коде не есть правильное действие. Если в твоем потоке символов предполагаются буквы и пробелы, а также цифры, но (допустим) никак не управляющие символы, то организуй соответствующее множество, и RCE (в процессе отладки, разумеется) будет означать, что пролез какой-нить ctrl-c, что есть признак ошики в коде и требует реакции программера.
Так что, тут нет никакого бага, мне кажется. IMHO, ессно. Но довольно твердое .
--------------------
я - ветер, я северный холодный ветер я час расставанья, я год возвращенья домой
Delphi не ругается ни при выключенном RangeCheck, ни при включенном. При операциях с числами аргументы приводятся к большему диапазону, так-что я не вижу смысла в случае с множествами поступать иначе.
При операциях с числами аргументы приводятся к большему диапазону, так-что я не вижу смысла в случае с множествами поступать иначе.
То, что ты его не видишь, не значит, что его нет )). Я уже привел ситуацию, когда такое поведение может быть полезным. Что касается больший/меньший диапазон - это неправильное проектирование числовых свойств на множества. Мне это тоже сначала пришло в голову, потом я покрутил в мозгах и понял, что это совсем разные вещи. В числах диапазон - это, как правило, ограничение, наложенное вычислительными возможностями. А тут ты можешь задать
tak = set of 'a'..'k'; tlz = set of 'l'..'z';
- и причиной для этого может быть именно отслеживание диапазона средствами компилятора на этапе отладки. Всякое "приведение, исходя из здравого смысла" тут неуместно. Арчон, ты в ладах с граматиками и т.п. stuff'ом, ты должен это понять (или строго доказать мне обратное)).
Молчание volvo я склонен воспринимать как согласие со мной (если, конечно, он не супер занят на другом фронте)). Зная его нелюбовь признавать свои ляпы (очень редкие, правда), я полагаю, что он просто отмалчивается..
--------------------
я - ветер, я северный холодный ветер я час расставанья, я год возвращенья домой
. Обратил внимание? Сразу запихиваем содержимое очередного элемента массива в EAX, и смотрим, есть ли оно в множестве. А теперь вышеприведенный мной код:
type tset = set of 'a' .. 'z'; const myset: tset = ['a' .. 'z']; s: string = 'the test';
// for i := 1 to length(s) do if s[ i ] in myset then inc(count); writeln(count);
То есть, сначала из выдирается очередной символ, от него отнимается 97 (ну, это понятно - приводим к началу отсчета, 'a' считается нулевым элементом множества - значит ото всего будем отнимать 97, начинался бы интервал при описании tset с 'b' - отнимали бы 98), потом проверяем результат на попадание в допустимый интервал (26 символов, начиная с 0 - если значение больше 25, то RCE). А потом опять выдираем значение из строки и его уже проверяем на наличие во множестве...
Если так все-таки было задумано, то чего бы не сделать то же самое действие для целочисленных базовых типов - непонятно. Для перечислимых тоже есть такая проверка:
type t = (_1, _2, _3, _4); st = set of _2 .. _4;
const ssv: st = [_2 .. _4]; one: t = _1; begin if one in ssv then writeln('wrong'); end.
точно так же, как и при работе с Char-ами вылетает при отладке.
Неоднозначность какая-то получается. Учитывая то, что есть Generic-и - это ОЧЕНЬ нехорошая неоднозначность.
Если так все-таки было задумано, то чего бы не сделать то же самое действие для целочисленных базовых типов - непонятно. Для перечислимых тоже есть такая проверка: <...> Неоднозначность какая-то получается. Учитывая то, что есть Generic-и - это ОЧЕНЬ нехорошая неоднозначность.
Да, с этим я не могу не согласиться. Явная неоднозначность. И неоднозначность плохая, да. В такой ситуации ответ может дать только тот, кто делал.. Володь, ты еще не запостил этот вопрос на форум FP?
--------------------
я - ветер, я северный холодный ветер я час расставанья, я год возвращенья домой