Delphi 8 .NET - krótkie zestawienie nowości

Adam Boduch

Oficjalnej premiery Delphi 8 jeszcze nie ma (na dzień 20.12.2003), ale pragnę Wam przybliżyć pobieżnie nowe funkcje jakie czekają na Was w nowym Delphi. Artykuł w miarę czasu będzie przeze mnie rozbudowywany, będę dodawał do niego przykłady uzycia nowych funkcji z Delphi 8.

Zmiany generalne

Kompilator i linker przystosowany do .NET

Kompilator oraz linker w Delphi 8 różni się całkowicie od kompilatora z poprzednich wersji Delphi, ale dla nas - projektantów ma to mniejsze znaczenie.

Ważne jest to, że kod nie jest kompilowany od razu na kod maszynowy, lecz na kod pośredni MSIL (ang. Microsoft Intermediate Language). Dzięki temu plik wykonywalny ma bardzo mały rozmiar - ok 16 kB z użyciem bibliotek graficznych (wyświetlanie formularza). Programy nie wykorzystujące bibliotek graficznych, wyświetlające tekst na konsoli, napisane np. w języku <wiki href="C_sharp">C#</wiki> mają jeszcze mniejszy rozmiar - ok 3 kB.

Kod pośredni jest kompilowany "w locie", przy użyciu JIT (ang. Just-In-Time Compiler).

Rozmiar plików wykonywalnych jest mały dzięki temu, że wszystkie bibliteki potrzebne do działania programu, znajdują się w systemie - w platformie .NET Framework SDK 1.1. Do uruchomienia programu wymagane jest więc zainstalowanie tej platformy.

Format aplikacji wykonywalnych

Format plików wykonywalnych nosi nazwę PE (ang. Portable Executable). W pliku takim znajduje się kod IL oraz tzw. manifest, czyli opis kodu programu. Manifest zawiera opis zmiennych użytych w programie, typów danych, klas, procedur itp. Korzystając z odpowiedniego oprogramowania Microsoft (które dołączone jest do .NET) możemy odczytać z pliku binarnego informacje na temat kodu źródłowego programu.

CLS

Common Language Specification (CLS) to jedna z najważniejszych części .NET. Jak dotąd każdy język programowania charakteryzował się zupełnie innymi (lub podobnymi) mechanizmami. Platforma .NET dostarcza programiście nowe mechanizmy, zarówno działające na najniższym poziomie systemu, zajmujące się obsługą pamięci itp. Dzięki CLS nie jest ważne w jakim języku programujemy, wykorzystujemy te same mechanizmy. Różnica leży jedynie w składni charakterystycznej dla danego języka. Przykładowo składnia w <wiki href="Visual_Basic">Visual Basic</wiki>.NET różni się i to bardzo od składni C++. Nie jest jednak ważne, w jakim języku piszemy – wykorzystujemy nazwy komend o tej samej nazwie.

Do platformy .NET dołączone zostały także kompilatory języka Visual Basic.NET, C#, <wiki="J_sharp">J#</wiki>. Piszę o tym dlatego, że w .NET jest możliwa pełna współpraca pomiędzy programami niezależnie od tego w jakim języku zostały napisane. Możliwe jest więc wykorzystanie klasy z programu wykonywalnego napisanego w języku C#, w C++ i na odwrót.

Język Delphi

Kompatybilność wsteczna

Dużą zaletą nowego Delphi jest to, że nie powinno być problemów z przeniesieniem aplikacji napisanej pod Win32 na .NET, gdyż Delphi obsługuje także stare elementy języka, z kilkoma wyjątkami.

W Delphi 8 nie istnieje już typ PChar, PAnsiString, PWideString. Teraz wszystkie łańcuchy są typu String. Nie można korzystać także ze wskaźników i paru innych elementów języka (napisałem o tym we wskazówce, w FAQ), gdyż takie elementy są uważane z niebezpieczne (ang. unsafe).

Istnieje jednak możliwość na ominięcie tego umieszczając wszystkie elementy "niebezpieczne" w jednej procedurze i opatrzając ja dyrektywą UNSAFE.

