понедельник, октября 30, 2006
Заменитель Indy
Глюкобага. Очередная...
Заколебало :( Сегодня снова столкнулся с очень неприятной багой компилятора (бага старая и ранее я ее описывал на iXBT).
Объявляем вложенный тип в записи. Пытаемся объявить поле данного типа и получаем от компилятора пламенный привет. А вот свойства объявленного вложенного типа определяются на ура. Есть workaround: объявить поле с типом допускающим приведение к объявленному, объявить свойство проблемного типа и в методах доступа (read/write) производить приведение типов (поле к свойству/свойство к полю). Дабы устранить оверхэд методов, объявить их, как inline.
среда, октября 18, 2006
Маленькая радость
Америки я не отрою, если скажу, что с появлением динамических массивов и динамических строк жить стало легче, жить стало веселей :) Распределение памяти и управление временем жизни берет на себя компилятор, а мы можем избавится от выделения буферов средствами GetMem и ей подобным, т.к. такие массивы и строки являются по сути указателями на те самые буферы. И самое приятное, что такой буфер можно передать любой части программы без (даже временного) дублирования, т.к. компилятор использует механизм подсчета ссылок. Правда использовать такой буфер придется с приведением типа, но оно того стоит ;)
Пример:
s := 'http://www.borland.com/';
Stream.Write(Pointer(s)^, Length(s));
четверг, октября 12, 2006
Борис, ты не прав!
понедельник, октября 02, 2006
Enumerators (for-in-do)
Одним из самых заметных нововведений BDS 2006 является внесение в язык конструкции расширяющей оператор цикла For. For <container_item> In <container> Do; Переписывать сюда кусок документации не считаю нужным, и поэтому буду краток :) Лучше реализовывать перечислители в виде advanced-records т.к. при работе с ними не требуется динамического распределения памяти, а значит, код будет работать быстрее. Плюс удобнее работать с перечислителем вручную (не нужно создавать, не нужно финалить и разрушать), в случае необходимости. Правда сделать это (реализовать записью) не всегда удается, т.к. компилятор начинает ругаться на возвращаемый тип от GetEnumerator (видимо очередная глюкобага). Удачный пример перечислителя - перебор элементов XML документа, учитывая его структуру (каждый элемент может являться и родителем и ребенком) можно создать эффективный инструмент для перебора дочерних элементов любого родителя (хоть корня, хоть любого ребенка) с возможностью полного/близкого перебора. Сам перечислитель может обладать при этом указателем текущей глубины и номером элемента относительно начала перебора.
суббота, сентября 23, 2006
Счастливы вместе
четверг, сентября 21, 2006
Кодировки в XML-RPC
Неоднократно встречал в сети недовольные высказывания относительно того, что спецификация XML-RPC никак не регламентирует использование различных кодировок, в частности Unicode (и это, якобы, является минусом протокола). Но я считаю, что авторы этих высказываний (как и авторы библиотек включивших поддержку Unicode) не до конца понимают сути XML-RPC. Дело в том, что пакеты XML-RPC это лишь транспорт для данных приложения/сервиса и в каком виде данные должны предоставляться дело именно взаимодействующих сущностей, но ни как не протокола. На самом деле проблемы нет, как таковой. Ни что не мешает сервису предъявлять требования к передаче строк в кодировке, скажем UTF-8, если в том есть необходимость, а клиенту останется только "соответствовать". Такое требование затрагивает лишь данные, но не формат самого пакета. Таким образом и цель достигается, и происходит все в рамках спецификации. Выходит, что эта проблема "не в клозетах, а в головах" (c) Почти Булгаков :)
P.S.
Ну, а если вспомнить, что спецификация XML говорит об использовании UTF-8 во всяком случае, когда кодировка не может быть определена (не указаны Encoding и ByteOrder), то все становится просто и понятно, ведь пакеты XML-RPC не содержат ни того ни другого ;)
100 лет вместе с Turbo!
Позавчера получил CD c TurboDelphi 2006 Explorer! Спасибо Borland'у за бесплатную лицензию на 100 лет :) Правда в версии Explorer есть ограничение, а именно невозможность установки в среду сторонних компонентов. Но "ничего нет невозможного, для врача, для неотложного" (c) Розенбаум :), поэтому рецепт в студию: открываем пакет dclusr.dpk (это стандартный пакет пользовательских компонент и его установка допустима) и добавляем в него новый модуль инициализационная часть которого содержит код для загрузки необходимых пакетов:
Initialization
LoadPackage('package_1.bpl');
LoadPackage('package_1.bpl');
LoadPackage('package_1.bpl');
Но это еще не все! Для успешности данной операции необходимо, чтоб загружаемые пакеты могли саморегистрироваться (в отличие от обычного способа, когда регистрацией занимается среда) т.е. в инициализационной части модуля/модулей необходимо вызвать процедуру Register. Теперь все :) При запуске среды будет загружен dclusr.bpl, который, в свою очередь, загрузит нужные нам пакеты.
пятница, сентября 15, 2006
Багафича, даже две...
среда, сентября 13, 2006
среда, сентября 06, 2006
Advanced Records ("class-like")
Замечательная возможность BDS 2006! Работа с записями превращается в сказку, в смысле элегантности использования при грамотном проектировании. Использование свойств, методов и модификаторов видимости позволяет абстрагироваться от внутренней структуры записи, а применение директивы inline уменьшает/сводит на нет, какие бы то нибыло накладные расходы. В результате получаем работу с абстракцией и имеем при этом "чистый код"! Наличие конструкторов (пусть и параметризированных) облегчает использование advanced records в коде т.к. избавляет от необходимости объявлять переменные. Огромным плюсом является и тот факт, что даже при "конструировании" запись остается статической переменной, что в свою очередь снижает (опять же) накладные расходы и стимулирует к использованию advanced records в качестве перечислителей (enumerators). О перечислителях немного позже ;)
Небольшой пример:
// Структура для хранения данных о регионе
TData = Record
Public
{$REGION ' Определение вложенных членов '}
Type
// Массив прямоугольников и указатель на него
TRects = Array [0 .. MaxInt Div SizeOf(TRect) - 1] Of TRect;
PRects = ^TRects;
{$ENDREGION}
Strict Private
FBuffer : TByteDynArray;
Function GetPRect(AIndex : Cardinal) : PRect; Inline;
{$REGION ' Методы доступа к значениям свойств '}
Function GetBuffer : Pointer; Inline;
Function GetBufferSize : Integer; Inline;
Function GetHeader : PRgnDataHeader; Inline;
Function GetRects : PRects; Inline;
Function GetRectCount : Integer; Inline;
Procedure SetRectCount(Const Value : Integer); Inline;
{$ENDREGION}
Public
{$REGION ' Поддержка оператора for-in-do '}
Function GetEnumerator : TRectEnumerator; Inline;
{$ENDREGION}
Constructor Create(ARegion : HRGN); Overload;
Constructor Create(ARegion : TRegion); Overload;
Procedure UpdateHeader(ARecalculateBounds : Boolean = False);
Procedure RecalculateBounds;
Function TakeFrom(ARegion : TRegion{$IFDEF LASTERROR_SUPPORT}; Out ALastError : Longword{$ENDIF}) : Boolean; Overload;
{$IFDEF LASTERROR_SUPPORT}
Function TakeFrom(ARegion : TRegion) : Boolean; Overload; Inline;
{$ENDIF}
Function TakeFrom(ARegion : HRGN{$IFDEF LASTERROR_SUPPORT}; Out ALastError : Longword{$ENDIF}) : Boolean; Overload;
{$IFDEF LASTERROR_SUPPORT}
Function TakeFrom(ARegion : HRGN) : Boolean; Overload; Inline;
{$ENDIF}
Function TakeFrom(Const ARects : Array Of TRect) : Boolean; Overload;
Function TakeFrom(Const ABuffer : TByteDynArray) : Boolean; Overload;
Property Buffer : Pointer Read GetBuffer;
Property BufferSize : Integer Read GetBufferSize;
Property Header : PRgnDataHeader Read GetHeader;
Property Rects : PRects Read GetRects;
Property RectCount : Integer Read GetRectCount Write SetRectCount;
End;
Turbo возвращается!
пятница, августа 25, 2006
Class Helpers
Еще один способ облегчить себе жизнь воспользовавшись прелестями BDS 2006, а именно прелестью вынесенной в заголовок. Об этом я тоже уже упоминал но повторить (да еще и самого себя) не помешает. Итак:
Type
// Класс-хелпер для класса TObject
TObjectClassHelper = Class Helper For TObject
Private
{$REGION ' Методы доступа к значениям свойств '}
Function GetThis : TObject; Inline;
Function GetThisAssigned : Boolean; Inline;
{$ENDREGION}
Public
Property This : TObject Read GetThis;
Property ThisAssigned : Boolean Read GetThisAssigned;
End;
Implementation
{ TObjectClassHelper }
//
Function TObjectClassHelper.GetThis : TObject;
Begin
Result := Self;
End;
//
//
Function TObjectClassHelper.GetThisAssigned : Boolean;
Begin
Result := Assigned(Self);
End;
//Удобно использовать в коде требующем ссылку на объект раскрытый оператором With. В зависимости от стиля программирования такое может случаться довольно часто ;) Примеры:
With TRegion.CreateAssigned(ARegion, amSharing) Do
Try
Result := TakeFrom(TRegion(This), ALastError);
Finally
Free;
End;With FindControl(0) Do
If ThisAssigned Then
Caption := Caption + 'OK';
четверг, августа 24, 2006
Record Helpers
С чего-то нужно было начинать, поэтому я начну с того о чем уже упоминал. Несмотря на то, что в документации BDS 2006 не сказано о наличии record helper'ов для платформы Win32 (я во всяком случае не нашел) эта изумительная вещица работает! Простейший пример иллюстрирует всю прелесть данной конструкции:
TypeTRectHelper = Record Helper For TRect
Function GetWidth : Integer; Inline;
Function Getheight : Integer; Inline;
Property Width : Integer Read GetWidth;
Property Height : Integer Read GetHeight;
End;
...
//
Function TRectHelper.GetWidth : Integer;
Begin
With Self Do
Result := Right - Left;
End;
//
//
Function TRectHelper.GetHeight : Integer;
Begin
With Self Do
Result := Bottom - Top;
End;
//После чего все переменные типа TRect получают свойства Width и Height.