D (programovací jazyk) - D (programming language)

D programovací jazyk
D Programovací jazyk logo.svg
Paradigma Multi-paradigma : funkční , imperativní , objektově orientované
Navrhl Walter Bright , Andrei Alexandrescu (od roku 2007)
Vývojář Jazyková nadace D.
Poprvé se objevil 8. prosince 2001 ; Před 19 lety ( 2001-12-08 )
Stabilní uvolnění
2.097.0  Upravte to na Wikidata / 3. června 2021 ; Před 4 měsíci ( 3. června 2021 )
Kázeň při psaní Odvozené , statické , silné
OS FreeBSD , Linux , macOS , Windows
Licence Boost
Rozšíření názvu souboru .d
webová stránka dlang .org
Hlavní implementace
DMD ( referenční implementace ), GCC ,

GDC ,

LDC , SDC
Ovlivněn
C , C ++ , C# , Eiffel , Java , Python
Ovlivněn
Genie , MiniD, Qore , Swift , Vala , C ++ 11 , C ++ 14 , C ++ 17 , C ++ 20 , Go , C# a další.

D , také známý jako Dlang , je systémový programovací jazyk s více paradigmaty, který vytvořil Walter Bright na Digital Mars a byl vydán v roce 2001. Andrei Alexandrescu se připojil k úsilí o návrh a vývoj v roce 2007. Ačkoli vznikl jako přepracování C ++ , D je odlišný jazyk. Přepracoval některé základní funkce C ++ a zároveň sdílí vlastnosti dalších jazyků, zejména Javy , Pythonu , Ruby , C# a Eiffel .

Cíle návrhu jazyka se pokusily spojit výkon a bezpečnost kompilovaných jazyků s expresivní silou moderních dynamických jazyků . Idiomatic D kód je obvykle stejně rychlý jako ekvivalentní kód C ++ a je také kratší. Jazyk jako celek není bezpečný pro paměť, ale obsahuje volitelné atributy určené ke kontrole bezpečnosti paměti.

Sem závěr , automatickou správu paměti a syntaktický cukr pro běžné typy umožňují rychlejší vývoj , zatímco odhady kontrole , návrh smlouvou funkcemi a souběžnost -aware typu pro systém pomoci snížit výskyt chyb .

Funkce

D byl navržen s poučením z praktického používání C ++, spíše než z čistě teoretického hlediska. Přestože jazyk používá mnoho konceptů C a C ++, některé také zahodí nebo k dosažení některých cílů používá různé přístupy (a syntaxi). Jako takový není zdrojově kompatibilní (a ani se nesnaží být) se zdrojovým kódem C a C ++ obecně (některé jednodušší kódové základny z těchto jazyků mohou naštěstí fungovat s D nebo vyžadují nějaké přenesení ). D byl však ve svém designu omezen pravidlem, že každý kód, který byl v C i D legální, by se měl chovat stejně.

D získal některé funkce před C ++, jako jsou uzávěry , anonymní funkce , provádění funkcí při kompilaci , rozsahy, integrované koncepty iterace kontejnerů a odvozování typů . D přidává k funkcionalitě C ++ také implementací návrhu podle smlouvy , testování jednotek , skutečných modulů , sbírání odpadků , polí první třídy , asociativních polí , dynamických polí , krájení polí , vnořených funkcí , opožděného hodnocení , provádění kódu s rozsahem (odloženým) a přepracovaná syntaxe šablony . C ++ vícenásobná dědičnost byla nahrazena jednoduchou dědičností ve stylu Java s rozhraními a mixiny . Na druhou stranu, deklarace, prohlášení a výrazová syntaxe D úzce odpovídá C ++.

D si zachovává schopnost C ++ provádět nízkoúrovňové programování včetně inline assembleru , který typizuje rozdíly mezi D a aplikačními jazyky, jako je Java a C# . Inline assembler umožňuje programátorům zadávat kód sestavy specifický pro stroj v rámci standardního kódu D, což je metoda, kterou používají systémoví programátoři k přístupu k funkcím procesoru na nízké úrovni potřebným ke spouštění programů, které jsou propojeny přímo s podkladovým hardwarem , jako jsou operační systémy a ovladače zařízení , stejně jako psaní vysoce výkonného kódu (tj. pomocí vektorových přípon, SIMD ), který je obtížné automaticky generovat kompilátorem.

D standardně podporuje přetížení funkcí a přetížení operátorů , stejně jako dynamická pole a asociativní pole. Symboly (funkce, proměnné, třídy) lze deklarovat v libovolném pořadí - předávací deklarace nejsou povinné. Obdobně lze importy provádět téměř v libovolném pořadí a dokonce je možné jejich rozsah (tj. Importovat nějaký modul nebo jeho část pouze do funkce, třídy nebo unittestu). D má vestavěnou podporu pro komentáře k dokumentaci, což umožňuje automatické generování dokumentace .