Klasy

Borland wiele zmian wprowadził w wykorzystaniu <wiki href="klasa">klas</wiki> w Delphi. Ciekawostką są typy zagnieżdżone, które umożliwiają deklarację klas w klasach:

type
  TFiat = class
    procedure Jedz; virtual;

    type
      TMaluch = class
        procedure Jedz;
      end;
  end;

Możliwe jest również wykorzystanie klas bez korzystania z konstruktora - np.

var
  Maluch : TFiat.TMaluch;
beign
  Maluch.Jedz; // dobrze!
end;

Taki zapis jest prawidłowy dopóki nie korzystamy w klasie ze zmiennych - wówczas program "wysypie" się...

W niektórych przypadkach nie jest konieczne deklarowanie nawet zmiennej wskazującej na klasę - np.

TFiat.TMaluch.Jedz; // dobrze!

W takim wypadku należy zadeklarować metodę lub zmienną z użyciem słowa kluczowego class:

  ...
  class procedure Jedz;
  ...

W związku z przystosowaniem Delphi do .NET, obowiązują także nowe poziomy dostępu do klasy - strict private oraz strict protected, które bardziej surowo traktują dostęp do klasy. Przykładowo metody oraz pola zadeklarowane w sekcji strict private nie są widoczne dla innych klas i procedur nawet znajdujących się w tym samym module.

W Delphi 8 dochodzi również możliwość deklarowania pól z użyciem słów kluczowych var oraz </i>const</i> - np.

  type
    TKlasa = class
       var I : Integer;
       const S  = 'Delphi';
      procedura Moja;
   end;
Inherited

Delphi 8 wymaga, aby w konstruktor klas umieszczać słowo kluczowe inherited (co nie było konieczne w środowisku Win32). Zwyczajnie jest to wymóg .NET, aby przed dostępem do członków danej klasy, wywoływać konstruktor klasy bazowej. W tym celu Twój konstruktor powinien wyglądać zawsze tak:

constructor TFiat.Create;
begin
  inherited Create;
  { kod }
end;

Zawsze najlepiej obok samego słówka inherited dodawać nazwę metody – w tym wypadku Create. Może się bowiem zdarzyć, że nasz konstruktor będzie miał inną nazwę, niż konstruktor w klasie bazowej:

constructor TFiat.CreateMain;
begin
  inherited Create;
  { kod }
end;

W takim przypadku niewystarczające jest samo słowo kluczowe inherited.

Jeżeli konstruktor nie zawiera słowa kluczowego inherited, kompilator wskaże błąd: [Error] WinForm2.pas(108): 'Self' is uninitialized. An inherited constructor must be called.

Class helpers

Kolejną innowacją wprowadzoną w Delphi 8 jest mechanizm class helpers umożliwiający rozszerzenie funkcjonalności danej klasy bez konieczności dziedziczenia z niej, czy jakiejkolwiek zmiany w jej kodzie.

Mechanizm class helpers charakteryzuje się specyficzną konstrukcją:

  TFiat = class
    KM : Integer;
  end;

  TFiatHelper = class helper for TFiat
    procedure Jedz;
  end;

Przykład ten prezentuje stworzenie klasy TFiatHelper, która prezentuje właśnie mechanizm class helpers, czyli rozszerzenie funkcjonalności klasy TFiat. Oto schemat budowy takiej klasy:

NazwaKlasy = class helpers for [KlasaBazowa];
end;

Zwyczajnie w miejsce [KlasaBazowa] należy wstawić nazwę klasy, którą chcemy „rozszerzyć” Same dodawanie metod i właściwości odbywa się w ten sam sposób, co w zwykłej klasie. Spójrz na procedurę Jedz z klasy TFiatHelper:

procedure TFiatHelper.Jedz;
begin
  KM := 25;
  MessageBox.Show(Convert.ToString(KM));
end;

Zwróć uwagę, ze możemy się bez problemu odwołać do właściwości znajdującej się w klasie TFiat (właściwość KM).
Dzięki class helpers możesz odwołać się do metody Jedz (która znajduje się w klasie TFiatHelper) z klasy TFiat:

