D (język programowania)

Z Wikipedii, wolnej encyklopedii
Skocz do: nawigacja, szukaj
D
Pojawienie się 2007
Paradygmat wieloparadygmatowy
Typowanie statyczne (silne)
Implementacje Digital Mars D, LLVM, GCC
Pochodne {{{pochodne}}}
Aktualna wersja stabilna 1.076/2.062[1][2]
(1 stycznia 2013)
Aktualna wersja testowa {{{wersja testowa}}}
Twórca Walter Bright
Licencja {{{licencja}}}
Platforma sprzętowa wieloplatformowy
Platforma systemowa wieloplatformowy
{{{www}}}

Język Dwieloparadygmatowy język programowania umożliwiający programowanie obiektowe, imperatywne oraz metaprogramowanie. Został opracowany przez Waltera Brighta, twórcę pierwszego natywnego kompilatora C++, Zortech C++. D powstał jako obiektowy następca języka C, jednak w przeciwieństwie do C++ zachowuje ze swoim poprzednikiem jedynie binarną kompatybilność. D posiada wiele cech obecnych w C++, a jego składnia oraz możliwości są wzorowane na Javie, C# oraz Eiffel[potrzebne źródło]. Pierwsza stabilna wersja języka ukazała się 2 stycznia 2007 roku[3]. 17 czerwca 2007 roku opublikowano po raz pierwszy eksperymentalną wersję 2.0[4].

Możliwości[edytuj | edytuj kod]

Język D jest projektowany bardziej z praktycznej, niż z teoretycznej perspektywy. Jego składnia oraz możliwości zostały opracowane na podstawie praktycznych wniosków z użytkowania oraz implementowania C++. Zrezygnowano z wstecznej kompatybilności kodu źródłowego na rzecz przejrzystej, bezkontekstowej gramatyki ułatwiającej tworzenie kompilatorów, a także z niektórych możliwości dostępnych w C++ takich, jak wielokrotne dziedziczenie na rzecz interfejsów i domieszkowania. W zamian wprowadzono wiele nowoczesnych rozwiązań: programowanie kontraktowe, prawdziwe moduły, wbudowane automatyczne zarządzanie pamięcią (przez garbage collector), testy jednostkowe, tablice asocjacyjne, tablice dynamiczne, domknięcia, funkcje anonimowe, funkcje zagnieżdżone, klasy wewnętrzne, leniwe wartościowanie oraz zintegrowany z kompilatorem system dokumentacji ddoc. Oprócz tego całkowicie przeprojektowano mechanizm szablonów. Utrzymana została możliwość tworzenia niskopoziomowego kodu oraz umieszczania wstawek asemblerowych.

Paradygmaty programowania[edytuj | edytuj kod]

D wspiera trzy główne paradygmaty programowania: imperatywne, obiektowe oraz metaprogramowanie.

Programowanie imperatywne[edytuj | edytuj kod]

Programowanie imperatywne wygląda niemal identycznie, jak w C. Dostępne są klasyczne pętle, instrukcje warunkowe, funkcje, zmienne lokalne i globalne oraz wyrażenia, które działają identycznie, jak w pierwowzorze, a programy mają bezpośredni dostęp do biblioteki standardowej C. Ponadto wprowadzone zostały dwa rozszerzenia w postaci instrukcji foreach do iterowania po kolekcjach oraz funkcji zagnieżdżonych, które mają dostęp do zmiennych lokalnych funkcji nadrzędnej.

Programowanie obiektowe[edytuj | edytuj kod]

Klasy w D tworzą pojedynczą hierarchię wywodzącą się z klasy Object. Język nie wspiera wielokrotnego dziedziczenia, proponując w zamian interfejsy w stylu Javy oraz domieszki, które umożliwiają przeniesienie współdzielonej funkcjonalności poza hierarchię klas.

