D-ohjelmointikieli on oliosuuntautunut, imperatiivinen, moniparadigmainen järjestelmäohjelmointikieli. D-kieli on syntynyt C++:n uudelleensuunnitteluna, ja D:n suunnittelutavoitteet pyrkivät yhdistämään käännettyjen kielten suorituskyvyn ja nykyaikaisten dynaamisten kielten turvallisuuden ja ilmaisuvoiman. D-koodi on yleisesti yhtä nopeaa kuin vastaava C++-koodi, mutta samalla lyhyempää ja muistiturvallisempaa.
Lyhyt historia ja tavoitteet
D syntyi 2000-luvun alussa tarkoituksena säilyttää C++:n suorituskyky ja järjestelmäohjelmoinnin ominaisuudet, mutta poistaa kielen monimutkaisuutta ja lisätä turvallisuutta sekä tuottavuutta. Sen suunnittelussa on otettu vaikutteita monista kielistä (esim. C, C++, Java, Python ja Lisp), ja tavoitteena on tarjota moderni työkalu sekä järjestelmä- että sovelluskehitykseen.
Keskeiset ominaisuudet
- Moniparadigmaisuus: tuki olio-ohjelmoinnille, funktionaalisille piirteille, imperatiiviiselle tyylille ja metaohjelmoinnille.
- Suorituskyky: käännetty kieli, jonka koodi voi olla lähestulkoon yhtä nopeaa kuin C/C++-vastineet.
- Muistiturvallisuus: kielessä on työkaluja ja attribuutteja muistivirheiden vähentämiseksi (esim. @safe, @trusted, @system, @nogc).
- Metaohjelmointi ja CTFE: laajat compile-time -ominaisuudet, kuten template-mallinnus, mixinit ja CTFE (compile-time function execution).
- Modernit kielenrakenteet: moduulit korvaavat header-tiedostot, sopimukset (contracts), lambdat, toutitteluominaisuudet ja heikennetty syntaksi verrattuna perinteiseen C++:iin.
Muistiturvallisuus ja muistin hallinta
D tarjoaa useita mekanismeja muistiturvallisuuden parantamiseksi ilman, että suorituskykyä joudutaan luopumaan:
- @safe / @trusted / @system: funktioattribuutit, jotka ohjaavat koodin turvallisuustasoa ja rajoittavat epävarmoja operaatioita.
- Garbage Collector (GC): D:n runtime sisältää roskankerääjän, mikä helpottaa muistin hallintaa ja vähentää muistivuotoja. GC on kuitenkin valinnainen: järjestelmäohjelmoinnissa voi kirjoittaa @nogc-koodia ja käyttää manuaalista muistinhallintaa tai RAII-tyyppisiä ratkaisuja.
- Array bounds checking ja tyyppijärjestelmä: oletuksena saatavilla olevat tarkistukset ja immutability- ja const-avainsanat vähentävät yleisiä virheitä.
- Deterministinen siivous: destruktorit ja scope-ominaisuudet (esim. scope(exit)) mahdollistavat resurssien vapauttamisen ennustettavasti.
Metaohjelmointi ja generics
D:ssä on tehokkaat generics- ja metaohjelmointiominaisuudet: templatet, compile-time -funktiot (CTFE), string-mixinit, reflektio ja traitit mahdollistavat monimutkaisen koodin tuottamisen turvallisesti ja ilman runsaasti boilerplatea. Tämä tekee D:stä erityisen sopivan tilanteisiin, joissa suorituskyky ja koodin abstraktion taso molemmat ovat tärkeitä.
Yhteensopivuus ja ekosysteemi
- C-yhteensopivuus: D tukee hyvin C-funktioiden kutsumista ja kirjastojen linkittämistä (extern(C)), mikä tekee olemassa olevan C-koodin hyödyntämisestä helppoa.
- C++-yhteensopivuus: D:n suunnittelussa on ollut vaikutteita C++:sta ja kielellä on mekanismeja rajalliseen C++-yhteensopivuuteen (esim. extern(C++)), mutta täydellinen saumaton interoperabiliteetti riippuu ABI:sta ja käytetyistä C++-ominaisuuksista.
- Komppailijat ja työkalut: tunnetuimpia kääntäjiä ovat DMD (referenssikääntäjä), GDC (GCC:n D-portti) ja LDC (LLVM-pohjainen). Paketinhallinta- ja build-työkalu on dub, ja standardikirjasto on nimeltään Phobos (ja runtime druntime).
Konkurenssi ja rinnakkaisuus
D tarjoaa useita tapoja toteuttaa rinnakkaisuutta ja turvallista monisäikeisyyttä: immutability (immutable), shared-tyyppi sekä korkeamman tason kirjastoja kuten std.concurrency ja std.parallelism. Ohjelmoija voi valita säie- tai viestipohjaisen mallin tilanteen mukaan.
Käyttötapaukset
D soveltuu erityisesti niihin projekteihin, joissa tarvitaan natiivin koodin suorituskykyä mutta halutaan myös moderneja tuottavuutta parantavia ominaisuuksia. Tyypillisiä käyttökohteita ovat järjestelmäohjelmointi, pelimoottorit, palvelinpuolen sovellukset, tietojenkäsittelykirjastot ja työkalu- tai infrastruktuurikehitys.
Yhteenveto
D on tavoitteellinen kompromissi suorituskyvyn ja turvallisuuden välillä: se tarjoaa C/C++-tyyppisen suorituskyvyn, mutta runsaasti moderneja kieliominaisuuksia, muistiturvallisuutta parantavia mekanismeja ja tehokasta metaohjelmointia. Valitsemalla D:n kehittäjä saa työkalun, jolla voi kirjoittaa tehokasta, selkeämpää ja turvallisempaa natiivikoodia—samalla kuitenkin säilyttäen mahdollisuuden integroida olemassaolevia C- ja joissain tilanteissa C++-resursseja.