var
  Fiat : TFiat;
begin
  Fiat := TFiat.Create;
  Fiat.Jedz;
end;

Uwaga! Z pozoru dla class helpers nie istotne są sekcje klasy bazowej. Przykładowo, jeżeli zmienna KM znajdzie się w sekcji strict private to i tak program zostanie skompilowany, lecz w trakcie działania taki kod spowoduje pojawienie się błędu. Podsumowując: metody i pola w klasie bazowej nie mogą znajdować się w sekcji strict private oraz strict protected jeżeli class helpers ma mieć do nich dostęp.

Wszystko jest klasą!

Należy zaznaczyć, że VCL został przystosowany do .NET w ten sposób, aby łatwa była migracja aplikacji do nowego środowiska. Przykładem może być klasa TObject, która od tej pory wskazuje na obiekt System.Object.
Piszę o tym aby uświadomić Czytelnika, że w .NET jest w pełni obiektowy jednak jego struktura umożliwia w wielu przypadkach wykorzystanie obiektów bez wywoływania konstruktorów. W ten sposób np. wszystkie typy zmiennych o których wspominałem wcześniej są klasami. Warto w tym momencie wspomnieć chociażby o typie String, który w rzeczywistości wskazuje na klasę System.String. Tak samo jest z typem Integer (wskazuje na klasę System.Int32) itd. Istnieją oczywiście wyjątki jak np. typ AnsiString, który został zachowany w Delphi ze względów kompatybilności.

Namespace

W .NET wprowadzono nowy dostęp do modułów oraz klas z użyciem operatora . (kropka) - np. System.Windows.Forms.Form; W .NET klasy - w przeciwieństwie do VCL nie zaczynają się od litery T.

Podstawową klasą w .NET jest System.Object (w Delphi synonim TObject).

Rekordy

Możliwe jest teraz deklarowanie metod (!) w rekordach:

  TRecord = record
    X, Y : Integer;
    procedure Main;
  end;

Definicja <wiki href="metoda">metod</wiki> w rekordach wygląda tak samo jak w klasach. Nie istnieje natomiast możliwość dziedziczenia klas, przedefiniowania metod. Dodatkowo wszystkie metody w rekordach są statyczne.

Należy zwrócić uwagę, że nie jest możliwe jawne wywołanie konstruktora w rekordzie. Oczywiście – istnieje możliwość jego deklaracji, ale jego wywołanie następuje automatycznie w momencie skorzystania z metody w rekordzie.
Deklaracja konstruktora musi nastąpić z użyciem słowa kluczowego class, tak jak poniżej:

type
  TRecord = record
    X, Y : Integer;
    procedure Main;
    class constructor Create;
  end;

Jeżeli nie użyjesz słowa kluczowego class, Dlephi wyświetli bład: [Error] Uni1.pas(110): Parameterless constructors not allowed on record types.

{ TRecord }

class constructor TRecord.Create;
begin
  MessageBox.Show('Rozpoczynam używanie rekordu TRecord...');
end;

Konstruktor w rekordzie nie może być wywołany jawnie. Jest on wywoływany automatycznie po pierwszym użyciu metody z rekordu.

Uwaga! W rekordzie nie mogą znajdować się destruktory.

Pozostałe (jeszcze nie opisane)
  • Przeładowanie operatorów
  • Deklarowanie atrybutów
  • Różnice w imporcie bibliotek DLL

Microsoft .NET

FCL

Platforma .NET udostępnia ponad 4500 klas nazwanych Fundation Class Library. W ich skład wchodzą klasy do obsługi wyrażeń regularnych, kryptografii, parsera XML, dostępu do baz danych, obsługi <wiki href="gniazdka">gniazdek</wiki> i różnych protofkołów itp...

WinForms