D zmienia również sposób obsługi metod wirtualnych. Domyślnie każda metoda, która nie jest statyczna, prywatna oraz szablonowa, staje się metodą wirtualną. Kompilator analizuje hierarchię klas, określając które metody wirtualne można wywoływać statycznie oraz w jakim kontekście, co pozwala na lepszą optymalizację kodu wynikowego oraz uniknięcie wielu błędów programistycznych.

Metaprogramowanie[edytuj | edytuj kod]

Metaprogramowanie jest wspierane przez kombinację szablonów, wykonywania funkcji w trakcie kompilacji, krotek oraz domieszkowania tekstu. Poniższe przykłady demonstrują niektóre możliwości metaprogramowania w D.

W przeciwieństwie do C++, szablony w D bardziej przypominają funkcje. Poniższy przykład pokazuje wykorzystanie statycznego ifa, instrukcji wykonywanej w trakcie kompilacji, do obliczania wartości silni:

template Factorial(ulong n)
{
    static if(n <= 1)
        const Factorial = 1;
    else
        const Factorial = n * Factorial!(n - 1);
}

Poniżej pokazana jest natomiast klasyczna funkcja, która bardzo przypomina wersję z szablonem:

ulong factorial(ulong n)
{
    if(n <= 1)
        return 1;
    else
        return n * factorial(n - 1);
}

Poniżej pokazane jest wykorzystanie szablonu i funkcji do obliczenia wartości silni w trakcie kompilacji. W języku D nie ma konieczności deklarowania typów stałych, ponieważ mogą one zostać wyliczone z prawej strony wyrażenia.

const fact_7 = Factorial!(7);

Zwykłe funkcje mogą być obliczone w trakcie kompilacji, gdy są użyte w stałych wyrażeniach spełniających określone kryteria.

const fact_9 = factorial(9);

Szablon std.metastrings.Format udostępnia formatowanie tekstu w stylu printf, którego wynik jest wyświetlany podczas kompilacji przez dyrektywę msg.

import std.metastrings;
pragma(msg, Format!("7! = %s", fact_7));
pragma(msg, Format!("9! = %s", fact_9));

Domieszkowanie tekstu w połączeniu z funkcjami wykonywanymi w trakcie kompilacji pozwala na dynamiczne generowanie kodu D podczas kompilowania programu. Może to być wykorzystane do parsowania języków dziedzinowych do kodu D, który następnie jest włączany jako część powstającego programu D.

import FooToD; // hipotetyczny moduł z funkcją tłumaczącą język Foo na D
 
void main()
{
    mixin(fooToD(import("example.foo")));
}

Zarządzanie pamięcią[edytuj | edytuj kod]

Choć D jest kompilowany do kodu maszynowego, zarządzanie pamięcią domyślnie odbywa się za pośrednictwem odśmiecacza pamięci, identycznie jak w językach interpretowanych. Część obiektów może być usuwana natychmiast po znalezieniu się poza zasięgiem. Pomimo tego, programista ma pełną kontrolę nad całym procesem. Dozwolone jest ręczne alokowanie i zwalnianie pamięci poprzez przeciążone operatory new oraz delete lub poprzez zwyczajne wywołanie funkcji malloc() oraz free() z biblioteki standardowej C. Możliwe jest zmienianie zakresów pamięci obserwowanych przez odśmiecacz, wstrzymywanie i wznawianie jego pracy, a także wymuszanie wykonania ogólnego lub pełnego czyszczenia. Dokumentacja podaje przykłady implementacji innych technik zarządzania pamięcią dla sytuacji, w których odśmiecanie nie jest optymalnym rozwiązaniem.

Łączenie z innymi językami[edytuj | edytuj kod]

Język D jest binarnie kompatybilny z C, co pozwala łączyć napisane w nim programy ze wszystkimi bibliotekami C, w tym również z biblioteką standardową tego języka, która jest także częścią biblioteki standardowej D.

Łączenie z kodem C++ nie jest obsługiwane przez wersję 1.0. Eksperymentalna częściowa obsługa pojawiła się w wersji 2.0.

D 2.0[edytuj | edytuj kod]

