czwartek, 10 grudnia 2009

Serializacja klas cz1. cz.2 i cz.3

Zbiór 3 artykułów o serializacji klas w Delphi mojego autorstwa bazujący na mechanizmach używanych przez VCL. Obecnie (od Delphi 2010) serializacja jest możliwa w dużo bardziej prosty i oczywisty sposób o którym postaram się wkrótce napisać, jednak warto poznać ta "Old Schoolową" technikę. Wrzucam wszystkie 3 części:

najważniejsze procedury z dtxUtils używane w dalszym kodzie, bardzo przydatne podczas serializacji klas w Delphi
function ComponentToString(Component: TComponent): string;
var
BinStream:TMemoryStream;
StrStream: TStringStream;
s: string;
begin
BinStream := TMemoryStream.Create;
try
StrStream := TStringStream.Create(s);
try
BinStream.WriteComponent(Component);
BinStream.Seek(0, soFromBeginning);
ObjectBinaryToText(BinStream, StrStream);
StrStream.Seek(0, soFromBeginning);
Result:= StrStream.DataString;
finally
StrStream.Free;

end;
finally
BinStream.Free
end;
end;

procedure StringToComponent(Value: string; Comp: TComponent);
var
StrStream:TStringStream;
BinStream: TMemoryStream;
begin
StrStream := TStringStream.Create(Value);
try
BinStream := TMemoryStream.Create;
try
ObjectTextToBinary(StrStream, BinStream);
BinStream.Seek(0, soFromBeginning);
BinStream.ReadComponent(Comp);
finally
BinStream.Free;
end;
finally
StrStream.Free;
end;
end;

{$WARNINGS OFF}
procedure SaveComponent(AFile: string; AComponent: TComponent;
AText: boolean = true);
var
f: TFileStream;
m: TMemoryStream;
begin
if AText then
try
m := TMemoryStream.Create;
m.WriteComponent(AComponent);
m.Seek(0, soFromBeginning);

f := TFileStream.Create(AFile, fmCreate);
ObjectBinaryToText(m, f);
finally
m.Free;
f.Free;
end else
try
f := TFileStream.Create(AFile, fmCreate);
f.WriteComponent(AComponent);
finally
f.Free;
end;
end;
{$WARNINGS ON}

{$WARNINGS OFF}
procedure LoadComponent(AFile: string; AComponent: TComponent;
AText: boolean = true);
var
f: TFileStream;
m: TMemoryStream;
begin
if AText then
try
f := TFileStream.Create(AFile, fmOpenRead);
m := TMemoryStream.Create;

ObjectTextToBinary(f, m);
m.Seek(0, soFromBeginning);
m.ReadComponent(AComponent);
finally
m.Free;
f.Free;
end else
try
f := TFileStream.Create(AFile, fmOpenRead);
f.ReadComponent(AComponent);
finally
f.Free;
end;
end;
{$WARNINGS ON}


Część 1

