Strona używa cookies (ciasteczek). Dowiedz się więcej o celu ich używania i zmianach ustawień. Korzystając ze strony wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.    X

Godny następca C i C++, czyli programowanie w D - cz. 2: Zaczynamy pisać w D

Witam ponownie. W poprzednim wpisie pokrótce opisałem, czym jest D i co zmieniło w porównaniu do C i C++. W drugiej części pokażę, jak to wygląda w praktyce. Opiszę, skąd ściągnąć i jak zainstalować kompilator. Przedstawię też podstawy programowania w D (wpis kieruję do osób, które mają już ogólne pojęcie o programowaniu. Jeżeli chciałbyś nauczyć się D jako pierwszego języka, zapraszam na Wikibooka o D). Do dzieła :)

Z czym to się je?

Jak się zapewne domyślacie, żeby pisać programy, trzeba mieć jakiś kompilator. Oczywiście D nie jest w tym przypadku wyjątkiem. W pierwszej części wymieniłem najważniejsze kompliatory - DMD, GDC, LDC i D Compiler for .NET. Osobiście polecam ten pierwszy. DMD jest kompilatorem oficjalnym i wyznacza standardy dla języka. Korzystając z najnowszej wersji DMD mamy pewność, że nasze programy nie będą odstawać od nich tak, jak Internet Explorer od internetowych ;)

DMD możemy ściągnąć z oficjalnej strony języka D - Digitalmars. Do wyboru jest kilka opcji - wieloplatrormowa paczka .ZIP, windowsowy instalator .EXE i pakiecik .DEB dla Ubuntu. Możemy też zainstalować wersję D1 (1.030 lub 1.057) lub D2 (2.042). Pomimo oznaczenia Alpha proponuję wybrać D 2.0. Działa stabilnie, więc o błędy nie trzeba się martwić. Poza tym większość bibliotek jest już pisanych pod tą wersję, więc za starszą wersję chyba nie opłaca się zabierać.
Tak więc ściągamy i instalujemy wersję 2.042 w pakiecie EXE lub DEB. Jeżeli korzystamy z dystrybucji Linuksa obsługującej inne pakiety, niż DEB, musimy poradzić sobie z archiwum ZIP. Nie jest to zbyt trudne, a instrukcje znajdują się w paczce.

Zaczynamy

Mając świeżo zainstalowany kompilator, możemy przystąpić do pisania. A pierwszym programem, który napiszemy, będzie (tu niestety nikogo nie zaskoczę) Hello World. Otwieramy dowolny edytor tekstu (Domyślne dla KDE i GNOME oferują kolorowanie składni do D. Dla Windowsa możemy ściągnąć np. Notepad++) i piszemy:// Listing 1 import std.stdio; void main() { write("Hello world!"); readln(); }Jak widać, od C trochę się różni. Czym? Od początku:
- import std.stdio; - ta linia bardziej przypomina Javę, niż C/C++. Zamiast plików nagłówkowych mamy podział na pakiety i moduły. pakiet std to biblioteka standardowa zwana Phobos. Zawarty w nim moduł stdio odpowiada za standardowe wejście i wyjście. Niektóre moduły dołączane wraz z językiem znajdują się w pakiecie core (jak np. core.thread).
- void main() - funkcja main nie musi zwracać wartości. Może przyjmować argument typu string[] zawierający wywołania programu.
- write("Hello, world!"); - wypisuje linię tekstu. W C mieliśmy printf(), w D mamy do wyboru cztery funkcje: write(), writeln(), writef(), writefln(). Używamy ich podobnie, jak printf() z C. Funkcje z literami "ln" na końcu dostawiają znak nowego wiersza, zaś funkcje bez "f" (czyli write i writeln) nie biorą pod uwagę formatów (np. %d).
- readln(); - po prostu wczytuje linię tekstu, żeby konsola nam nie zniknęła za wcześnie.
W D możemy również używać biblioteki standardowej języka C. W zasadzie przydaje się to tylko wtedy, gdy moduły D nie mają odpowiednich funkcji (np. funkcja system()). Każdemu plikowi nagłówkowemu C odpowiada moduł std.c.nazwapliku. Np. dla stdlib mamy moduł std.c.stdlib.