W skład FCL wchodzi Windows Forms (w skrócie WinForms, czyli biblioteka klas do projektowania wizualnego. Zwiera podstawoawe kontrolki Windows takie jak formualrze, etykiety, przyciski itp...

Wykorzystanie WinForms daje niestety nieco inne spojrzenie na kod. Programowanie trochę różni się od standardowego programowanie w VCL, więc programiści wychowani na VCL będą mieli troche problemów ze zmianą.

Przykładowy kod formularza w WinForms, jaki zostaje wygenerowany przy utworzeniu nowego projektu wygląda tak:

unit WinForm2;

interface

uses
  System.Drawing, System.Collections, System.ComponentModel,
  System.Windows.Forms, System.Data;

type
  TWinForm2 = class(System.Windows.Forms.Form)
  {$REGION 'Designer Managed Code'}
  strict private
    /// <summary>
    /// Required designer variable.
    /// </summary>
    Components: System.ComponentModel.Container;
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    procedure InitializeComponent;
  {$ENDREGION}
  strict protected
    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    procedure Dispose(Disposing: Boolean); override;
  private
    { Private Declarations }
  public
    constructor Create;
  end;

  [assembly: RuntimeRequiredAttribute(TypeOf(TWinForm2))]

implementation

{$REGION 'Windows Form Designer generated code'}
/// <summary>
/// Required method for Designer support -- do not modify
/// the contents of this method with the code editor.
/// </summary>
procedure TWinForm2.InitializeComponent;
begin
  Self.Components := System.ComponentModel.Container.Create;
  Self.Size := System.Drawing.Size.Create(300, 300);
  Self.Text := 'WinForm2';
end;
{$ENDREGION}

procedure TWinForm2.Dispose(Disposing: Boolean);
begin
  if Disposing then
  begin
    if Components <> nil then
      Components.Dispose();
  end;
  inherited Dispose(Disposing);
end;

constructor TWinForm2.Create;
begin
  inherited Create;
  //
  // Required for Windows Form Designer support
  //
  InitializeComponent;
  //
  // TODO: Add any constructor code after InitializeComponent call
  //
end;

end.
Aplikacje międzyplatformowe

Idea .NET, kod pośredni daje możliwość uruchamiania aplikacji .NET dla innych platform - np. na palmtopach.

VCL.NET

Na szczęście w Delphi 8 nie zabrakło VCL (teraz nazwane VCL.NET) tak więc mamy do wyboru dwa środowiska wizualnego projektowania aplikacji: WinForms oraz VCL.NET. VCL.NET na pewno będzie dobrym rozwiązaniem na początek dla programistów, którzy wcześniej go wykorzystywali. Ciężko jest albowiem przenieść apikacje napisane we wcześniejszych wersjach Delphi (w VCL) na Delphi 8 z wykorzystaniem Windows Forms. Jedyną alternatywą jest przeniesienie programu na VCL.NET.

Jeżeli chodzi o VCL.NET nie ma tu żadnego zaskoczenia - nadal obecvne są wszystkie kontrolki, z którymi miałeś okazję spotkać się w przeszłości.

Zaletą nowego Delphi 8 jest to, że możemy pisać programy wykorzystując zarówno VCL.NET jak i WinForms. Np. jeden formularz może być zaprojektowany z użyciem VCL.NET, a drugi w WinForms. Wadą takiego rozwiązania jest większy rozmiar aplikacji wykonywalnej.

Uwaga! "Czysta" aplikacja napisana w VCL.NET (tylko formularz) po skompilowaniu ma rozmiar aż 1,2 MB, więc warte jest przemyślenia programowanie w WinForms.

IDE

  • Zmieniony wygląd IDE. Możliwy jest jednak powrót do starego IDE, znanego z poprzednich wersji Delphi
  • Zmiany w wyglądzie Inspektora Obiektów
  • Tools Palette (nowa wersja palety narzędzi)
  • Makra
  • Możliwośc ukrywania częsci kodu w edytorze kodu
  • Okno Code Snippets umożliwiające szybkie wstawianie gotowych fragmentów kodu
  • Okienko Welcome Page
  • Ulepszony debugger
  • Zmienione/dodane opcje edytora i środowiska
  • Zmienione/dodane opcje projektu
  • Nowe paski narzędzi upraszczające manipulowanie komponentami na formularzu
  • Edytor WYSIWYG
  • Obsługa ASP.NET
  • Project Manager, nowe zakladki Data Explorer oraz Model View
  • Niewizualne komponenty Windows Forms oraz WebForms sa umieszczone na specjalnym podajniku pod formularzem (tray)

Pozostałe

  • Bazy danych ADO.NET
  • Możliwość tworzenia aplikacji ASP.NET, WebForms
  • Usługi sieciowe, wsparcie dla XML, SOAP

Podsumowanie

Wydaje mi się że Delphi 8 jest dobrym produktem aczkolwiek rewolucyjnym przez to, że jest przystosowany do .NET a to wiąże się z wieloma zmianami w samym języku. Może się to wiązać z trudnościami w przyswojeniu nowego środowiska, ale jestem dobrej mysli. Chociaż .NET to przyszłość, ale badania pokazują, że coraz więcej ludzi interesuje się tą platformą. Szkoda, że na razie Microsoft nie planuje wypuszczenia .NET dla Linuxa aczkolwiek trwają pracę nad kompilatorem C# pod Linuxa i ogólnie - środowiskiem .NET na platformy typu UNIX/Linux.

Duże perspektywy w programowaniu dają usługi sieciowe oraz możliwość integracji między poszczególnymi aplikacjami. Microsoft zapowiada, że Windows.NET (nazwa kodowa Longhorn) nie zostanie wypuszczony przed rokiem 2006, wiec pozostaje jeszcze sporo czasu w przystosowaniu się do nowej platformy, nowych warunków do czasu, aż .NET będzie wpełni obsługiwany...

18 komentarzy

Nie ma sie czemu dziwic skoro Microsoft jest posiadaczem części akcji Borlanda, pytanie tylko czy nam wyjdzie to na dobre? Bo Microsoftowi na pewno.

Metody w rekordach... to mi się podoba.. wreszcie będę mógł nazywać funkcje wieloma nazwami, a jest mi to często potrzebne :)