Programovací paradigmata

D podporuje pět hlavních programovacích paradigmat :

Rozkazovací způsob

Imperativní programování v D je téměř totožné s programem C. Funkce, data, příkazy, deklarace a výrazy fungují stejně jako v C a k běhové knihovně C lze přistupovat přímo. Na druhou stranu některé pozoruhodné rozdíly mezi D a C v oblasti imperativního programování zahrnují foreachkonstrukci smyčky D , která umožňuje smyčku přes kolekci, a vnořené funkce , což jsou funkce, které jsou deklarovány uvnitř jiné a mohou přistupovat k lokálním proměnným uzavírající funkce .

import std.stdio;

void main() {
    int multiplier = 10;
    int scaled(int x) { return x * multiplier; }

    foreach (i; 0 .. 10) {
        writefln("Hello, world %d! scaled = %d", i, scaled(i));
    }
}

Objektově orientovaný

Objektově orientované programování v D je založeno na jediné hierarchii dědičnosti, přičemž všechny třídy jsou odvozeny ze třídy Object. D nepodporuje vícenásobnou dědičnost; místo toho používá rozhraní ve stylu Java , která jsou srovnatelná s čistými abstraktními třídami C ++, a mixiny , které oddělují běžné funkce od hierarchie dědičnosti. D také umožňuje definování statických a konečných (nevirtuálních) metod v rozhraních.

Rozhraní a dědičnost v D podporují kovariantní typy pro návratové typy přepsaných metod.

D podporuje přesměrování typu a také volitelné vlastní dynamické odesílání .

Třídy (a rozhraní) v D mohou obsahovat invarianty, které jsou automaticky kontrolovány před a po vstupu do veřejných metod, v souladu s metodikou design by contract .

Mnoho aspektů tříd (a struktur) lze introspektovat automaticky v době kompilace (forma reflexe pomocí type traits) a za běhu (RTII / TypeInfo), aby se usnadnil generický kód nebo automatické generování kódu (obvykle pomocí technik kompilace).

Funkční

D podporuje funkce funkčního programování, jako jsou literály funkcí , uzávěry , rekurzivně neměnné objekty a použití funkcí vyššího řádu . Pro anonymní funkce existují dvě syntaxe, včetně formuláře s více příkazy a zápisu „krátkého slova“ s jedním výrazem:

int function(int) g;
g = (x) { return x * x; }; // longhand
g = (x) => x * x;          // shorthand

Existují dva předdefinované typy pro literály funkcí function, což je jednoduše ukazatel na funkci přidělenou zásobníkem a delegatekterý také obsahuje ukazatel na okolní prostředí. Odvození typu lze použít s anonymní funkcí, v takovém případě kompilátor vytvoří, delegatepokud neprokáže, že ukazatel prostředí není nutný. Podobně k implementaci uzavření kompilátor umístí uzavřené lokální proměnné na haldu pouze v případě potřeby (například pokud je uzávěr vrácen jinou funkcí a ukončí rozsah této funkce). Při použití odvození typu kompilátor také přidá atributy typu purea nothrowk typu funkce, pokud dokáže, že platí.

Další funkční funkce, jako je currying a běžné funkce vyššího řádu, jako je mapa , filtr a zmenšení, jsou k dispozici prostřednictvím standardních knihovních modulů std.functionala std.algorithm.

import std.stdio, std.algorithm, std.range;

void main()
{
    int[] a1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    int[] a2 = [6, 7, 8, 9];

    // must be immutable to allow access from inside a pure function
    immutable pivot = 5;

    int mySum(int a, int b) pure nothrow // pure function
    {
        if (b <= pivot) // ref to enclosing-scope
            return a + b;
        else
            return a;
    }

    // passing a delegate (closure)
    auto result = reduce!mySum(chain(a1, a2));
    writeln("Result: ", result); // Result: 15

    // passing a delegate literal
    result = reduce!((a, b) => (b <= pivot) ? a + b : a)(chain(a1, a2));
    writeln("Result: ", result); // Result: 15
}

Alternativně mohou být výše uvedené kompozice funkcí vyjádřeny pomocí jednotné syntaxe volání funkcí (UFCS) pro přirozenější čtení zleva doprava:

    auto result = a1.chain(a2).reduce!mySum();
    writeln("Result: ", result);

    result = a1.chain(a2).reduce!((a, b) => (b <= pivot) ? a + b : a)();
    writeln("Result: ", result);