Skoro napisaliśmy już kod, czas na kompilację. Kod źródłowy należy zapisać w pliku z rozszerzeniem .d, np. main.d. Program kompilujemy poleceniem dmd:dmd main.dJeżeli nie popełniliśmy żadnych błędów, kompilator nic nie napisze, a nazwa pliku wykonywalnego będzie taka sama, jak pliku źródłowego.

Przy pierwszym programie wspomnę jeszcze o komentarzach. Podobnie jak w C++, mamy do dyspozycji komentarze liniowe (//coś tam) i blokowe (/*coś tam*/). Oprócz tego jest jeszcze jeden nowy typ komentarzy blokowych. Umożliwia on umieszczanie jednego komentarza w drugim: (/+jeden komentarz /+ i drugi wewnątrz +/ tego pierwszego +/).

"Więc chodź, pomaluj mój świat..."

Po pokazaniu, jak wygląda prosty program w D, czas zobaczyć, co to cudeńko potrafi. Spróbujmy przykładowo napisać coś w konsoli na zielono. Kolorowanie tekstu w konsoli jest dostępne zarówno na Windowsie, jak i na systemach Linuksowych. Kłopot w tym, że każdy z systemów robi to inaczej. Linux wykorzystuje sekwencje ucieczki, zaś Windows - odpowiednie funkcje niedostępne pod innymi platformami.
Kompilacja warunkowa to mechanizm, który - w zależności od instrukcji zawartych w kodzie lub flag kompilatora - pozwala na kompilowanie programu w różny sposób. Możemy ją na przykład wykorzystać, by inne instrukcje były wbudowane w build dla Windowsa, a inne w build dla Linuksa. Nasz kod będzie wyglądał tak:// Listing 2 import std.stdio; version(Windows) { import std.c.windows.windows; } void main() { version(Windows) { HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(hOut, FOREGROUND_GREEN); write("Zielono mi! :)"); } else version(linux) { write("\033[32mZielono mi! :)\033[0m"); //]] - inaczej jest błąd w bloku kodu na stronie } else { write("Nie działa na twoim systemie."); } readln(); }Od razu rzucają się w oczy bloki version(Windows) i version(linux). To właśnie one odpowiadają za kompilację pod pewnymi warunkami. W zaprezentowanym kodzie warunkiem jest system operacyjny. Bloki, które nie nie znajdą się w programie (jak np. blok version(linux) na Windowsie) w ogóle nie są brane pod uwagę przez kompilator. Nawet, jeśli zawierają błędy, kompilator ignoruje je. Tak więc ten kod dla kompilatora będzie wyglądał tak:

Na Windowsie:// Listing 3 import std.stdio; import std.c.windows.windows; void main() { HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(hOut, FOREGROUND_GREEN); write("Zielono mi! :)"); readln(); }

Na Linuksie:// Listing 4 import std.stdio; void main() { write("\033[32mZielono mi! :)\033[0m"); //]] - inaczej jest błąd w bloku kodu na stronie readln(); }

I na innych systemach (else działa tak samo, jakby zamiast version było if)// Listing 5 import std.stdio; void main() { write("Nie działa na twoim systemie."); readln(); }

Jeżeli w listingu 1 pominęlibyśmy else w linii "else version(linux)", na Windowsie zobaczymy wyjście:Zielono mi :)Nie działa na twoim systemie. gdzie fragment "Zielono mi :)" będzie w kolorze zielonym.

Szczegółów dotyczących kolorowania wyjścia konsoli na poszczególnych systemach nie będę opisywał, ponieważ artykuł i tak jest już długi. Informacje te można bardzo łatwo znaleźć za pośrednictwem wyszukiwarki.

Kompilacji warunkowej ciąg dalszy