Dokument dotyczacy migracji aplikacji z Win32 do .NET mozna znalezc w dziale Dokumentacja.

Taka ciekawostka: źródła popularnej gry Quake II zostały przerobione na .NET - teraz jest to Quake II .NET :)

Tak Vogel, ale tu chodzilo mi w kontekście typów zagnieżdżonych. Może źle się wyraziłem.

Najpierw kilka uwag merytorycznych (sztuk 1):

W niektórych przypadkach nie jest konieczne deklarowanie nawet zmiennej wskazującej na klasę - np.

TFiat.TMaluch.Jedz; // dobrze!

W takim wypadku należy zadeklarować metodę lub zmienną z użyciem słowa kluczowego class:

...
class procedure Jedz;
...

Adam, wstydź się!!! Przecież to w Delphi istnieje od dawna...

Teraz kilka uwag do samego Delphi 8:

  • przeładowanie operatorów

Nareszcie! Po latach oczekiwania w końcu nadeszła ta chwila.. Wreszcie wzięli przykład z C++ oraz FPC/GPC/TMT Pascal

  • Możliwość ukrywania częsci kodu w edytorze kodu
    [BTW: Możliwość, nie możliwośc]

Nareszcie!!

A co to samej idei .NET'u - no cóż, jakby nie patrzeć jest to regularna Java :)

Jeżeli .NET się upowszechni, to ja kończę z programowaniem i idę zbierać truskawki...

Ja osobiscie widzialem w dzialaniu te gowno microsoftu .net To jest koszmar!!!!!!!! Niewiem kto bedzie w tym cokolwiek pisal. Zawsze bylo ze kazdy jezyk mial swoje wady i zalety. Sam loncze jezyki. np: exe-k napisany w c++, dll w delphi, wstawki w asemblerze itp. itp. Ale to co zrobil microsoft to poprostu siasc i plakac plakac brak mi slow...... w tym nieda sie napisac niczego wiencej niz prostej aplikacji "Hello Word" naprawde..... jesli to odniesie sukces taki jaki odniusl winshit to ja juz niewiem........

Wiesz... zawsze mozna bylo stosowac rzutowanie PChar(String)... nie ma PChara, niejako dlatego, ze ten typ ma cos wspolnego ze wskaznikami...