(*******************************************************************************
Serializacja klas w Delphi cz.1

DaThoX 2004-2008

Maciej Izak (hnb.code[at]gmail[dot]com)


Serializacja – w programowaniu komputerów proces przekształcania obiektów,
tj. instancji określonych klas, do postaci szeregowej, czyli w strumień
bajtów, z zachowaniem aktualnego stanu obiektu. Serializowany obiekt może
zostać utrwalony w pliku dyskowym, przesłany do innego procesu lub innego
komputera poprzez sieć. Procesem odwrotnym do serializacji jest
deserializacja. Proces ten polega na odczytaniu wcześniej zapisanego
strumienia danych i odtworzeniu na tej podstawie obiektu klasy wraz z jego
stanem bezpośrednio sprzed serializacji.

Powyższa definicja pochodzi z wikipedii
(http://pl.wikipedia.org/wiki/Serializacja)

Serjalizacja w Delphi wygląda dużo bardziej estetycznie niż w innych językach
i moim zdaniem jest znacznie prostsza. Zresztą nie bedę się zbytnio rozpisywał
:) - przejdźmy do kodu

(******************************************************************************)

program Lesson_01;

{$APPTYPE CONSOLE}

uses
SysUtils,
Classes, // <- podstawowe klasy z których bedziemy dziedziczyć
Dialogs,
dtxUtils // <- napisałem procedury ułatwiające serializację klas
;

{-------------------------------------------------------------------------------
Generalnie sprawa jest prosta. Każda klasa którą chcemy zapisywać do pliku musi
dziedziczyć z TComponent. Oczywiście jeśli posiadamy odpowiednio duża wiedzę
możemy się pokusić o napisanie własnych klas do zapisu klas do pliku ale po co?

TComponent jest świetną klasą, zwartą i dzielącą/łączącą wszystko w jedną całość.
Możemy przyjąć że TComponent to Np. TGracz
{------------------------------------------------------------------------------}

type
// wrsja gracza 1 :) - później omówimy kolejne możliwości serializacji
// i nie chcę by ten tutek stracił czytelność
TPlayer1 = class(TComponent)
private
FName: string; // nazwa
FRememberPasswd: boolean; // możemy nie chcieć zapamiętywać hasła do pliku
//by go ktoś nie przechwycił
FPasswd: string; // hasło
public
// ---
protected
// ---
published
// zapis odbywa się dzięki property
property Name: string read FName write FName;
// kolejność property ma OGROMNE znaczenie. Przypuśćmy że pole
//
// property RememberPasswd
//
// byłoby za
//
// property Passwd
//
// wtedy zawartość Passwd mogłaby zostać nie wczytana ponieważ na końcu jej
// deklaracji mamy dyrektywę "stored" i nazwę pola "FRememberPasswd" co
// oznacza:
//
// "zainicjalizuj właściwość Passwd tylko jeśli pole FRememberPasswd
// ma wartość true"
//
// !!!oczywiście za stored możemy umieśćić funkcję (która zostanie wywołana
// podczas odczytu/zapisu)!!!
//
// Z tego wniosek, że za późno zinicjalizowalibyśmy wartość pola
// FRememberPasswd i przez to nie wczytalli hasła :(
property RememberPasswd: boolean read FRememberPasswd write FRememberPasswd;
property Passwd: string read FPasswd write FPasswd stored FRememberPasswd;
end;

{-------------------------------------------------------------------------------
Zaletą serializacji klas w delphi jest to że struktura klasy może się
!zmieniać! co w przypadku plików binarnych niosłoby ze sobą szereg zmian.

ZALETĄ zapisu przez property jest fakt że możemy za read/write wstawić metody
odczytu i zapisu co w połączeniu ze stored daje nam ogromne mozliwości!
{------------------------------------------------------------------------------}

{-------------------------------------------------------------------------------
Na chwilę obecną zanim omówimy bardziej zaawansowane aspekty serializacji w
Delphi sprawdźmy czy faktycznie działa...
{------------------------------------------------------------------------------}

var
Player: TPlayer1;
c: char;
begin
Player := TPlayer1.Create(nil);

Write('Podaj swoj nick : ');
ReadLn(Player.FName);

Write('Podaj haslo : ');
ReadLn(Player.FPasswd);

Write('Zapamietac twoje haslo na pozniej (T/N)? : ');
ReadLn(c);
Player.FRememberPasswd := UpCase(c) = 'T';

// przekształcamy obiekt w tekst :)
// zapisem zajmiemy się w nastepnej części
WriteLn(sLineBreak,

ComponentToString(Player)

);

// zakończ ...
ReadLn;
Player.Free;
end.


Część 2

(*******************************************************************************
Serializacja klas w Delphi cz.2

DaThoX 2004-2008

Maciej Izak (hnb.code[at]gmail[dot]com)

Na dzisiejszej lekcji zajmiemy się obsługą zapisu przypisanej metody do pola
(Delphi umożliwia zapamiętanie jaką metodę przypisaliśmy polu typu
proceduralnego obiektowego)

Poznamy także procedury umozliwiajace odczyt/zapis klasy z/do pliku
(******************************************************************************)
program Lesson_02;

{$APPTYPE CONSOLE}

uses
SysUtils,
Classes, // <- podstawowe klasy z których bedziemy dziedziczyć
Dialogs,
dtxUtils; // <- napisałem procedury ułatwiające serializację klas
{-------------------------------------------------------------------------------
Na dole w głównym bloku begin ... end. znajduje się opis zapisu i odczytu klas
z jak i do pliku ...

------------------------------------------------------------------------------
/// Funkcje pomocnicze z dtxUtils.pas ///
------------------------------------------------------------------------------

---
1 procedure StringToComponent(Value: string; Comp: TComponent);
---
------------------------------------------------------------------------------
Konwertuje dane z łańcucha znaków na dane do obiektu i inicjalizuje
jego dane. Przekazywana klasa Comp musi być wczesniej stworzona.


---
2 function ComponentToString(Component: TComponent): string;
---
------------------------------------------------------------------------------
Konwertuje komponent na łańcuch


---
3 procedure SaveComponent(AFile: string; AComponent: TComponent;
--- AText: boolean = true);
------------------------------------------------------------------------------
Zapisuje komponent do pliku tekstowego. Parametr AText ustawia czy ma być
to w postaci czytelnej dla człowieka (tekstowej) czy też binarnej.
Wersja binarna zajmuje nieco mniej miejsca.


---
4 procedure LoadComponent(AFile: string; AComponent: TComponent;
--- AText: boolean = true);
------------------------------------------------------------------------------
Robi dokładnie to co SaveComponent tylko w drugą stronę

------------------------------------------------------------------------------
/// Funkcje i typy pomocnicze z "Classes.pas" ///
------------------------------------------------------------------------------

---
1 type
--- TStreamOriginalFormat = (sofUnknown, sofBinary, sofText);
------------------------------------------------------------------------------
Typ mówiący o tym w jakiej postaci zapisaliśmy obiekt (binarna/tekstowa)


---
2 procedure ObjectBinaryToText(Input, Output: TStream); overload;
--- procedure ObjectBinaryToText(Input, Output: TStream;
var OriginalFormat: TStreamOriginalFormat); overload;
procedure ObjectTextToBinary(Input, Output: TStream); overload;
procedure ObjectTextToBinary(Input, Output: TStream;
var OriginalFormat: TStreamOriginalFormat); overload;
------------------------------------------------------------------------------
Funkcje konwertujące obiekt w postaci binarnej do tekstowej (i odwrotnie)
operujące na strumieniach


---
3 procedure ObjectResourceToText(Input, Output: TStream); overload;
--- procedure ObjectResourceToText(Input, Output: TStream;
var OriginalFormat: TStreamOriginalFormat); overload;
procedure ObjectTextToResource(Input, Output: TStream); overload;
procedure ObjectTextToResource(Input, Output: TStream;
var OriginalFormat: TStreamOriginalFormat); overload;
------------------------------------------------------------------------------
Funkcje konwertujące postać tekstową do zasobów i odwrotnie


---
4 function TestStreamFormat(Stream: TStream): TStreamOriginalFormat;
---
------------------------------------------------------------------------------
Funkcja sprawdzająca jakiego typu są dane zserializowanego obiektu

{------------------------------------------------------------------------------}
type
// "typ" naszej procedury
TOnPrint = procedure of object;

// wrsja gracza 2 :) - zawiera wszystko to co zawierała klasa z poprzedniej
// części + mała nowość :)
TPlayer2 = class(TComponent)
private
FName: string;
FRememberPasswd: boolean;
FPasswd: string;
FOnPrint: TOnPrint;
public
// ---
protected
// ---
published
property Name: string read FName write FName;
property RememberPasswd: boolean read FRememberPasswd write FRememberPasswd;
property Passwd: string read FPasswd write FPasswd stored FRememberPasswd;

// tytaj zaczynają się nowości :) ...
procedure OnPrint1; // mamy dwie procedury do wyboru
procedure OnPrint2;

// pole pamiętające nasz wybór (możemy przypisać mu dowolną metodę będacą
// w sekcji published z klasy w której ów właściwość jest zadeklarowana)
property OnPrint: TOnPrint read FOnPrint write FOnPrint;
end;


{ TPlayer2 }

procedure TPlayer2.OnPrint1;
begin
WriteLn('Wywolano OnPrint1');
end;

procedure TPlayer2.OnPrint2;
begin
WriteLn('Wywolano OnPrint2');
end;

var
Player: TPlayer2;
c: char;
{-------------------------------------------------------------------------------
Poniżej są zastosowane procedury zapisu odczytu klas do plików i strumieni.
{------------------------------------------------------------------------------}
begin
Player := TPlayer2.Create(nil);

Write('Ktora metode chcesz przypisac do property OnPrint (1 lub 2) : ');
ReadLn(c);
if c = '1' then
Player.OnPrint := Player.OnPrint1
else
Player.OnPrint := Player.OnPrint2;

// Wywołujemy property :)
WriteLn(sLineBreak, 'Za chwile wywolamy metode zapisana w property OnPrint :');
Player.OnPrint;
WriteLn;

WriteLn('Tak wyglada nasza klasa przerobiona na napis :', sLineBreak, sLineBreak,

ComponentToString(Player)

);

// zapisujemy do pliku
SaveComponent('Player.txt', Player);
// i zwalniamy
Player.Free;

WriteLn(sLineBreak,
'Klasa zostala zapisany do ''Player.txt'' i zwolniona z pamieci. ',
'Mozesz otworzyc zapisany plik i go zmodyfikowac - za chwile klasa TPlayer2 ',
'zostanie utworzona na nowo i wlasnie z ''Player.txt'' zostanie wczytana ',
'zawartosc klasy. Zmodyfikuj plik jak chcesz i wcisnij [ENTER] by ',
'zaincjalizowac klase i wywolac property OnPrint.');
ReadLn;

// tworzymy obiekt od nowa
Player := TPlayer2.Create(nil);
LoadComponent('Player.txt', Player);
WriteLn('Tak wyglada nasza klasa po wczytaniu z pliku :', sLineBreak, sLineBreak,

ComponentToString(Player)

);

// Wywołujemy property :)
WriteLn('Za chwile wywolamy metode zapisana w property OnPrint :');
Player.OnPrint;
WriteLn;

// zakończ ...
ReadLn;
Player.Free;
end.


Część 3

(*******************************************************************************
Serializacja klas w Delphi cz.3

DaThoX 2004-2008

Maciej Izak (hnb.code[at]gmail[dot]com)

Na dzisiejszej lekcji dowiemy się jak wpleść w klasę TComponent inne klasy
nie dziedziczące z TComponent;
(******************************************************************************)

program Lesson_03;

{$APPTYPE CONSOLE}

uses
SysUtils,
Classes, // <- podstawowe klasy z których bedziemy dziedziczyć
Dialogs,
dtxUtils; // <- napisałem procedury ułatwiające serializację klas

type
// nasza klasa która chcemy wpleść. Np. gracz ma samochód :)
//
// musimy dziedziczyć z TPersistent - ona zapisuje z RTTI naszej klasy
// właściwości z sekcji published. Moglibyśmy sami napisać taką klasę ale
// ta jest wystarczająco dobra i nic nie dorzuca do TObject. Czyli zamiast
// dziedziczyć po TObject (TKlasa = class lub TKlasa = class(TObject))
// dziedziczymy z TPersistent TKlasa = class(TPersistent)
TCar = class(TPersistent)
private
FName: string;
FMaxSpeed: single;
public
constructor Create(AName: string; AMaxSpeed: single);
published
property Name: string read FName write FName;
property MaxSpeed: single read FMaxSpeed write FMaxSpeed;
end;

{ TCar }

constructor TCar.Create(AName: string; AMaxSpeed: single);
begin
inherited Create;
FName := AName;
FMaxSpeed := AMaxSpeed;
end;

// wrsja gracza 3 :) -
// NOWOŚĆ :D Jeśli klasa ma włączone RTTI to od razu po class(TComponent)
// mamy do czynienia z sekcją published :)
// NOWOŚĆ 2 :D
// sprawdź blok begin ... end. aplikacji. Jeśli nadamy wartość polu name z
// TComponent nasz obiekt w wersji tekstowej będzie wyglądał inaczej :)...
type
TPlayer3 = class(TComponent)
// tu też jest published !!! tylko ciut inne ;) - omówimy później
//
//
private
FCar: TCar;
public
// musim stworzyć i zniszczyć klasę z pola FCar
constructor Create; reintroduce;
destructor Destroy; override;
published
property Car: TCar read FCar write FCar;
end;

{ TPlayer3 }

constructor TPlayer3.Create;
begin
inherited Create(nil);
FCar := TCar.Create('BMW', 210.6);
end;

destructor TPlayer3.Destroy;
begin
FCar.Free;
inherited;
end;

var
Player: TPlayer3;
c: char;
begin
Player := TPlayer3.Create;

// NADAJEMY Name :D
Player.Name := 'HNB';

WriteLn(

ComponentToString(Player)

);
// zakończ ...
ReadLn;
Player.Free;
end.


Powodzenia :)! Powyżej zaprezentowane lekcje to tylko niewielki wstęp do całego tematu. Zachęcam do samodzielnego poszerzania wiedzy, albo do czekania na kolejne części :).

sobota, 28 listopada 2009

Dyrektywy kompilatora Pascala cz.1 - Symbole predefiniowane

ważne: jeśli dostrzegłeś jakieś braki czekam na komentarz!

Zaczniemy od podstaw - omówimy na początek symbole pre-definiowane, które są podstawą do sprawnej kompilacji warunkowej. Na początek trochę nudów i może dla większości rzeczy oczywistych, jednak spokojnie :). Jeden z artykułów będzie o "białych krukach" wśród dyrektyw.

Symbole pre-definiowane to symbole które zostały zdefiniowane przez kompilator w zależności od przeróżnych okoliczności (np. system operacyjny linux lub windows). Dzięki temu jesteśmy w stanie generować różny kod. Standardowo sami możemy definiować symbole o wymyślonych przez nas nazwach, bądź je usuwać:


{$DEFINE SOME_NAME} // definiujemy symbol o nazwie SOME_NAME
{$UNDEF SOME_NAME} // kasujemy symbol o nazwie SOME_NAME


Zaczniemy rysem historycznym (uwielbiam te nazwy kodowe!). Przytoczę wersje kodowe produktów, cytując artykuł "Delphi History" i wzbogacając go o nowe pozycje (uwzględniając najnowszy "RAD Studio, Delphi and C++Builder Roadmap"):

Project Commodore 2010/2011
Project Delphi "X" 2010
Embarcadero RAD Studio 2010 Weaver 2009
CodeGear C++ Builder 2009 Barracuda 2008
CodeGear RAD Studio 2009 - Unicode Tiburón 2008
CodeGear RAD Studio 2007 Highlander 2007, Sept 5
Chrome 2.0 by RemObjects Joyride 2007, Aug 1
CodeGear C++ Builder 2007 Cogswell 2007, June 5
CodeGear Delphi for PHP Astro 2007, Mar 27
CodeGear Delphi 2007 for Vista and AJAX Spacely 2007, Mar 19
Borland Developer Studio 2006 - W32, .Net, C++ and C# DeXter 2005, Oct 10
Borland Delphi 2005 - C# and Delphi Diamondback 2004, Oct 12
Borland Delphi 8 for .Net Octane 2003, Dec 22
Borland C++BuilderX Tomahawk 2003, Aug 28
Borland C#Builder 1.0 Sidewinder (Galileo IDE 1.0) 2003, Jun 16
Borland Delphi.NET compiler (.Net 1.0) Morpheus 2003
Borland Delphi 7 Aurora 2002, Aug 9
Borland C++ Builder 6.0 Riptide 2002, Feb 1
Borland Delphi 6 Illiad 2001, May 21
Borland C++ Builder 5.0 Rampage 2000, Jan 30
Borland Delphi 5 Argus 1999, Aug 10
Borland Delphi/400 outsourced 1999, Feb
Borland Delphi 4 Allegro 1998, Jun 17
Borland Delphi 3 Ivory 1997, Aug 5
Borland Delphi 2 32bit/Win95 Polaris 1996, Feb 10
Borland Delphi 1 16bit/Win3.x Delphi95, Wasabi, Mango, AppBuilder 1995, Feb 14

i teraz poniżej zobaczmy, jakimi symbolami pre-definiowanymi zostały oznaczone poszczególne wersje, nie tylko Delphi ale i C++ (możliwe jest miksowanie kodu C++ i Delphi), w oparciu o artykuł "Borland Compiler Conditional Defines"


{$DEFINE VER210} // Embarcadero RAD 2010 v14.0
{$DEFINE VER200} // CodeGear Delphi 2009 v12.0
{$DEFINE VER200} // CodeGear C++ Builder 2009 v12.0
{$DEFINE VER190} // CodeGear Delphi 2007 for .NET v11.0
{$DEFINE VER185} // CodeGear Delphi 2007 for Win32 v11.0
{$DEFINE VER180} // CodeGear Delphi 2007 for Win32 v11.0
{$DEFINE VER180} // Borland Developer Studio 2006 v10.0
{$DEFINE VER170} // Borland Delphi 2005 v9.0
{$DEFINE VER160} // Borland Delphi 8 for .NET v8.0
{.$DEFINE ?} // C++BuilderX
{$DEFINE VER160} // Borland C#Builder v1.0
{$DEFINE VER150} // Borland Delphi 7 v7.0
{$DEFINE VER140} // Borland Kylix 3 v3.0
{$DEFINE VER140} // Borland C++Builder 6
{$DEFINE VER140} // Borland Kylix 2 v2.0
{$DEFINE VER140} // Borland Delphi 6 v6.0
{$DEFINE VER140} // Borland Kylix v1.0
{$DEFINE VER130} // Borland C++Builder 5
{$DEFINE VER130} // Borland Delphi 5 v5.0
{$DEFINE VER125} // Borland C++Builder 4
{$DEFINE VER120} // Borland Delphi 4 v4.0
{$DEFINE VER110} // Borland C++Builder 3
{$DEFINE VER100} // Borland Delphi 3 v3.0
{.$DEFINE ?} // Borland C++ 5
{$DEFINE VER93} // Borland C++Builder 1
{$DEFINE VER90} // Borland Delphi 2 v2.0
{.$DEFINE ?} // Borland C++ 4.5
{$DEFINE VER80} // Borland Delphi v1.0
{.$DEFINE ?} // Borland C++ 4
{$DEFINE VER70} // Borland Pascal 7 v7.0
{.$DEFINE ?} // Borland C++ 3.1
{$DEFINE VER70} // Turbo Pascal for Windows 1.5 v1.5
{.$DEFINE ?} // Turbo C++ for DOS 3
{.$DEFINE ?} // Borland C++ 3
{.$DEFINE ?} // Turbo C++ for Windows 3 (Win16)
{.$DEFINE ?} // Turbo Pascal for Windows 1.0 v1.0
{.$DEFINE ?} // Borland C++ 2
{$DEFINE VER60} // Turbo Pascal 6 v6.0
{.$DEFINE ?} // Turbo C++ for DOS
{.$DEFINE ?} // Turbo C for DOS 2
{$DEFINE VER55} // Turbo Pascal 5.5 v5.5
{.$DEFINE ?} // Turbo C for DOS v1.5
{$DEFINE VER50} // Turbo Pascal 5 v5.0
{$DEFINE VER40} // Turbo Pascal 4 v4.0
{.$DEFINE ?} // Turbo C for DOS
{.$DEFINE ?} // Turbo Pascal 3 v3.0
{.$DEFINE ?} // Turbo Pascal 2 v2.0
{.$DEFINE ?} // Turbo Pascal 1 v1.0


Nieźle? :D To nie wszystko. Istnieją także symbole definiowane w zależności od środowiska/warunków/wersji w jakim kod został skompilowany (część z nich można znaleźć na tej oficjalnej stronie).

{$DEFINE CONSOLE} // defioniowana w projektach gdzie została użyta dyrektywa {$APPTYPE CONSOLE}
{$DEFINE CONDITIONALEXPRESSIONS} // definiowane w przypadku gdy możliwe jest testowanie warunków poprzez używanie dyrektywy $IF
{$DEFINE DEBUG} // gdy kompilujemy kod w trybie debugowania
{$DEFINE CPU386} // procesor Intel 386 i późniejszy
{$DEFINE WINDOWS} // używamy Windowsa - definicja "depracted" i zalecane jest używanie MSWINDOWS
{$DEFINE MSWINDOWS} // używamy Windowsa
{$DEFINE WIN32} // Windows 32 bitowy
{$DEFINE WIN64} // Windows 64 bitowy
{$DEFINE LINUX} // Linux
{$DEFINE NOT} // zebezpiecznie kou przed próbami automatycznej modyfikacji na różnych platformach
{$DEFINE MACOSX} // MacOSX! :D (pojawia się w kodzie D2010)
{$DEFINE UNICODE} // Wersja Delphi z unicode
{$DEFINE RTL} // wersja Delphi dla .NET

Zgrzeszyłbym nie przedstawiając pre-definiowanych symboli w FreePascalu. FreePascal posiada szereg swoich własnych symboli nieco odmiennych czy wybrakowanych w stosunku do Delphi, jednak istnieje plik zgrabnie ujednolicający definicje FPC i Delphi (patrz niżej opis pliku jedi.inc). Poniższa lista powstała w oparciu o "Appendix G -
Compiler defines during compilation"
gdzie można odnaleźć bardziej kompletne zestawienie.


{$DEFINE FPC_LINK_DYNAMIC} // Kiedy ustawiliśmy linkowanie dynamiczne
{$DEFINE FPC_LINK_STATIC} // Dla linkowania statycznego (domyślnie)
{$DEFINE FPC_LINK_SMART} // Defioniowane dla "sprytnego linkowania" (ang. smartlinking)
{$DEFINE FPC_CROSSCOMPILING} // Kiedy docelowa platforma jest inna niż ta na któej kompilujemy
{$DEFINE FPC} // Definiowane dla FreePascala
{$DEFINE VER2} // Definiowane dla Free Pascala 2.x.x.
{$DEFINE VER2_0} // Definiowane dla Free Pascala 2.0.x.
{$DEFINE VER2_2} // Definiowane dla Free Pascala 2.2.x.
{$DEFINE FPC_DELPHI} // Free Pascal w "Delphi mode" (dyrektywa $MODE DELPHI)
{$DEFINE FPC_OBJFPC} // Free Pascal w "OBJFPC mode" (dyrektywa $MODE OBJFPC)
{$DEFINE FPC_TP} // Free Pascal w "Turbo Pascal mode" (dyrektywa $MODE TP)
{$DEFINE FPC_GPC} // Free Pascal w "GNU Pascal mode" (dyrektywa $MODE GPC)


Jeszcze więcej o symbolach pre-definiowanych możemy znaleźć w pliku jedi.inc - jest to bardzo użyteczny plik, który po dołączeniu za pomocą dyrektywy


unit Unit1;
{$I jedi.inc}
interface {...}


umożliwia nam łatwiejsze sprawdzanie co/jak/która wersja (np. definiuje DELPHI6_UP - symbol definiowany dla Delphi6 i każdego następnego) . Zachęcam do jego analizy. Jako alternatywy można też użyć pliku GX_CondDefine.inc z pluginu gexperts (informacja pochodzi z tej strony)

New art soon. gl&hf

piątek, 27 listopada 2009

Kolorowa składni i nowy charakter bloga

Nowy charakter bloga. Od dzisiaj poza newsami będę wrzucał trochę kodu :). Pokolorowane dzięki SyntaxHighlighter i z pomocą wpisu na Carter Cole's Blog

Myślę że kilka osób na to czekało ^^. Z góry dzięki za ewentualne sugestie i propozycja poprawek błędów.



:D

piątek, 3 lipca 2009

Delphi - nowe wrażenia - potęga języka na przestrzeni lat

Dobra na Delphi nie mogę się gniewać bo Delphi jest jak kobieta. Co gorsze trochę kosztuje - podobnie jak płeć piękna.

Założę się, że większość z was nie miała pojęcia o istnieniu wszystkich elementów Object Pascala. Poniżej wymieniłem najistotniejsze zmiany wprowadzone w samym tylko języku od czasów Delphi 6 na przestrzeni około 7 lat:

Delphi 7 "Aurora"
-Rozbudowane możliwości typu variant i odseparowania na osobny unit elementów związanych z typem variantowym do "variants.pas"
-Poszerzone informacje czasu wykonania dla metod klas w zastępstwie sekcji klasy "automated"

Delphi 2005 "Diamondback"
-Pętla "for in do" na wzór foreach z php
-Słowa kluczowe dla bezpieczeństwa kodu czyli oznaczenia experimental
-Łatwe tworzenie tablic dynamicznych
-Procedury / funkcje / metody inline

Delphi 2006 i Delphi 2007 (D2007 naprawia głównie błędy z D2006) "DeXter" i "Spacely"
-Przeciążenia operatorów
-Opisy dla depracted
-Rewelacyjny menager pamięci FastMM, za który autor dostaje do końca życia za darmo nowe wersje Delphi!
-Statyczne metody
-Nieinstancyjne "class property"
-Zmienne statyczne
-Typy wewnątrz definicji klas
-Tworzenie sekcji var/type na przemian z deklarowaniem procedur wewnątrz definicji klas
-Rekordy mogą przyjmować część cech klas (np. metody w rekordach, konstruktory rekordów)
-Pomocnicze regiony w kodzie jak w C#
-Klasy / rekordy pomocnicze
-Słowa kluczowe precyzujące kontekst użycia klas (abstract i sealed)
-Sekcje strict
-Dyrektywa final do metod wirtualnych

Delphi 2009 "Tiburón"
-Matematyka wskaźników na wzór C
-Metody anonimowe
-Używanie klas jako procedur / funkcji związane z metodami anonimowymi
-Typy generyczne i cała infrastruktura języka z tym związana
-Exit działające opcjonalnie jak return w C
-Unicode i infrastruktura języka związana z kodowaniem regionalnym dla typów AnsiString i wsparcie ze strony RTL

Delphi Weaver (w fazie beta)
-Łatwiejsze tworzenie singletonów (statyczne konstruktory)
-Dyrektywa delayed
-Atrybuty
-Rozbudowa RTTI i RTL od RTTI, a z tym wiele ciekawych nowości (np. wywoływanie metod w czasie działania aplikacji - na potrzeby skryptów. Co prawda jest to możliwe znacznie wcześniej jednak technika ta nie jest tak oczywista i jest nieudokumentowana!)

I do wszystkich wersji ;):
-Spora rozbudowa RTL związana z nową składnią


Niech mnie ktoś poprawi jeśli coś przeoczyłem bo pisałem to z głowy. Zabawne jest to jak ludzie krytykują Delphi, nie mając nawet pojęcia o ułamku możliwości i ułatwień jakie w ze sobą niesie. (Delphi jest dla mnie jak pyszne ciasteczko z kawą xD!)

Jest to na chwilę obecną jedyny język tak twardo stojący natywnie a zarazem udostępniający ułatwienia "platformy" .NET, przy czym to Delphi jest prekursorem i wzorcem dla .NET, a nie odwrotnie :)!

PS. Najbardziej bolesne jest to, że jedne z ciekawszych elementów składni (w tym niektóre z tych przedstawione w powyższej liście czy dyrektyw służących optymalizacji są nieudokumentowane! Szczerze to tylko niewielka grupa "wtajemniczonych" programistów Delphi ma szersze pojęcie i niestety aby dowiedzieć się pewnych rzeczy trzeba mieć po prostu szczęście...

Podziękowania dla Force za przypomnienie o sekcjach strict i sugestii o podziale na wersje

czwartek, 21 maja 2009

Delphi X , Delphi Weaver, Delphi 64

Straciłem motywację do pisania postów. Po pierwsze powodem jest niezbyt miły kontakt z CodeGear, a po drugie nie ma nic o darmowym Delphi. Na nieszczęście jest mnóstwo informacji i nowinek o samym Delphi. W związku z brakiem chęci tak tylko skrótowo:

Delphi Waver/Commodore 64 - trwają beta testy nowego Delphi. W wersji rozbudowano RTTI, i lada dzień mają zostać wprowadzone 64 bity. Na beta-testera prawdopodobnie można się jeszcze zapisać pod adresem beta.embarcadero.com

Delphi X - nie chodzi tu o komponent. Ten mroczny tytuł to kodowa nazwa natywnego Delphi dla MacOS X i LinuXa.

Long life Delphi dla kasiastych ludzi i koncernów -,-

żal.pl...

niedziela, 22 marca 2009

Delphi?

Ciągle żyję i pamiętam o blogach. Tylko marność nad marnościami, nie widać na horyzoncie nowego darmowego Delphi. Nie odpisują. Olewają. Po ostatnich kontaktach z CodeGear mam szczerze dość.

Tylko M$ dba o przyszłe pokolenia programistów. Czy CG nie rozumie że nie wspierając młodych tylko na tym traci? -,-

wtorek, 13 stycznia 2009

The Future of the Delphi Compiler

Ostatnio w DN ukazał się ciekawy artykuł pana Nicka Hodgesa odnośnie przyszłości kompilatora Delphi. Przyszłość rysuje się naprawdę kolorowymi barwami :D. Po pierwsze w skrócie w planach jest napisanie kompilatora od nowa, umożliwiając używanie starego dla kompatybilności. Właśnie przez tą kompatybilność składnia Delphi troszeczkę stoi w miejscu. Zresztą co będę pisał - przeczytajcie i oceńcie sami!

http://dn.codegear.com/article/39174


Gorąco zachęcam do lektury.