понедельник, октября 30, 2006

Заменитель Indy

Не так давно открыл для себя сетевую библиотеку Synapse. Ощущения самые положительные. В отличии от монстра по имени Indy, Synapse являет собой легкую и элегантную оболочку над сетевой инфраструктурой сокетов. В настоящий момент, на ее основе, мною создаются транспортные уровни клиента и сервера XML-RPC (правда реализация на Indy, тоже предусматривается ;))

Глюкобага. Очередная...

Заколебало :( Сегодня снова столкнулся с очень неприятной багой компилятора (бага старая и ранее я ее описывал на iXBT).

Объявляем вложенный тип в записи. Пытаемся объявить поле данного типа и получаем от компилятора пламенный привет. А вот свойства объявленного вложенного типа определяются на ура. Есть workaround: объявить поле с типом допускающим приведение к объявленному, объявить свойство проблемного типа и в методах доступа (read/write) производить приведение типов (поле к свойству/свойство к полю). Дабы устранить оверхэд методов, объявить их, как  inline.

среда, октября 18, 2006

Маленькая радость

Америки я не отрою, если скажу, что с появлением динамических массивов и динамических строк жить стало легче, жить стало веселей :) Распределение памяти и управление временем жизни берет на себя компилятор, а мы можем избавится от выделения буферов средствами GetMem и ей подобным, т.к. такие массивы и строки являются по сути указателями на те самые буферы. И самое приятное, что такой буфер можно передать любой части программы без (даже временного) дублирования, т.к. компилятор использует механизм подсчета ссылок. Правда использовать такой буфер придется с приведением типа, но оно того стоит ;)

Пример:

s := 'http://www.borland.com/';


Stream.Write(Pointer(s)^, Length(s));

четверг, октября 12, 2006

Борис, ты не прав!

FAQ Apache, в части о сжатии запроса/ответа XML-RPC, говорит о том, что спецификация XML-RPC запрещает использование сжатия (и где они это нашли??). Считаю необходимым прояснить ситуацию. Спецификация XML-RPC требует: чтоб тип контента (Content-Type) запроса/ответа соответствовал text/xml, имелись некоторые обязательные заголовки (User-Agent, Content-Length) и не более того. Спецификация не запрещает применения сжатия к контенту (Content-Encoding), поэтому - Apache, ты не прав!

понедельник, октября 02, 2006

Enumerators (for-in-do)

Одним из самых заметных нововведений BDS 2006 является внесение в язык конструкции расширяющей оператор цикла For. For <container_item> In <container> Do; Переписывать сюда кусок документации не считаю нужным, и поэтому буду краток :) Лучше реализовывать перечислители в виде advanced-records т.к. при работе с ними не требуется динамического распределения памяти, а значит, код будет работать быстрее. Плюс удобнее работать с перечислителем вручную (не нужно создавать, не нужно финалить и разрушать), в случае необходимости. Правда сделать это (реализовать записью) не всегда удается, т.к. компилятор начинает ругаться на возвращаемый тип от GetEnumerator (видимо очередная глюкобага). Удачный пример перечислителя - перебор элементов XML документа, учитывая его структуру (каждый элемент может являться и родителем и ребенком) можно создать эффективный инструмент для перебора дочерних элементов любого родителя (хоть корня, хоть любого ребенка) с возможностью полного/близкого перебора. Сам перечислитель может обладать при этом указателем текущей глубины и номером элемента относительно начала перебора.

суббота, сентября 23, 2006

Счастливы вместе

Речь снова о TurboDelphi. Описаный ранее трюк с подключением пакетов перестает работать после установки вышедшего не так давно патча. Установка в среду пакета dclusr становится невозможной, а если он был ранее установлен то последующая его пересборка приведет к тому, что пакет из среды будет удален. Но есть решение: установить данный пакет до установки патча, код загрузки с прямым указанием загружаемых пакетов заменить на чтение списка пакетов из файла. После чего установить патч и не изменять dclusr.

четверг, сентября 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

Багафича, даже две...

На оператор класса Implicit (другие не пробовал) не действует директива Inline. Все условия для Inline соблюдены, но тело оператора не разворачивается в код :( И еще об Implicit: не удается добиться работоспособности данного оператора при декларировании с типами Double и TDateTime. Типы по описанию не идентичные, но компилятор, так, видимо, не считает... Поэтому, если описать неявное преобразование в Double, будет допустимо присваивание значения типа TDateTime, но при этом, разумеется, будет вызван метод Implicit для типа Double. Если же описать неявное преобразование для них обоих, будет потеряна всякая возможность присваивания значений данных типов. Такое вот, хреновое лето...

среда, сентября 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 возвращается!

Сегодня стала доступна для скачивания TurboDelphi! Ура, товарищи! Уже заказал CD, поглядим через пару неделек :)

пятница, августа 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 (я во всяком случае не нашел) эта изумительная вещица работает! Простейший пример иллюстрирует всю прелесть данной конструкции:

 Type
  TRectHelper = 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.