Mozna stosowac ten typ oznaczajac procedure, w ktorej sie znajduje jako UNSAFE.

Wszystko fajnie, jest tylko jeden szkopuł: MICROSOFT........ Gdyby te innowacje językowe (głównie w zakresie klas i rekordów) były w ZWYKŁYM Delphi, to bym się bardzo ucieszył. Ale tegom Octane nie mam zamiaru tknąć nawet dwumetrowym kijem..... Może są jakieś szanse na następną wersję zwykłego Delphi?

no rzeczywiście krótkie zestawienie cech :D

Źle się wyraziłem. Trzeba wywalić słówko "teraz" ;)

[quote]Format plików wykonywalnych nosi teraz nazwę PE (ang. Portable Executable).[/quote]
Wszystkie pliki wykonywalne w systemie Windows mają format PE.

[quote]Możliwe jest teraz deklarowanie metod (!) w rekordach[/quote]
Hehe - przypomina mi się hasło Apple gdy M$ wprowadzało Win95 (i w końcu długie nazwy plików) - coś w ten deseń: "MS 95 - Apple 86". A nawiązuję do tego, bo już od dawna używam metod czy konstruktorów w strukturach (odpowiednik rekordów w C++).

A tak w ogóle, to cały kod, dołączanie bibliotek i różne szczególiki jak np. zagnieżdżone klasy ogromnie przypomina (nielubianą przeze mnie) Javę.

Ja nie mogę, trochę tego nazmieniali.

Cóż, były plany powstania Delphi 8 for Win32, ale szanse są nikłe. I jest tylko Delphi 8 for .NET.

Strasznie trudno przenieść gotowe bardziej rozbudowane aplikacjie czy komponenty z poprzednich wersji Delphi. Delphi 8 jest bardzo upożądkowaną wersją, w stosunku do swoich poprzedników. Jest to krok w kierunku uniwersalizacji aplikacji. Jestem jednak sceptyczny co do tego czy "starszym" programistą bedzie się chciało przesiąść na 8. Korzystam z Delphi 7 i do póki nie skończe aktualnie realizowanych projektów nie zamierzam sie przesiąść na Delphi 8.NET.

Jeśli mam być szczery, cieszy mnie tylko jedna rzecz - mianowicie usunięcie zmiennych PChar. Zawsze denerwowało mnie to, że nie można zastosować stringa - StrPCopy i StrPas się kłania...

Z ta przenośnością kodu to nie jest tak do końca ;-) probowałem kilka dni temu przenieść jeden z moich firmowych programów na D8Pro i zaciąłem się np. na typie TOleEnum, nie udalo mi sie tez przekonac D8 do zaimportowania ActiveX'a.... choc postepowalem dokladnie z instrukcja z Helpa ;-) ale coz, jak na razie poswiecilem na zabawy z nowym D8 gora 2 godziny z czego wiekszosc czasu bawilem sie zabawkami w stylu zwijania kodu ;-)
No i w pracy wykorzystywac bede dodaną do D8 Delphi 7 :-) co najmniej do czasu jak nie zaczniemy jakiegoś projektu NETowego i nie zmienie systemu na "pracowym" komputerze :-)
Z tego co widze to Delphi migruje w kierunku rozwiazan z Java 2, tylko patrzec jak w D9 pojawia sie metody statyczne w stylu TApplication.ShowMessage albo cos podobnego ;-) [a moze juz sa?]
Ciekawi mnie tez problem wydajnosci nowej Delphi, z tego co zauwazylem, kod jest zauwazalnie wolniejszy od D7 [logiczne, skoro jest jednak czyms w stylu bcode'u], ale wyglada zdecydowanie lepiej od Java'y. Choc mnie osobiscie Java uzeka bardziej niz Delphi swoim podejsciem do problemu obiektowosci ;-)
Btw. czy tylko ja [dokladniej moja firma ;-)] dostalismy D8 wypalone na CDRkach z naklejonymi nalepkami? Reszta plytek, czyli DB2, MsSQL i D7 jest tloczona, ale te z D8 sa nagrywane :-)