W czerwcu 2007 roku ukazał się D 2.0, nowa eksperymentalna gałąź języka, która koncentruje się na jego dalszej rozbudowie. Niektóre z nowych wprowadzanych przez nią cech to:

  • Częściowa obsługa interfejsu binarnego C++.
  • Iteracja foreach po wybranym wycinku kolekcji.
  • Obsługa prawdziwych domknięć. W wersji 1.0 domknięcia nie mogą być bezpiecznie zwracane przez funkcje, gdyż skutkuje to utratą dostępu do danych zaalokowanych na stosie.
  • Obsługa funkcji czystych, które nie mają efektów ubocznych: mogą odwoływać się jedynie do niezmiennych danych oraz wywoływać inne funkcje czyste. W połączeniu z prawdziwymi domknięciami daje to pełną obsługę programowania funkcyjnego.
  • Funkcje nothrow.
  • Operacje wektorowe, np. c[] = b[] + a[]; (sumowanie odpowiadających sobie elementów z dwóch tablic) lub b[] *= 3; (pomnożenie każdego elementu tablicy przez 3).
  • Ulepszenia w bibliotece standardowej Phobos.

Implementacje[edytuj | edytuj kod]

Obecne implementacje języka D generują kod maszynowy, aby zapewnić maksymalną wydajność.

Chociaż D cały czas się rozwija, do wersji 1.0 nie są już wprowadzane żadne zmiany, a cały wysiłek koncentruje się na usuwaniu wykrytych błędów. Oficjalny kompilator Waltera Brighta definiuje jednocześnie sam język.

Obecnie rozwijane są cztery kompilatory języka D:

  • DMD - oficjalny kompilator Waltera Brighta. Front-end kompilatora objęty jest zarówno licencją artystyczną, jak i GNU GPL, a jego kod jest rozpowszechniany razem z binariami. Umożliwia to szybkie tworzenie nowych kompilatorów. Dostępne są także źródła back-endu, lecz nie są one objęte żadną otwartą licencją. Kompilator wspiera ograniczoną liczbę systemów operacyjnych oraz platform sprzętowych (w szczególności brakuje obsługi architektury 64-bitowej).
  • GDC - front-end dla kompilatora GCC wykorzystujący kod z DMD. Obecnie jest uznawany za martwy projekt, jednak ostatnio podjęte zostały próby napisania nowego front-endu, który domyślnie wspierać ma eksperymentalną wersję 2.0 języka[5]
  • LDC - front-end dla kompilatora LLVM wykorzystujący kod z DMD. Obsługuje zarówno wersję 1.0, jak i 2.0, a także bibliotekę Tango i platformy 64-bitowe.
  • D Compiler for .NET - eksperymentalny port kompilatora na platformę .NET[6]

Narzędzia programistyczne[edytuj | edytuj kod]

Jest wiele edytorów oraz środowisk IDE które obsługują D, obejmują onę m.in. Eclipse, Microsoft Visual Studio, SlickEdit, Emacs, vim, SciTE, Smultron, TextMate, MonoDevelop, Zeus,[7] i Geany.[8].

  • Wtyczki Eclipse dla języka D obejmują: DDT,[9] oraz Descent (projekt już nie rozwijany).[10]
  • Integracja z Visual Studio jest oferowana przez VisualD.[11]
  • Vim obsługuje kolorowanie składni oraz uzupełnianie kodu (przez załatane Ctags).
  • Pakiet jest destępny dla TextMate, i IDE Code::Blocks oferuje częściową obsługe dla języka.
  • Wtyczka dla Xcode 3 jest dostępna, "D for Xcode", żeby aktywować projekty oparte na D oraz programowanie w języku D.[12]
  • Wtyczka dla MonoDevelop jest dostępna, o nazwię Mono-D.[13]

Ponadto, powstają otwarte środowiska napisane w całości w D (np. Poseidon[14], D-IDE[15] i Entice Designer[16]), które posiadają wszystkie niezbędne opcje i które obsługują Windowsa.