Możliwości kompilacji warunkowej nie kończą się na kompilacji w zależności od systemu. Jako parametr bloku version() możemy podać dowolny identyfikator wersji. Standardowo mamy już zdefiniowane identyfikatory dla systemów operacyjnych, architektur, kolejności bajtów, wersji języka D 2.0... Ponadto możemy definiować własne warunki na dwa sposoby:// Listing 6 ... version(4) // lub inna liczba naturalna { // kod }Ten wariant określa poziom wersji. Do polecenia kompilacji dopisujemy wtedy flagę -version 4, co poskutkuje wkompilowaniem do programu kodu oznaczonego poziomie 4 lub wyższym.// Listing 7 ... version(TwojaWersja) { // kod }W takim wypadku w celu zawarcia tego kodu w programie używamy flagi kompilatora -version TwojaWersja.

Możemy też przyporządkować wersje w kodzie. Załóżmy, że chcemy skompilować program w trzech edycjach - Free, Standard i Pro. Wersje te będą różniły się ilością funkcji. // Listing 8 version(Free) { version = FajnaFunkcja; } version(Standard) { version = FajnaFunkcja; version = BardzoFajnaFunkcja; version = DrugaBardzoFajnaFunkcja; } version(Pro) { version = FajnaFunkcja; version = BardzoFajnaFunkcja; version = DrugaBardzoFajnaFunkcja; version = SuperHiperWypasionaFunkcja; } // Dalsza część kodu version(FajnaFunkcja) { // implementacja } version(BardzoFajnaFunkcja) { // implementacja } version(DrugaBardzoFajnaFunkcja) { // implementacja } version(SuperHiperWypasionaFunkcja) { // implementacja }Teraz każda z wersji Free, Standard i Pro ustawia dodatkowe parametry określające, które z funkcji mają być zawarte w każdej z wersji. Ustawiając flagę kompilatora -version=Pro dostaniemy wszystkie funkcje, zaś -version=Free da nam tylko tą fajną.

Kompilacja warunkowa jest również wykorzystywana w programowaniu kontraktowym. Szerszy opis kontraktów w D znajdziecie w jednej z kolejnych części.

To jeszcze nie koniec

Oj, rozpisałem się. Ale to jeszcze nie koniec. Myślę, że kolejne części (a podejrzewam, że będą jeszcze co najmniej dwie) pojawią się na moim blogu w najbliższych dniach. Opiszę w nich między innymi tablice dynamiczne i asocjacyjne (napiszemy słownik) oraz programowanie kontraktowe. Zapraszam do czytania.

P.S.
04.04.2010 - Poprawiłem jeden błąd merytoryczny. Kompilacja warunkowa w C++ jest możliwa, przepraszam za niedomówienie. W D jednak mechanizm ten wydaje się być znacznie prostszy w użyciu i bardziej funkcjonalny. 

Komentarze

0 nowych
przybylski   7 #1 04.04.2010 13:55

I bardzo dobrze, że to jeszcze nie koniec, czekam na kolejne części. Pozdrawiam

  #2 04.04.2010 15:56

I tak każdy woli C :)

GioWDS   13 #3 04.04.2010 16:26

@Jarek P.
D mi się tam zaczyna podobać ;)

tomekdkm   3 #4 04.04.2010 17:51

@Jarek P. (niezalogowany)

Mnie też, zaczyna się D podobać.
Bardzo ciekawy wpis jak i poprzedni o programowaniu w D.
Również czekam na kolejne części.
Pozdrawiam.

borzole   4 #5 04.04.2010 18:53

* Czy wcięcia w kodzie to jakiś problem na DP?
* "C++ zmusiłby nas do pisania oddzielnego kodu na każdą z platform. W D przychodzi nam z pomocą kompilacja warunkowa."
ale jak to się ma do dyrektyw preprocesora w C/C++ np. #ifdef ?
* Nie znam D, ale jakoś nie widzę dla niego miejsca w tej klasie. Potrzeba rewolucji, żeby wyprzeć c/c++ z rynku, a z tego co piszesz to są tylko "usprawnienia" naprawiające stare problemy, z którymi lepiej lub gorzej już sobie radzimy. Sorry, ale widzę tylko język przejściowy/sezonowy.

