D (język programowania)

język programowania

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[potrzebny przypis]. Pierwsza stabilna wersja języka ukazała się 2 stycznia 2007 roku[1]. 17 czerwca 2007 roku opublikowano eksperymentalną wersję 2.0[2].

D
Logo języka D
Logo języka
Pojawienie się

2007

Paradygmat

wieloparadygmatowy

Typowanie

statyczne (silne)

Implementacje

Digital Mars D, LLVM, GCC

Aktualna wersja stabilna

2.109.1
(1 lipca 2024) [±]

Twórca

Walter Bright

Platforma sprzętowa

wieloplatformowy

Platforma systemowa

wieloplatformowy

Strona internetowa

Możliwości

edytuj

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 ze 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

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

Programowanie imperatywne

edytuj

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

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

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 statycznej instrukcji „if”, instrukcji wykonywanej w trakcie kompilacji, do obliczania wartości silni:

template Factorial(static 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

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

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.

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

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[3]
  • 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[4]

Narzędzia programistyczne

edytuj

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

  • Wtyczki Eclipse dla języka D obejmują: DDT[7], oraz Descent (projekt już nie rozwijany)[8].
  • Integracja z Visual Studio jest oferowana przez VisualD[9].
  • Vim obsługuje kolorowanie składni oraz uzupełnianie kodu (przez załatane Ctags).
  • Pakiet jest dostępny dla TextMate, i IDE Code::Blocks oferuje częściową obsługę 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.[10]
  • Wtyczka dla MonoDevelop jest dostępna, o nazwie Mono-D.[11]

Ponadto, powstają otwarte środowiska napisane w całości w D (np. Poseidon[12], D-IDE[13] i Entice Designer[14]), 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

Dwie biblioteki standardowe

edytuj

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ą).

Przykładowy program

edytuj

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;
}

Przypisy

edytuj
  1. D 1.0 changelog (older versions). [dostęp 2009-01-03]. (ang.).
  2. D 2.0 changelog. [dostęp 2009-01-03]. (ang.).
  3. GDC – D Programming Language for GCC [online], gdcproject.org [dostęp 2021-04-15].
  4. http://www.infoq.com/news/2009/05/D-Source.
  5. Zeus.
  6. Wiki4D – Editor Support. [dostęp 2010-07-03].
  7. DDT.
  8. Descent.
  9. VisualD.
  10. D for Xcode.
  11. Mono-D.
  12. Poseidon.
  13. D-IDE.
  14. Entice Designer.

Linki zewnętrzne

edytuj
  NODES
Bugs 1
INTERN 1
Project 1