Aplikacje D mogą być analizowane debugerami stworzonymi dla C/C++, np. GDB i WinDbg, lecz z ograniczoną obsługą bardziej zaawansowanych możliwości języka. Pełną obsługę oferuje debuger Ddbg w Windows i może być używany z zewnętrznymi środowiskami programistycznymi lub za pomocą wiersza poleceń. Komercyjny ZeroBUGS dla Linuksa eksperymentalnie obsługuje D oraz posiada własny interfejs użytkownika.

Problemy i kontrowersje[edytuj | edytuj kod]

Dwie biblioteki standardowe[edytuj | edytuj kod]

Biblioteka standardowa D nosi nazwę Phobos. Część programistów ze społeczności D uważa, że jest ona zbyt uproszczona oraz posiada wiele nieścisłości, dlatego rozpoczęli prace nad alternatywną biblioteką Tango. W D 1.0 obie biblioteki są ze sobą wzajemnie niekompatybilne, gdyż używają innych odśmiecaczy pamięci, mechanizmów wielowątkowości itd. Obecność dwóch równie popularnych bibliotek prowadzi do wielu problemów z przenośnością: część pakietów korzysta z Tango, inne z Phobosa.

Problem jest w dużej mierze rozwiązany w D 2.0, w którym powstało jednolite środowisko uruchomieniowe druntime, na które obie biblioteki zostaną przeportowane, dzięki czemu stanie się możliwe ich jednoczesne wykorzystanie. Obecnie (styczeń 2010) Phobos zakończył już proces migracji. W dającej się przewidzieć przyszłości język będzie mieć dwie konkurujące biblioteki standardowe, lecz od wersji 2.0 będą one ze sobą kompatybilne na podstawowym poziomie, oraz współdzielić pewne podstawowe funkcje (np. interfejs tablic asocjacyjnych czy interfejs zarządzania pamięcią).

Nieukończona obsługa bibliotek współdzielonych[edytuj | edytuj kod]

Problem obsługi bibliotek współdzielonych związany jest z działaniem kompilatorów, nie z samym językiem.

Kompilator DMD ma problemy z tworzeniem bibliotek współdzielonych na systemach Unix. Uniksowy format ELF jest wspierany jako rozszerzenie kompilatora GDC. W systemach Windows biblioteki DLL są poprawnie obsługiwane oraz możliwe jest przekazywanie obiektów kontrolowanych przez odśmiecacz pamięci do funkcji C. Występują jednak pewne ograniczenia związane z użyciem obiektów. Związane jest to z mechanizmem automatycznego zarządzania pamięcią, który stosuje D.

W środowisku D istnieje tendencja do kompilowania statycznie całego programu, wraz z optymalizacją globalną oraz międzyproceduralną, co w przypadku bibliotek współdzielonych jest wysoce utrudnione. Kompilator DMD działa bardzo szybko[potrzebne źródło], dlatego równoczesne kompilowanie wielu plików w jednym przebiegu nie stanowi istotnego problemu.

Przykładowy program[edytuj | edytuj kod]

Prosty program wypisujący argumenty, z jakimi został wywołany:

import std.stdio;
int main(char[][] args)
{
   foreach(i, a; args)
      writefln("args[%d] = '%s'", i, a);
   return 0;
}

Linki zewnętrzne[edytuj | edytuj kod]

Zobacz publikację na Wikibooks:
D

Przypisy

  1. Changelog (ang.). W: D Programming Language 1.0 [on-line]. Digital Mars. [dostęp 31 grudnia 2012].
  2. Changelog (ang.). W: D Programming Language 2.0 [on-line]. Digital Mars. [dostęp 31 grudnia 2012].
  3. D 1.0 changelog (older versions) (ang.).
  4. D 2.0 changelog (ang.).
  5. Reaktywacja projektu GDC
  6. http://www.infoq.com/news/2009/05/D-Source
  7. Zeus
  8. Wiki4D - Editor Support. [dostęp 3 July 2010].
  9. DDT
  10. Descent
  11. VisualD
  12. D for Xcode
  13. Mono-D
  14. Poseidon
  15. D-IDE
  16. Entice Designer