Mi2   4 #6 04.04.2010 20:06

@borzole
* Wcięcia w kodzie wstawiałem, ale zniknęły. Jakiś problem na DP.
* Nie pisałem nic o preprocesorze, tylko o kompilacji warunkowej. W D nie występują w ogóle dyrektywy preprocesora.
* Może, ale jak dla mnie te usprawnienia są bardzo korzystne. Może D nie wyprze C/C++, w każdym razie chciałbym, żeby tak się stało. Gdyby zastąpił C/C++, moim zdaniem byłby to krok w dobrą stronę.
A nowości jest trochę więcej - między innymi kontrakty, tablice asocjacyjne... Może nie ma rewolucji, ale jest naprawdę dużo świetnych usprawnień. Więcej w kolejnych wpisach.

G.Gn7Ex   5 #7 04.04.2010 20:50

@Mi2
"Nie pisałem nic o preprocesorze, tylko o kompilacji warunkowej. W D nie występują w ogóle dyrektywy preprocesora."

Tak się składa, że w C/C++ też jest możliwa kompilacja warunkowa realizowana właśnie przez dyrektywy procesora oraz nawet można uzależnić kompilację wybranych kawałków kodu od środowiska na którym aktualnie przebiega kompilacja.

@borzole
Też tak samo uważam...

borzole   4 #8 04.04.2010 20:50

* Chodzi o to, że kompilacja warunkowa w D robi chyba dokładnie to samo co odpowiednie dyrektywy #ifdef w c/c++, ale nie ważne.
* No właśnie chodzi o ten brak rewolucji. Nawet jeśli D jest leprze od C++, to nie ma takiego zaplecza bibliotek i programistów. Ciężkie biznesowe aplikacje to Java/C#, szybkie sterowniki i biblioteki to C, a środek? No właśnie wielki burdel do zabawy językami, w którym zawsze jak trzeba zrobić coś konkretnego to wygrywa C++. Chociaż pomniejsze aplikacje są pisane w tylu językach ile matka natura dała, łącznie z językami skryptowymi. Nie mówię, że nie ma miejsca dla D, ale jeśli nie znajdzie swojej niszy zastosowań i nie wyjdzie z cienia w ciągu paru lat to może być klapa. D nie jest pierwszym językiem, który chce podebrać klientów C++ (chyba każdy w miarę szybki język kompilowany miał takie ambicje) i zobacz kto wciąż wygrywa?
Życzę D powodzenia, ale jestem sceptykiem (a wsparcie w jakimś dużym IDE już jest?)

MicMic   2 #9 04.04.2010 21:57

Wielkość programu i zużycie pamięci jednak trochę większe niż w przypadku C++.

Autor edytował komentarz.
Mi2   4 #10 04.04.2010 22:16

@G.Gn7Ex, borzole - rzeczywiście macie rację. Nie jestem ekspertem od C/C++, nie znałem tej dyrektywy. Choć w D kompilacja warunkowa wydaje się być łatwiejsza i bardziej funkcjonalna.

Usunąłem zdanie o kompilacji warunkowej w C/C++ i dopisałem post scriptum.

@MicMic - Napisałem prosty edytor kodu źródłowego w D przy użyciu bibliotek GTK/GtkD. Program po uruchomieniu zabiera 6MB RAM-u, więc chyba nie jest tak źle.

Jak rozwiążę pewien problem z bindingiem do QT, będę brał się za komunikator. Wtedy będę mógł trochę więcej powiedzieć o zastosowaniu D w trochę większych projektów.

Tak czy tak - mi z D korzysta się bardzo wygodnie, ale to już kwestia preferencji ;)

MicMic, możesz spróbować jeszcze GDC i zobaczyć, czy będzie mniej.

GL1zdA   11 #11 04.04.2010 22:30

@MicMic
Ale to nie jest problem języka, tylko tego co i jak jest linkowane do pliku wynikowego.