Rovnoběžnost

Koncepty paralelního programování jsou implementovány v knihovně a nevyžadují zvláštní podporu kompilátoru. Systém typu D a kompilátor však zajišťují, že sdílení dat lze detekovat a spravovat transparentně.

import std.stdio : writeln;
import std.range : iota;
import std.parallelism : parallel;

void main()
{
    foreach (i; iota(11).parallel) {
        // The body of the foreach loop is executed in parallel for each i
        writeln("processing ", i);
    }
}

iota(11).parallelje ekvivalentní std.parallelism.parallel(iota(11))použití UFCS.

Stejný modul také podporuje, taskPoolkteré lze použít pro dynamické vytváření paralelních úkolů, stejně jako operace stylu map-filtr-redukce a skládání na rozsahech (a polích), což je užitečné v kombinaci s funkčními operacemi. std.algorithm.mapvrací spíše líně vyhodnocený rozsah než pole. Tímto způsobem jsou prvky automaticky vypočítávány každou pracovní úlohou paralelně.

import std.stdio : writeln;
import std.algorithm : map;
import std.range : iota;
import std.parallelism : taskPool;

/* On Intel i7-3930X and gdc 9.3.0:
 * 5140ms using std.algorithm.reduce
 * 888ms using std.parallelism.taskPool.reduce
 *
 * On AMD Threadripper 2950X, and gdc 9.3.0:
 * 2864ms using std.algorithm.reduce
 * 95ms using std.parallelism.taskPool.reduce
 */
void main()
{
  auto nums = iota(1.0, 1_000_000_000.0);

  auto x = taskPool.reduce!"a + b"(
      0.0, map!"1.0 / (a * a)"(nums)
  );

  writeln("Sum: ", x);
}

Konkurence

Souběžnost je plně implementována v knihovně a nevyžaduje podporu kompilátoru. Jsou možné alternativní implementace a metodologie psaní souběžného kódu. Použití systému psaní D pomáhá zajistit bezpečnost paměti.

import std.stdio, std.concurrency, std.variant;

void foo()
{
    bool cont = true;

    while (cont)
    {
        receive( // Delegates are used to match the message type.
            (int msg) => writeln("int received: ", msg),
            (Tid sender) { cont = false; sender.send(-1); },
            (Variant v) => writeln("huh?") // Variant matches any type
        );
    }
}

void main()
{
    auto tid = spawn(&foo); // spawn a new thread running foo()

    foreach (i; 0 .. 10)
        tid.send(i);   // send some integers

    tid.send(1.0f);    // send a float
    tid.send("hello"); // send a string
    tid.send(thisTid); // send a struct (Tid)

    receive((int x) => writeln("Main thread received message: ", x));
}

Metaprogramování

Metaprogramming je podporován pomocí šablon, kompilace-time vykonávání funkce, n-tic a smyčcových mixins. Následující příklady ukazují některé z funkcí kompilace D v D.

Šablony v D lze psát v imperativnějším stylu ve srovnání s funkčním stylem C ++ pro šablony. Toto je běžná funkce, která vypočítává faktoriál čísla:

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

Zde static ifje ukázáno použití podmíněného konstruktu D v době kompilace ke konstrukci šablony, která provádí stejný výpočet pomocí kódu, který je podobný jako u výše uvedené funkce:

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

V následujících dvou příkladech se k výpočtu faktoriálů používá výše definovaná šablona a funkce. Typy konstant nemusí být specifikovány explicitně, protože překladač odvozuje jejich typy z pravé strany přiřazení:

enum fact_7 = Factorial!(7);

Toto je příklad spuštění funkce při kompilaci (CTFE). Běžné funkce mohou být použity v konstantních výrazech při kompilaci za předpokladu, že splňují určitá kritéria:

enum fact_9 = factorial(9);

Tyto std.string.formatfunkce provádí printf-Jako formátování dat (i na kompilaci, přes CTFE), a „MSG“ Pragma zobrazuje výsledek v době kompilace:

import std.string : format;
pragma(msg, format("7! = %s", fact_7));
pragma(msg, format("9! = %s", fact_9));

Řetězcové mixiny v kombinaci s prováděním funkcí v době kompilace umožňují generování kódu D pomocí řetězcových operací v době kompilace. To lze použít k analýze jazyků specifických pro doménu , které budou kompilovány jako součást programu:

import FooToD; // hypothetical module which contains a function that parses Foo source code
               // and returns equivalent D code
void main() {
    mixin(fooToD(import("example.foo")));
}

Správa paměti

Paměť je obvykle spravována pomocí uvolňování paměti , ale konkrétní objekty mohou být dokončeny okamžitě, když se dostanou mimo rozsah. To používá většina programů a knihoven napsaných v D.