MicMic   2 #12 04.04.2010 22:46

Nie mówię, że jest źle :D

Autor edytował komentarz.
borzole   4 #13 04.04.2010 23:41

@MicMic
rozmiar nie zawsze "ma znaczenie" ;)

GioWDS   13 #14 05.04.2010 02:49

Można optymalizować program pod względem wielkości i/lub względem szybkości. Osobiście wole parę KiB więcej niż sekund ;)

RubasznyRumcajs   6 #15 05.04.2010 05:08

tak z ciekawosci sie spytam (nie jestem programista jakby co)- jakie sa zalety owego jezyka, w porownaniu do np. jezyka Go (opracowanego przez google)?

  #16 05.04.2010 07:52

Zgadzam się z borzole i G.Gn7Ex
D to taki przejściowy język. Według mnie też jest bardzo interesująca Java.

  #17 05.04.2010 08:47

czy godny następca ? tu można polemizować

jak narazie (dluzsze narazie) to tylko jest taka ciekawostka

Mi2   4 #18 05.04.2010 09:50

@RubasznyRumcajs
Niestety nic nie mogę powiedzieć na ten temat, ponieważ nie pisałem nigdy niczego w Go.

@asdas
Dotąd pisałem w Javie. Jak narazie w D pisze mi się dużo wygodniej.

A właśnie, zapomniałem odpowiedzieć na pytanie o wsparcie w IDE. Z tego, co wiem, jest wtyczka Descent do Eclipse'a.

mati75   6 #19 05.04.2010 14:31

Wygląda jak połączenie C i pascala.

borzole   4 #20 05.04.2010 15:12

@RubasznyRumcajs
Z tego co pamiętam z newsa na DP, to Go nastawiony był na małe aplikacje wykorzystujące wiele procesorów/rdzeni, czy nawet gridy. To jest akurat nisza i przyszłościowe podejście, ale sam język był wówczas w fazie wczesnego rozwoju.

  #21 05.04.2010 21:15

Kolejny maniak próbujący nawrócić świat. D nie ma wsparcia odpowiednich firm, brak bibliotek i środowiska programistycznego. Powodzenia w pisaniu kodu.

Mi2   4 #22 06.04.2010 15:33

@Hakerpawel007
Ja nie próbuję nawrócić świata, lecz jedynie zaprezentować język, który mi wydaje się godny polecenia, choć mało popularny. Co do wsparcia firm - może i nie ma. Ale przecież nie wszystko od razu jest przez wszystkich wspierane. Bak bibliotek? Nie do końca, można przecież linkować z tymi napisanymi w C. Środowiska programistyczne - jest wtyczka do Eclipse'a, powstają też chyba jakieś IDE do D.
Mi za pomocą D udało się napisać prosty edytor kodu źródłowego oparty o GTK, a teraz zabieram się za komunikator w oparciu o QT. Nie jest tak źle, jak na młody jeszcze język.

kijek   6 #23 06.04.2010 18:54

Podczas próby kompilacji uzyskuję takie komunikaty:
main.d(6): Error: undefined identifier write, did you mean function fwrite?
main.d(6): Error: dunction expected before (), not write of type int

Co jest?

Mi2   4 #24 06.04.2010 21:20

kijek - prawdopodobnie korzystasz z wersji D 1.0, które zawiera wyłącznie funkcje writef i writefln. Przykłady pisałem pod dwójkę, wytłumaczyłem też, dlaczego warto ją wybrać.

Jeżeli chcesz zostać przy 1.0, użyj writef lub writefln.

Aby upewnić się, jaką masz wersję kompilatora, uruchom go bez żadnych plików (wpisz po prostu "dmd"). Wypisze Ci instrukcje użycia wraz z numerkiem wersji na samej górze.

kijek   6 #25 06.04.2010 22:13

Heh, przez przypadek zainstalowałem wersję 1 i 2, a podczas wywoływania dmd odpalała się 1. Dzięki :)

  #26 18.11.2010 20:19

C++ lubie najbardziej...