V případě, že je zapotřebí větší kontrola nad rozložením paměti a lepším výkonem, je možná explicitní správa paměti pomocí přetížených operátorů new a deletevoláním C 's malloc a free přímo, nebo implementací vlastních schémat alokátorů (tj. Na zásobníku s nouzovým řešením, alokace stylu RAII, počítání referencí, sdílené počítání referencí). Sběr odpadků lze ovládat: programátoři mohou přidávat a vylučovat paměťové rozsahy z pozorování kolektorem, mohou deaktivovat a povolit kolektor a vynutit si generační nebo úplný sběrný cyklus. Tato příručka uvádí mnoho příkladů, jak implementovat různá vysoce optimalizovaná schémata správy paměti pro případy, kdy je sběr odpadu v programu nedostatečný.

Ve funkcích structsjsou ve výchozím nastavení přiděleny na zásobníku, zatímco classesve výchozím nastavení jsou přiděleny na haldě (pouze odkaz na instanci třídy je v zásobníku). To však lze změnit u tříd, například pomocí standardní šablony knihovny std.typecons.scoped, nebo pomocí newpro structs a přiřazením ukazatele namísto proměnné na základě hodnoty.

Ve funkci jsou statická pole (známé velikosti) alokována na zásobník. U dynamických polí lze použít core.stdc.stdlib.allocafunkci (podobnou funkci C alloca, k přidělení paměti v zásobníku. Vrácený ukazatel lze použít (přepracovat) do (zadaného) dynamického pole pomocí řezu (nicméně pole pro změnu velikosti, včetně připojování, musí být vyhnout; a ze zřejmých důvodů nesmí být vráceny z funkce).

scopeKlíčové slovo může být použito jak pro anotaci částí kódu, ale také proměnných a tříd / structs, ukázat, že oni by měli být zničeny (destruktor nazývá) bezprostředně na výstupu rozsahu. Cokoli je paměť uvolněna, závisí také na implementaci a rozdílech mezi třídami a strukturou.

std.experimental.allocator obsahuje modulární a skládatelné šablony alokátorů pro vytváření vlastních vysoce výkonných alokátorů pro speciální případy použití.

SafeD

SafeD je název daný podmnožině D, u které lze zaručit, že bude bezpečná pro paměť (žádné zápisy do paměti, které nebyly přiděleny nebo které byly recyklovány). Označené funkce @safejsou zkontrolovány při kompilaci, aby se zajistilo, že nepoužívají žádné funkce, které by mohly vést k poškození paměti, například aritmetické ukazatele a nekontrolované přetypování, a všechny další volané funkce musí být také označeny jako @safenebo @trusted. Funkce lze označit @trustedpro případy, kdy kompilátor nedokáže rozlišit mezi bezpečným používáním funkce, která je v SafeD zakázána, a potenciálním případem poškození paměti.

Rozsah celoživotní bezpečnosti

Zpočátku pod bannery DIP1000 a DIP25 (nyní součást jazykové specifikace) poskytuje D ochranu proti určitým špatně tvarovaným konstrukcím zahrnujícím životnost dat.

Stávající zavedené mechanismy se primárně zabývají funkčními parametry a pamětí zásobníku, nicméně je deklarovanou ambicí vedení programovacího jazyka poskytnout důkladnější zpracování životů v programovacím jazyce D. (Ovlivněno nápady z programovacího jazyka Rust ).

Celoživotní bezpečnost úkolů

V rámci @bezpečného kódu se kontroluje životnost přiřazení zahrnujícího referenční typ, aby byla zajištěna delší životnost nabyvatele než přiřazeného.

Například:

@safe void test()
{
    int tmp = 0; // #1
    int* rad;    // #2
    rad = &tmp;  // If the order of the declarations of #1 and #2 is reversed, this fails.
    {
    	int bad = 45; // Lifetime of "bad" only extends to the scope in which it is defined.
        *rad = bad;   // This is kosher.
        rad = &bad;   // Lifetime of rad longer than bad, hence this is not kosher at all.
    }
}

Doživotní parametr parametru v rámci @bezpečného kódu

Při použití na parametr funkce, které jsou buď typu ukazatele nebo odkazů, návratová klíčová slova a rozsah omezují životnost a použití tohoto parametru.

Standard diktuje následující chování:

Třída úložiště Chování (a omezení) parametru s třídou úložiště
rozsah referencím v parametru nelze uniknout. Ignorováno pro parametry bez referencí
vrátit se Parametr může být vrácen nebo zkopírován do prvního parametru, ale jinak z funkce neunikne. Takové kopie musí nepřežít argumenty, ze kterých byly odvozeny. Ignorováno pro parametry bez referencí

Komentovaný příklad je uveden níže.

@safe:

int* gp;
void thorin(scope int*);
void gloin(int*);
int* balin(return scope int* p, scope int* q, int* r)
{
     gp = p; // error, p escapes to global gp
     gp = q; // error, q escapes to global gp
     gp = r; // ok

     thorin(p); // ok, p does not escape thorin()
     thorin(q); // ok
     thorin(r); // ok

     gloin(p); // error, gloin() escapes p
     gloin(q); // error, gloin() escapes q
     gloin(r); // ok that gloin() escapes r

     return p; // ok
     return q; // error, cannot return 'scope' q
     return r; // ok
}

Interakce s jinými systémy

C ‚s Abi (ABI) je podporován, stejně jako všechny základní a odvozené typy c, umožňující přímý přístup k existující kód v C a knihoven. Vazby D jsou k dispozici pro mnoho populárních knihoven C. Standardní knihovna C je navíc součástí standardu D.

V systému Microsoft Windows má D přístup ke kódu COM ( Component Object Model ).

Dokud je o správu paměti řádně postaráno, lze s D v jedné binárce kombinovat mnoho dalších jazyků. Například kompilátor GDC umožňuje propojení C, C ++ a dalších podporovaných jazykových kódů, které mají být smíchány. Kód D (funkce) lze také označit jako používající ABI C, C ++, Pascal, a tak být předán knihovnám napsaným v těchto jazycích jako zpětná volání . Podobně lze data mezi kódy zapsanými v těchto jazycích zaměňovat oběma způsoby. To obvykle omezuje použití na primitivní typy, ukazatele, některé formy polí, odbory, struktury a pouze některé typy ukazatelů funkcí.

Protože mnoho dalších programovacích jazyků často poskytuje C API pro psaní rozšíření nebo spouštění překladače jazyků, D může komunikovat přímo s těmito jazyky také pomocí standardních vazeb C (s tenkým souborem rozhraní D). Existují například obousměrné vazby pro jazyky jako Python , Lua a další jazyky, které často používají metody generování kódu při kompilaci a metody reflexe typu při kompilaci.

Interakce s kódem C ++

D má tolerantní, ale realistický přístup k spolupráci s kódem C ++.

Pro kód D označený jako externí (C ++) jsou zadány následující funkce:

  • Konvence pro manipulaci s názvy se musí shodovat s konvencemi C ++ na cíli.
  • Pro volání funkcí je ABI ekvivalentní.
  • Vtable musí být spárována až do jedné dědičnosti (jediná úroveň podporovaná specifikací jazyka D).

Obor názvů C ++ se používá prostřednictvím externího syntaxe (C ++, obor názvů), kde namespace je název oboru názvů C ++.

Příklad spolupráce C ++

Strana C ++

#include <iostream>
using namespace std;
class Base
{
    public:
        virtual void print3i(int a, int b, int c) = 0;
};

class Derived : public Base
{
    public:
        int field;
        Derived(int field) : field(field) {}

        void print3i(int a, int b, int c)
        {
            cout << "a = " << a << endl;
            cout << "b = " << b << endl;
            cout << "c = " << c << endl;
        }

        int mul(int factor);
};

int Derived::mul(int factor)
{
    return field * factor;
}

Derived *createInstance(int i)
{
    return new Derived(i);
}

void deleteInstance(Derived *&d)
{
    delete d;
    d = 0;
}

Strana D.

extern(C++)
{
    abstract class Base
    {
        void print3i(int a, int b, int c);
    }

    class Derived : Base
    {
        int field;
        @disable this();
        override void print3i(int a, int b, int c);
        final int mul(int factor);
    }

    Derived createInstance(int i);
    void deleteInstance(ref Derived d);
}

void main()
{
    import std.stdio;

    auto d1 = createInstance(5);
    writeln(d1.field);
    writeln(d1.mul(4));

    Base b1 = d1;
    b1.print3i(1, 2, 3);

    deleteInstance(d1);
    assert(d1 is null);

    auto d2 = createInstance(42);
    writeln(d2.field);

    deleteInstance(d2);
    assert(d2 is null);
}

Lepší C.

Programovací jazyk D má oficiální podmnožinu známou jako „ Better C “. Tato podmnožina zakazuje přístup k funkcím D vyžadujícím použití jiných runtime knihoven než C.

Povoleno pomocí příznaků kompilátoru „-betterC“ na DMD a LDC a „-fno-druntime“ na GDC, Better C může volat pouze do kódu D kompilovaného pod stejným příznakem (a propojeného kódu jiného než D), ale kód kompilován bez Možnost Better C může volat do kódu zkompilovaného s ním: toto však povede k mírně odlišnému chování kvůli rozdílům ve způsobu, jakým C a D zpracovávají tvrzení.

Funkce zahrnuté v Better C

  • Neomezené používání funkcí kompilace (například funkce dynamické alokace D lze použít v době kompilace k předběžnému přidělování dat D)
  • Kompletní možnosti metaprogramování
  • Vnořené funkce, vnořené struktury, delegáti a lambdas
  • Členské funkce, konstruktory, destruktory, provozní přetížení atd.
  • Plně modulový systém
  • Krájení pole a kontrola hranic pole
  • RAII
  • rozsah (výstup)
  • Ochrana bezpečnosti paměti
  • Rozhraní s C ++
  • Třídy COM a třídy C ++
  • selhání tvrzení jsou směrována do runtime knihovny C.
  • spínač se strunami
  • konečný spínač
  • unittest bloky
  • ověření formátu printf

Funkce vyloučené z Better C

  • Sběr odpadků
  • TypeInfo a ModuleInfo
  • Vestavěné řezání závitů (např. core.thread)
  • Dynamická pole (ačkoli řezy statických polí fungují) a asociativní pole
  • Výjimky
  • synchronizované acore.sync
  • Konstruktéři nebo destruktory statických modulů

Dějiny

Walter Bright začal pracovat na novém jazyce v roce 1999. D byl poprvé vydán v prosinci 2001 a dosáhl verze 1.0 v lednu 2007. První verze jazyka (D1) se soustředila na imperativní, objektově orientovaná a metaprogramovací paradigmata, podobná C ++.

Někteří členové komunity D nespokojení s Phobosem, oficiální běhovou a standardní knihovnou D , vytvořili alternativní běhovou a standardní knihovnu s názvem Tango. První veřejné oznámení Tango přišlo do několika dní od vydání D 1.0. Tango přijalo jiný styl programování, zahrnující OOP a vysokou modularitu. Jako komunitní projekt byl Tango otevřenější vůči příspěvkům, což mu umožňovalo postupovat rychleji než oficiální standardní knihovna. V té době byly Tango a Phobos nekompatibilní kvůli různým rozhraním API pro podporu běhu (odpadkový koš, podpora vláken atd.). To znemožnilo použití obou knihoven ve stejném projektu. Existence dvou knihoven, obě široce používané, vedla k výrazným sporům kvůli některým balíčkům využívajícím Phobos a jiným využívajícím Tango.

V červnu 2007 byla vydána první verze D2. Začátek vývoje D2 signalizoval stabilizaci D1. První verze jazyka byla umístěna do údržby, pouze přijímala opravy a opravy chyb implementace. D2 zavedl zásadní změny jazyka, počínaje prvním experimentálním konstantním systémem . D2 později přidal řadu dalších jazykových funkcí, jako jsou uzávěry , čistota a podpora funkčních a souběžných paradigmat programování. D2 také vyřešil problémy standardní knihovny oddělením modulu runtime od standardní knihovny. Dokončení portu D2 Tango bylo oznámeno v únoru 2012.

Uvolnění Andrei Alexandrescu ‚s knihou Systém D programovací jazyk dne 12. června 2010 označil stabilizaci D2, který je dnes běžně označované jen jako‚D‘.

V lednu 2011 se vývoj D přesunul ze základny pro odposlouchávání bugtrackerů / oprav na GitHub . To vedlo k významnému nárůstu příspěvků do kompilátoru, modulu runtime a standardní knihovny.

V prosinci 2011 Andrei Alexandrescu oznámil, že D1, první verze jazyka, bude ukončena dne 31. prosince 2012. Konečné vydání D1, D v1.076, bylo 31. prosince 2012.

Kód pro oficiální kompilátor D, kompilátor Digital Mars D od Waltera Bright, byl původně vydán pod vlastní licencí , která je kvalifikována jako dostupný zdroj, ale neodpovídá definici open source . V roce 2014, kompilátor front-end byl re-licensovaný jako open source pod licencí plnicího Software . Tento znovu licencovaný kód vyloučil back-end, který byl částečně vyvinut ve společnosti Symantec . Dne 7. dubna 2017 byl celý kompilátor zpřístupněn pod licencí Boost poté, co společnost Symantec udělila povolení k opětovné licenci back-endu. Dne 21. června 2017 byl jazyk D přijat k zařazení do GCC.

Implementace

Většina aktuálních implementací D je kompilována přímo do strojového kódu pro efektivní provedení.

Kompilátory připravené k produkci:

  • DMD - překladač Digital Mars D společnosti Walter Bright je oficiálním překladačem D; open source pod licencí Boost Software License . Frontend DMD je sdílen GDC (nyní v GCC) a LDC, aby se zlepšila kompatibilita mezi kompilátory. Zpočátku byl frontend napsán v jazyce C ++, ale nyní je většina z nich nyní napsána v samotném D (vlastní hostování). Optimalizátory backendu a strojového kódu jsou založeny na kompilátoru Symantec. Zpočátku podporoval pouze 32bitové x86, podpora byla přidána pro 64bitové amd64 a PowerPC od Waltera Bright. Později byl backend a téměř celý kompilátor přenesen z C ++ do D pro úplné vlastní hostování.
  • GCC -The GNU Compiler Collection , sloučilo GDC do GCC 9 29. října 2018. První pracovní verze GDC s GCC, založené na GCC 3.3 a GCC 3.4 na 32bitových x86 v Linuxu a macOS, byly vydány 22. března 2004. Od poté GDC získával podporu pro více platforem a zlepšoval výkon a opravoval chyby a sledoval upstream DMD kód pro frontend a jazykovou specifikaci.
  • LDC -Kompilátor založený na frontendu DMD, který používá LLVM jako back-end kompilátoru. První verze v dobré kvalitě byla zveřejněna 9. ledna 2009. Podporuje verzi 2.0.

Kompilátory hraček a konceptů:

  • Kompilátor D pro .NET -back-end pro kompilátor D programovacího jazyka 2.0. Kompiluje kód do bajtového kódu Common Intermediate Language (CIL), nikoli do strojového kódu. CIL pak lze spustit prostřednictvím virtuálního počítače Common Language Infrastructure (CLI) . Projekt nebyl několik let aktualizován a autor uvedl, že projekt již není aktivní.
  • SDC - Stupid D Compiler používá vlastní front-end a LLVM jako kompilátor back-end. Je napsán v jazyce D a používá plánovač ke zpracování rozlišení symbolů, aby elegantně zvládl funkce kompilace v čase D. Tento kompilátor aktuálně podporuje omezenou podmnožinu jazyka.

Pomocí výše uvedených kompilátorů a řetězců nástrojů je možné kompilovat programy D pro cílení na mnoho různých architektur, včetně x86 , amd64 , AArch64 , PowerPC , MIPS64 , DEC Alpha , Motorola m68k , Sparc , s390 , WebAssembly . Primárním podporovaným operačním systémem jsou Windows a Linux , ale různé překladače podporují také Mac OS X , FreeBSD , NetBSD , AIX , Solaris/OpenSolaris a Android , ať už jako hostitel nebo cíl, nebo obojí. Cíl WebAssembly (podporovaný prostřednictvím LDC a LLVM) může fungovat v jakémkoli prostředí WebAssembly, jako je moderní webový prohlížeč ( Google Chrome , Mozilla Firefox , Microsoft Edge , Apple Safari ) nebo vyhrazené virtuální stroje Wasm.

Vývojové nástroje

Editoři a integrované vývojové prostředí (IDE) podporující zvýraznění syntaxe a částečné doplňování kódu pro jazyk patří SlickEdit , Emacs , vim , SciTE , Smultron , Dia a Geany mezi ostatními.

  • Dexed (dříve Coedit), D zaměřené grafické IDE napsané v Object Pascal
  • Mono-D je multiplatformní grafické IDE zaměřené na D platformy založené na MonoDevelop / Xamarin Studio, vytvořené převážně v jazyce C Sharp.
  • Pluginy Eclipse pro D zahrnují DDT a Descent (mrtvý projekt).
  • Integraci Visual Studia zajišťuje VisualD.
  • Integrace kódu Visual Studio s rozšířeními jako Dlang-Vscode nebo Code-D.
  • Pro TextMate je k dispozici balíček a IDE Code :: Blocks obsahuje částečnou podporu pro jazyk. Standardní funkce IDE, jako je dokončení kódu nebo refaktoring, však zatím nejsou k dispozici, i když v Code :: Blocks fungují částečně (kvůli podobnosti D s C).
  • Xcode 3 plugin "D pro Xcode" umožňuje projekty a vývoj D-založené.
  • K dispozici je plugin pro automatické dokončování KDevelop (stejně jako jeho backend textového editoru, Kate).

Existují open source D IDE pro Windows , některé napsané v D, například Poseidon, D-IDE a Entice Designer.

D aplikace lze ladit pomocí libovolného ladicího programu C/C ++, jako je GDB nebo WinDbg , ačkoli podpora různých jazykových funkcí specifických pro D je extrémně omezená. V systému Windows lze programy D ladit pomocí Ddbg nebo nástrojů pro ladění společnosti Microsoft (WinDBG a Visual Studio) po převedení informací o ladění pomocí cv2pdb . ZeroBUGS debugger pro Linux má experimentální podporu pro jazyk vývoje. Ddbg lze použít s různými IDE nebo z příkazového řádku; ZeroBUGS má vlastní grafické uživatelské rozhraní (GUI).

DustMite je výkonný nástroj pro minimalizaci zdrojového kódu D, užitečný při hledání problémů s kompilátorem nebo testy.

dub je populární správce balíčků a sestavení pro aplikace a knihovny D a je často integrován do podpory IDE.

Příklady

Příklad 1

Tento ukázkový program vytiskne argumenty příkazového řádku. mainFunkcí je vstupní bod D programu, a argsje pole řetězců představujících argumenty příkazového řádku. A stringv D je řada znaků, reprezentovaná immutable(char)[].

import std.stdio: writefln;

void main(string[] args) {
    foreach (i, arg; args)
        writefln("args[%d] = '%s'", i, arg);
}

foreachProhlášení může iteraci žádnou sbírku. V tomto případě vytváří z pole posloupnost indexů ( i) a hodnot ( arg) args. Index ia hodnota argmají své typy odvozené z typu pole args.

Příklad 2

Následující text ukazuje několik schopností D a kompromisů návrhu D v krátkém programu. Iteruje přes řádky pojmenovaného textového souboru words.txt, který obsahuje na každém řádku jiné slovo, a vytiskne všechna slova, která jsou přesmyčky jiných slov.

import std.stdio, std.algorithm, std.range, std.string;

void main() {
    dstring[] [dstring] signature2words;

    foreach (dchar[] w; lines(File("words.txt"))) {
        w = w.chomp().toLower();
        immutable signature = w.dup.sort().release().idup;
        signature2words[signature] ~= w.idup;
    }

    foreach (words; signature2words) {
        if (words.length > 1) {
            writeln(words.join(" "));
        }
    }
}
  1. signature2wordsje vestavěné asociativní pole, které mapuje klíče dstring (32-bit / char) na pole dstrings. Je to podobné jako defaultdict(list)v Pythonu .
  2. lines(File())líně vytváří řádky s novým řádkem. Poté musí být zkopírován, idupaby se získal řetězec, který se použije pro hodnoty asociativních polí ( idupvlastnost polí vrací neměnný duplikát pole, což je vyžadováno, protože dstringtyp ve skutečnosti je immutable(dchar)[]). Vestavěná asociativní pole vyžadují neměnné klíče.
  3. ~=Operátor připojí nový dstring k hodnotám přidružené dynamické pole.
  4. toLower, joina chompjsou řetězcové funkce, které D umožňuje použití se syntaxí metody. Název těchto funkcí je často podobný řetězcovým metodám Pythonu. V toLowerpřevede řetězec na malá písmena, join(" ")připojí pole řetězců do jednoho řetězce za použití jediného prostoru jako oddělovač, a chompodstraňuje nový řádek od konce řetězce, pokud je přítomen. Je w.dup.sort().release().idupčitelnější, ale ekvivalentní release(sort(w.dup)).idupnapříklad. Tato funkce se nazývá UFCS (Uniform Function Call Syntax) a umožňuje rozšířit všechny vestavěné nebo balíčky třetích stran o funkce podobné metodám. Styl psaní kódu, jako je tento, je často označován jako potrubí (zvláště když jsou použité objekty líně počítány, například iterátory / rozsahy) nebo rozhraní Fluent .
  5. Je sortto funkce std.algorithm, která třídí pole na místě a vytváří jedinečný podpis pro slova, která jsou navzájem přesmyčky. release()Metoda na zpáteční hodnotě sort()je po ruce, aby kód jako jediný výraz.
  6. Druhý foreachiteruje na hodnotách asociativního pole, je schopen odvodit typ words.
  7. signature je přiřazen k neměnné proměnné, jeho typ je odvozen.
  8. dchar[]Místo normálního UTF-8 se používá UTF-32,char[] jinak jej sort()odmítá třídit. Existují účinnější způsoby, jak napsat tento program pomocí pouze UTF-8.

Využití

Mezi významné organizace, které pro projekty používají programovací jazyk D, patří Facebook , eBay a Netflix .

D byl úspěšně použit pro AAA hry , překladače jazyků, virtuální stroje, jádro operačního systému , programování GPU , vývoj webu , numerická analýza , aplikace GUI , informační systém pro cestující , strojové učení, zpracování textu, webové a aplikační servery a výzkum.

Viz také

Reference

Další čtení

externí odkazy