A C és C++ programozók számára a D utasítások ismerősek lesznek, néhány érdekes újdonsággal kibővítve.
Blokk-, kifejezés- és deklarációs utasítások ugyanolyanok mint a C/C++-ban, az utasítások ;-vel vannak elválasztva egymástól.
A goto, continue és break utasítások ugyanúgy megtalálhatók a D nyelvben mint a C++-ban, ugyanazzal a jelentéssel.
A synchronize, try-catch-finally és throw megvalósításokat szintén megtartották ebben a nyelvben, működésük hasonló a C++-beli működéshez.
A C és C++ programozók számára a D kifejezések a megszokottak lesznek néhány érdekes kiegészítéssel.
Hacsak nincs másképp specifikálva, az implementáció nincs megkötve abból a szempontból, hogy egy kifejezés komponenseit milyen sorrendben értékelje ki. Hiba akkor lép fel a kiértékelés sorrendjétől függően, ha az nincs specifikálva. Például a következő kifejezések illegálisak:
Ha a fordító meg tudja határozni, hogy egy kifejezés eredménye illegális-e a kiértékelés sorrendjétől függően, akkor jelezheti a hibát.
Előbb a baloldali operandus, majd a jobboldali operandus értékelődik ki. A kifejezés típusa a jobboldali operandus típusa lesz, és az eredmény a jobboldali operandusban jelenik meg.
A jobboldali operandus impliciten átkonvertálódik a baloldali operandus típusára, és hozzárendelődik. Az eredmény típusa a balérték típusa lesz, és az eredmény értéke a balérték lesz miután kiértékelődött.
A baloldali operandusnak egy balértéknek kell lennie.
+= -= *= /= %= &= |= ^= <<= >>= >>>=
Az értékadó operátor kifejezések alakja: a op= b, ami szemantikusan ekvivalens az a = a op b alakkal, azzal a különbséggel, hogy az a operandus csak egyszer értékelődik ki.
OrOrExpression ? Expression : ConditionalExpression
Az első kifejezés boolean típusúra konvertálódik át, majd kiértékelődik. Ha ez igaz, akkor a második kifejezés értékelődik ki, majd ennek eredménye lesz az eredeti kifejezés eredménye. Ha az első kifejezés értéke hamis, akkor a harmadik kifejezés értékelődik ki, és ez lesz az eredmény. Ha a második vagy a harmadik kifejezés típusa void, akkor az eredmény típusa is void lesz. Egyébként a második és harmadik kifejezés típusa impliciten átkonvertálódik egy egyszerű típussá, és ez lesz az eredmény típusa.
AndAndExpression || AndAndExpression
Egy vagyvagy kifejezés eredményének típusa boolean lesz, kivéve ha a jobb operandus típusa void -> ekkor az eredmény is void lesz.
Először a baloldali operandus értékelődik ki, amelynek típusa boolean lesz. Ha ez igazra értékelődik ki, akkor a jobboldali operandus nem értékelődik ki, az eredmény true lesz feltéve, hogy az eredmény típusa boolean. ha a baloldali operandus hamis, akkor az eredmény a jobboldali operandus eredményének boolean-ra konvertált értéke lesz.
OrExpression && OrExpression
Egy ésés kifejezés eredményének típusa boolean, de ha a jobboldali operandus típusa void, akkor az eredmény is void lesz.
Először a baloldali operandus értékelődik ki. Ha ennek booleanra konvertált eredménye false, akkor a jobboldali operandus nem értékelődik ki, az eredmény false lesz. Egyébként az eredmény a jobboldali operandus booleanra konvertált értéke lesz.
A bitwise kifejezések bitenkénti műveleteket végeznek az operandusaikon. Az operandusok beépített típusúak kell hogy legyenek.
XorExpression | XorExpression
AndExpression ^ AndExpression
EqualExpression & EqualExpression
RelExpression == RelExpression //egyenlőségvizsgálat
RelExpression != RelExpression // igaz, ha nem egyenlő
A C, C++-ban megszokott módon működik.
Lebegőpontos típus esetén bonyolultabb az egyenlőségvizsgálat. A -0 és a +0 egyenlők. Ha az egyik vagy mindkét operandus NaN, akkor az == és a != is false értéket ad vissza. Egyébként a szokásos módon történik az összehasonlítás.
Komplex számok esetén az egyenlőség a következőképpen van definiálva:
az egyenlőtlenség pedig:
Az osztály objektumokra az egyenlőség az Object.eq() meghívásával dönthető el. Két null objektum egyenlő, ha csak az egyik objektum null, akkor nem egyenlők.
A statikus és dinamikus tömböknél az egyenlőséget a tömbök hosszának egyenlősége és összes elemeinek egyenlősége adja.
RelExpression === RelExpression
RelExpression !== RelExpression
A === azonosságot vizsgál, a !== a nem azonosságot nézi. Az eredmény típusa boolean.
Ha az operandusok típusa nem osztály objektum, statikus vagy dinamikus tömbök, akkor az azonosság ugyanazt jelenti, mint az egyenlőség.
Osztály objektum esetén az azonosság azt jelenti, hogy az objektum referenciák ugyanarra az objektumra mutatnak.
Statikus és dinamikus tömbök esetén az azonosság a tömbelemek azonosságára vonatkozó azonosságot jelenti.
< <= > >= !<>= !<> <> <>= !> !>= !< in
A beépített típusokra a szokásos módon működik.
Osztály objektumok esetén az Object.cmp()-t hívjuk meg a baloldali operandusra, 0-t adunk meg jobboldali operandusként. Például az (o1 op o2) relációs kifejezést a következő formában kell megadni:
Hibát ad, ha az egyik objektum null.
Statikus és dinamikus tömbök esetén az op reláció a tömbök első nem egyenlő elemét hasonlítja össze. Ha a két tömb egyenlő, de különböző hosszúságúak, akkor a rövidebb tömb "kevésbé" lesz összehasonlítva, mint a hosszabb tömb. (????)
Számok összehasonlítása a szokott módon a <, >, <=, >=, ==, != relációkkal történik. Hibát eredményez az összehasonlítás a <, <=, >, >= relációk esetén, ha az egyik operandus signed, a másik pedig unsigned.
Ha az egyik vagy mindkét operandus lebegőpontos, akkor lebegőpontos összehasonlítást végzünk.
14 lehetséges összehasonlítást mutat be az alábbi táblázat, ahol az unordered jelentése: az egyik vagy mindkét operandus NaN:
Operator | Greater Than | Less Than | Equal | Unordered | Exception | Relation |
== | F | F | T | F | no | equal |
!= | T | T | F | T | no | unordered, less, or greater |
> | T | F | F | F | yes | greater |
>= | T | F | T | F | yes | greater or equal |
< | F | T | F | F | yes | less |
<= | F | T | T | F | yes | less or equal |
!<>= | F | F | F | T | no | unordered |
<> | T | T | F | F | yes | less or greater |
<>= | T | T | T | F | yes | less, equal, or greater |
!<= | T | F | F | T | no | unordered or greater |
!< | T | F | T | T | no | unordered, greater, or equal |
!>= | F | T | F | T | no | unordered or less |
!> | F | T | T | T | no | unordered, less, or equal |
!<> | F | F | T | T | no | unordered or equal |
Megjegyzés:
ShiftExpression in ShiftExpression
Egy asszociatív tömb esetén ellenőrizni lehet, hogy egy elem eleme-e a tömbnek:
Az in kifejezésnek ugyanolyan precedenciája van, mint a relációs kifejezéseknek: <, <= -nak, stb.
AddExpression << AddExpression
AddExpression >> AddExpression
AddExpression >>> AddExpression
Az operandusoknak beépített típusúaknak kell lenniük. Az eredmény típusa a baloldali operandus típusa lesz. Az eredmény értéke a jobboldali operandus értékével való léptetés eredménye lesz.
MulExpression + MulExpression
MulExpression - MulExpression
Beépített típusok esetén szokásos.
Ha az egyik operandus lebegőpontos, akkor a másik operandus impliciten átkonvertálódik erre a típusra, végül az aritmetikai konverzió hajtódik végre ha szükséges.
Ha az első operandus egy pointer, a második pedig egy beépített típus, akkor az eredmény típusa az első operandus típusa lesz, az eredmény értéke pedig a pointer plusz (vagy mínusz) a második operandus szorozva az első operandus típusának méretével.
A + operátor esetén, ha mindkét operandus tömb kompatíbilis típussal, akkor az eredmény is tömb lesz kompatíbilis típussal, és az értéke a két tömb konkatenációja lesz.
UnaryExpression * UnaryExpression
UnaryExpression / UnaryExpression
UnaryExpression % UnaryExpression
Aritmetikai típusokra a szokásos módon működik, az osztás vagy a modulusképzés a DivideByZeroException kivételt dobja, ha a jobboldali operandus 0.
Lebegőpontos operandusok esetén a műveletek megfelelnek az IEEE 754 lebegőpontos ekvivalenciának. A modulusképzés csak valós számok esetén alkalmazható, képzetes vagy komplex számokra nem.
& ++ -- * - + ! ~ delete new ( Type ) ( Type ) . Identifier
A C-ben és a C++-ban a cast kifejezés alakja a következő:
(type) unaryexpression
Ez viszont kétértelmű, ugyanis:
Ez most a p negáltjának a dereferenciája lesz a foo típusra, vagy a p a foo-bóI van kivonva? Ezt csak úgy lehetne eldönteni, hogy a szimbólumtáblában megnézzük, hogy a foo egy típus vagy egy változó. Viszont a D tervezésekor az volt az egyik cél, hogy ne kelljen a szimbólumtáblához fordulni ilyen esetben. Ezért más szintaxisra volt szükség.
C++ ezt a következőképpen oldja meg:
ami nem szép megoldás. A D-ben bevezették a cast kulcsszót:
A D-nek nincs a Java-hoz hasonló instanceof operátora, mivel a cast operátor ugyanennek a funkciónak felel meg:
Java:
D:
Identifier this super null true false NumericLiteral StringLiteral AssertExpression Type . Identifier
AssertExpression: assert ( Expression )
Az assert-ek kiértékelik az expression-t. Ha az eredmény false, akkor egy AssertException kivétel lép fel. Ha az eredmény true, akkor nincs kivétel. Akkor lép fel hiba, ha az expression bármilyen mellékhatást tartalmaz, ami a programtól függ. Egy assert kifejezés eredményének típusa void lesz. Az assert-ek alapvető részei a Design by Contract-nak (DBC) amelyet a D támogat.
Az utasításokat el lehet látni címkével. A címke egy azonosító, ami megelőz egy utasítást.
LabelledStatement: Identifier ':' Statement
Bármilyen, még az üres utasítást is meg lehet címkézni, ezzel segítve a goto, break és continue utasításokat.
GotoStatement:
goto Identifier ;
goto default ;
goto case ;
goto case Expression ;
A goto hatására a vezérlés a goto után megadott cimkén folytatódik.
goto default; esetén a tartalmazó switch utasítás default ágához ugrik.
goto case; a tartalmazó switch utasítás következő case ágában lévő utasításhoz ugrik.
goto case expression; a tartalmazó switch utasítás Expression-t tartalmazó ágához ugrik.
Minden közbeeső finally végrehajtásra kerül és minden szinkronizációs mutex felszabadul (release)
Goto-t nem lehetséges inicializáció kihagyására használni.
IfStatement:
if ( Expression ) Statement
if ( Expression ) Statement else Statement
A szokásos módon működik. Egy 'kallódó' else ág megegyezés szerint a legközelebbi if utasításhoz tartozik.
SwitchStatement:
switch ( Expression ) BlockStatement
CaseStatement:
case Expression : Statement
DefaultStatement:
default: Statement
A switch feltétele kiértékelődik, melynek eredménytípusa beépített típus, char[] vagy wchar[] kell hogy legyen. Az ennek megfelelő case ág végrehajtódik. Ha nincs megfelelő ág, akkor a default ág hajtódik végre. Ha nincs default ág, akkor SwitchException kivétel lép fel. Csak egy default ág lehet.
A case ág utasítássorozatai és a default ág utasítássorozatai blokkba ágyazottak is lehetnek, nem kell a legkülső blokkban lenniük. Például a következő forma megengedett:
A C és C++-hoz hasonlóan a case utasítás nem állítja meg a "lefelé csordogálást", a break utasítással lehet kiugrani a blokkból. Például a következő utasítás 4-et ad eredményül, ha az i=1 volt:
Megjegyzés: A C és C++-al ellentétben stringet is használhatunk a switch kifejezésében! Például:
WhileStatement: while ( Expression ) Statement
Addig fut, amíg az Expression hamis értéket nem ad. Egy break utasítás hatására kiugrunk a ciklusból. Egy continue utasítás hatására a ciklus az Expression kifejezés vizsgálatával folytatódik. Lásd C++-nál.
DoStatement: do Statement while ( Expression )
A Statement egyszer biztosan végrehajtódik. Ha az Expression igazra értékelődik ki, újra végrehajtódik a ciklusmag.
A break -kel kiugrunk a ciklusból, a continue-val újra kiértékeljük a feltételt.
ForStatement: for (Initialize; Test; Increment) Statement
Hasonlóan működik mint a C++-beli for ciklus.
A break-ke kiugrunk, a continue-val az Increment-tel folytatódik a program.
Az Initializer-ben deklarálhatjuk a ciklusváltozót, amit a ciklusmagban is használhatunk:
A függvénytörzs nem lehet üres:
Helyette használjunk üres blokk-utasítást:
Az Initializer és a Test elhagyható. Ha nincs megadva Test, akkor az olyan, mintha mindig a true érték állna ott.
A foreach utasitás egy collection (gyűjtemény) elemein iterál
ForeachStatement:
Foreach (ForeachTypeList; Aggregate) NoScopeNonEmptyStatement
Foreach:
foreach
foreach_reverse
ForeachTypeList:
ForeachType
ForeachType , ForeachTypeList
ForeachType:
inout Type Identifier
Type Identifier
inout Identifier
Identifier
Aggregate:
Expression
Tupleu
A collection kiértékelődik. Statikus tömb, dinamikus tömb, asszociatív tömb, struktúra, osztály, delegate, vagy tuple(rendezett n-es) típusok valamelyikére kell kiértékelődnie.
A NoScopeNonEmptyStatement a collection minden elemére végrehajtódik egyszer. Minden iteráció elején a ForeachTypeList-ben megadott változók felveszik a csoport egyes elemeinek értékét.
Ha a változó inout típusú akkor referencia adódik át az elemre, különben másolás történik.
A collection a ciklus invariánsa kell hogy legyen, azaz egyetlen elem sem adható a csoporthoz illetve távolítható el belőle a NoScopeNonEmptyStatement-ben.
Ha a csoport statikus vagy dinamikus tömb, akkor egy vagy két változót deklarálhatunk.
Ha egyet, akkor a változó a tömbbeli elemek értékét veszi fel egyenként. Értelemszerűen a változó típusa meg kell hogy egyezzen a tömb elemeinek típusával (kivéve a lent vázolt esetben)
Ha kettőt, akkor az első változó az index, míg a második változó az érték. Az index csak int vagy uint típusú lehet, és nem lehet inout módú. Az index értéke a tömbelem aktuális elemének indexe lesz.
Pl.:
A foreach utasításnál a tömb a 0-s kezdőindextől iterálódik a tömb hosszáig (maximum), míg foreach_reverse esetén az iteráció fordított irányú.
Ha a collection char, wchar vagy dchar típusokból álló statikus vagy dinamikus tömb akkor az érték típusa bármelyik lehet a char, wchar, dchar közül. Eszerint bármelyik UTF tömböt átkonvertálhatjuk bármelyik másikká:
A csoport lehet string literál is, és ebben az esetben char, wchar vagy dchar típusú tömbként érhetjük el:
Ami a következő kimenetet adja:
Ha a csoport asszociatív tömb, akkor egy vagy két változó lehet definiálva:
Ha egy, akkor a változó értéke a tömb elemeinek értéke egyenként
Ha kettő, akkor az első változó az index, míg a második változó az érték. Az index típusa meg kell egyezzen az asszociatív tömb indexeinek típusával, és nem lehet inout módú. Az index értéke a tömbelem aktuális elemének indexe lesz.
Abban az esetben ha asszociatív tömb esetén az elemek sorrendje nem definiált a foreach_reverse nem értelmezett. (foreach viszont igen)
Ha struct vagy class típusú, a foreach egy speciális opApply member függvény segítségével van definiálva. A foreach_reverse pedig a speciális opApplyReverse memberrel. Ha az osztályra szeretnénk használni a foreach, illetve foreach_reverse utasításokat, akkor ezekben a speciális függvényekben a típus meg kell egyezzen a ForeachType típussal.
ahol
Több ForeachType megfelel több Type-nak az opApply vagy opApplayReverse függvényekben.
Több opApplay és opApplayReverse függvény is lehetséges (túlterhelés/polimorfizmus). A megfelelőt a dg típusával választja ki a fordító, úgy hogy megegyezzen a ForeachType-al az ForeachStatement-ben. A függvények törzse iterál a collection elemein, és átadja őket a dg függvénynek. Ha a dg 0-val tér vissza, akkor veszi a következő elemet (következő iterációs lépés) Ha dg nem 0-val tér vissza akkor az iteráció megáll és a függvény visszatér azzal az értékkel. Ha az iteráció befejeződött (végigment az összes elemen) a függvény 0-val visszatér.
Például vegyünk egy 2 elemet tároló osztályt:
Ezt használhatjuk pl az alábbi kódban:
És a következő eredményt kapjuk:
Ha a csoport egy delegate, akkor a delegate típusa megegyezik az opApply típusával. Ez lehetővé teszi több különböző iterációs stratégia működését ugyanabban az osztályban vagy struktúrában.
Inout használatával felülírhatjuk az eredeti elemeket:
Eredmény:
De: az index nem lehet inout típusú
Ha a Types a ForeachType-ban nem definiált akkor meghatározható a csoport típusából.
A csoportot az iteráció alatt nem lehet átméretezni, újraallokálni, felszabadítani, vagy megsemmisíteni:
Ha a csoport egy tuple akkor egy vagy két változó deklarálható:
Ha egy, akkor a változó értéke a tuple elemeinek értéke egyenként. Ha a változó típusa adott akkor meg egyezzen a tuple elemeinek típusával. Ha nincs megadva a változó típusa automatikusan a tuple elemeinek típusa lesz amely iterációs lépésenként változhat.
Ha kettő, akkor az első változó az index, míg a második változó az érték. Az index típusa int vagy uint lehet, és nem lehet inout. Az index értéke a tuple aktuális elemének indexe lesz.
Ha a tuple egy típuslista akkor a foreach utasítás végrehajtódik egyszer minden típusra, és az érték egy alias lesz típusra.
Eredmény:
A foreach törzsében elhelyezett break utasítás hatására kilép a foreach-ből, míg continue utasításra a következő iterációs lépésbe kezd.
ContinueStatement:
continue;
continue Identifier ;
A continue abortálja a tartalmazó ciklus aktuális iterációját, és a következő iterációs lépésre ugrik.
Érvényes a while, for, do ciklusokra.
Ha a continue-t egy azonosító követi, akkor az egy címke egy tartalmazó while, for vagy do ciklusra, és a ciklus következő iterációja kerül végrehajtásra. Amennyiben a címke érvénytelen, hiba lép fel.
Minden közbeeső finally végrehajtódik, és minden közbeeső szinkronizációs objektum szabaddá válik (release)
Megjegyzés:
Ha egy finally egy return throw vagy goto utasítást hajt végre amely elhagyja a finally-t a continue célját nem lehet elérni!
BreakStatement:
break;
break Identifier ;
A break kilép az őt tartalmazó utasításból, és a soron következő utasítást hajtja végre. Érvényes a legbelső while, for, do, vagy switch utasításokra.
Ha a breaket egy azonosító követi akkor az egy címke a tartalmazó while, for, do, vagy switch utasításra, és ennek hatására abból az utasításból lép ki. Amennyiben a címke érvénytelen, hiba lép fel.
Minden közbeeső finally végrehajtódik, és minden közbeeső szinkronizációs objektum szabaddá válik (release)
Ha egy finally egy return throw vagy goto utasítást hajt végre amely elhagyja a finally-t akkor a break célját nem lehet elérni.
Overloading tökéletes eszköz speciális egy, vagy kétoperandusú tagfüggvények implementálására.
Túlterhelhető Egyértékű Operátorok
op | opfunc |
- | neg |
~ | com |
e++ | növelés |
e-- | Csökkentés |
Egyértékű túlterhelést ad.
op : operátor ; opfunc : a megfelelő osztály vagy struktúra függvény neve. A szintaxis:
ahol a egy osztály vagy struktúra referencia. Interpretációja a következőképpen történik:
Mióta ++e szemantikája úgy van definiálva, hogy szemantikája megegyezzen e+=1 -gyel, ++e kifejezés e+=1 alakra újraírható, és eztán az operátor túlterhelés ellenőrzése kész van. A helyzet –e-vel hasonló.
Például:
Túlterhelhető Bináris Operátorok
op | kommutatív? | opfunc | opfunc_r |
+ | igen | add | - |
- | nem | sub | sub_r |
* | igen | mul | - |
/ | nem | div | div_r |
% | igen | mod | mod_r |
& | nem | and | - |
| | igen | or | - |
^ | igen | xor | - |
<< | nem | shl | shl_r |
>> | nem | shr | shr_r |
>>> | nem | ushr | ushr_r |
~ | nem | cat | cat_r |
== | igen | eq | - |
!= | igen | eq | - |
< | igen | cmp | - |
<= | igen | cmp | - |
> | igen | cmp | - |
>= | igen | cmp | - |
+= | nem | addass | - |
-= | nem | subass | - |
*= | nem | mulass | - |
/= | nem | divass | - |
%= | nem | modass | - |
&= | nem | andass | - |
|= | nem | orass | - |
^= | nem | xorass | - |
<<= | nem | shlass | - |
>>= | nem | shrass | - |
>>>= | nem | ushrass | - |
~= | nem | catass | - |
Kétoperandusú túlterhelést tesz lehetővé, az op az operátor, az opfunc a megfelelő osztály vagy struktúra függvénye, a szintaxis a következő:
kiértékelése megegyezik, mintha a következőt írtuk volna:
vagy:
A következő szabály sorozatot alkalmazza, az alábbi sorrendben, annak meghatározására, hogy melyik formula van használva:
Ha a egy struktúra, vagy osztály referencia, amely opfunc-beli nevek valamelyikét tartalmazza, a kifejezés átírható:
Ha b egy struktúra vagy osztály referencia, amelyet az opfunc_r oszlop tartalmaz és az operátor nem kommutatív, a kifejezés átírható:
Ha b egy struktúra vagy osztály, amelyet az opfunc oszlop tartalmaz, és az operátor (op) kommutatív, a kifejezés átírható:
Abban az esetben, ha a vagy b egy struktúra vagy osztály, hiba.
Például:
Mindkét operátor az eq() függvényt használja. (a == b) kifejezés úgy is leírható, mint a.equals(b), és (a != b) mint !a.equals(b).
Az eq() függvény is az Object osztály részeként van definiálva a következőképpen:
vagyis minden osztálynak létezik eq() művelete.
Ha egy struktúrának nincs eq() függvény deklarálva akkor a két struktúrában lévő bitek összehasonlítása határozza meg az egyenlőséget, vagy a nem egyenlőséget.
Ezek az összehasonlító operátorok a cmp() függvényt használják. Az (a op a) kifejezés átírható (a.cmp(b) op 0) alakra. A kommutatív műveletek a (0 op b.cmp(a)) alakra írhatóak át.
A cmp() függvény az Object osztály műveleteként van meghatározva a következőképpen:
vagyis minden osztálynak létezik cmp() művelete.
Ha egy struktúrának nincs cmp() függvény deklarálva, akkor megkísérli a két struktúrát összehasonlítani, és ha nem sikerül hibaüzenetet küld.
Megjegyzés: Referencia és egy osztály objektum összehasonlítása lehetséges, mint:
és nem mint:
Az utóbbit átkonvertálja:
alakra, amely hibaüzenetet küld, ha cmp virtuális függvény.
Annak oka, hogy mind eq() és cmp() függvény is van definiálva az, hogy
Egyenlőség tesztelése néha sokkal eredményesebb, mint a nagyobb, vagy kisebb vizsgálat.
Néhány objektum esetében a nagyobb vagy kisebb összehasonlításnak nincs semmi értelme. Ezekben az esetekben a cmp() függvényt hatástalanítani lehet:
Egyre több operátor válik túlterhelhetővé, de némelyek, mint ., &&, ||, ?:, és még néhány soha.
ReturnStatement:
return;
return Expression ;
A return kilép az aktuális függvényből és annak visszatérési értékét szolgáltatja. Visszatérési érték akkor kell ha a függvény nem void. A kifejezés impliciten konvertálódik a visszatérési érték típusára.
Legalább egy return, throw utasítás vagy assert(0) kifejezés kell azokban a függvényekben amelyek visszatérési értéke nem void.
Akkor is adhatunk vissza egy kifejezést ha a függvény void típusú, ekkor a kifejezés kiértékelődik de nem adódik át visszatérési értékként.
Mielőtt a függvény ténylegesen visszatérne, minden automatikus objektum törlődik, minden finally és scope utasítás végrehajtásra kerül, és minden szinkronizációs objektum felszabadul (release)
A függvény nem tér vissza ha bármelyik finally-ben return goto vagy throw utasítás van amely elhagyja a finally-t.
Ha van kilépési postcondition (lásd szerződés), akkor az végrehajtódik miután a kifejezés kiértékelődött, de mielőtt a függvény visszatérne.
WithStatement: with ( Expression ) BlockStatement
A with jelentése ugyanaz, mint a C++-ban, az Expression egy objektum referenciát értékel ki. Ennek mezőire lehet hivatkozni a with -en belül minősítés nélkül.
Megjegyzés: az Expression csak egyszer értékelődik ki.
A synchronized utasítás a kritikus szakaszokat veszi körül, és ezzel szinkronizálja a szálak egyidejű hozzáférését a blokkhoz.
SynchronizedStatement:
synchronized ScopeStatement
synchronized ( Expression ) ScopeStatement
A szinkronizációval elérhető, hogy egyszerre csak egy szál hajthassa végre a szinkronizációs utasítást (ScopeStatement)
A szinkronizációs kifejezés -ahol az Expression egy objektum referencia- biztosítja, hogy egyszerre csak egy szál használhassa az objektumot a ScopeStatement végrehajtására. Ha az Expression egy Interface, akkor Object-re konvertálódik (cast) .
A szinkronizáció befejeződik ha a ScopeStatement végrehajtódik kivétellel, goto, vagy return utasítással.
Példa: synchronized { ... }
VolatileStatement:
volatile Statement
volatile ;
Az utasítás kiértékelődik. Memóriába írás csak a Statement végrehajtása előtt, az olvasások előtt akár a Statement-ben akár utána. Olvasás ennek megfelelően a Statement után, és az összes írás után akár a Statement előtt vagy benne.
A volatile utasítás azonban nem garantálja az atomi végrehajtást. Ha azt szeretnénk, használjuk a Synchronized utasítást.
A magas szintű nyelvbe beépített assemblert támogatja a D nyelv az asm utasítással:
AsmStatement: asm { } asm { AsmInstructionList } AsmInstructionList: AsmInstruction ; AsmInstruction ; AsmInstructionList
Egy asm utasítás megengedi az assembly nyelv parancsainak közvetlen használatát. Egyszerűen lehet kezelni a speciális CPU felületet anélkül, hogy az assemblerhez kellene fordulnunk. A D fordító felügyel a függvényhívási konvenciókra, verem-beállításokra, stb.
Az utasítások formája természetesen erősen függ a CPU környezeti beállításaitól. De a következő formátumra vonatkozó konvenciók érvényesek:
Ezek a szabályok biztosítják, hogy a D forráskódot a szintaktikus és szemantikus elemzőtől függetlenül lehessen tokenizálni.
Például Intel Pentium-on:
A D-nek nincs volatile tároló típusa. A volatile-t tipikusan hardware regiszterek elérésére használják, így a magas szintű nyelvbe beépített assembler alkalmas ilyen esetekre, mint például:
Néhány D megvalósítás, mint például a D-ről C-re fordító, a magas szintű nyelvbe beépített assemblert nem érzékeli, ezért nem szükséges ezt implementálni. A version utasítást használják ennek bejegyzésére/igazolására:
Pragma:
pragma ( Identifier )
pragma ( Identifier , ExpressionList )
ExpressionList:
ExpressionList , Expression
Expression
A pragmák arra valók, hogy speciális információt adjunk át a fordítónak valamint implementáció-specifikus kiegészítéseket adjunk a D-hez. A pragmák önmagukban is állhatnak, ekkor ';'-val végződnek. De meghatározhatnak egy kifejezést, kifejezések blokkját, egy deklarációt vagy deklarációk egy blokkját.
A pragma fajtáját az Identifier rész határozza meg. Az ExpressionList AssignExpressions részek (tehát kifejezések) vesszővel elválasztott listája. Szintaktikusan helyesnek kell lenniük, de a szemantikája a pragma fajtájától függ.
Minden implementációnak támogatnia kell a következő pragmákat (minimum figyelmen kívül kell hagynia):
msg
Fordítás alatt egy szöveget ír ki, az AssignExpressions-nak string literálnak kell lenni:
lib
Egy direktívát helyez el az object-fájlban, ezáltal a paraméterben megadott programkönyvtárat a szerkesztő csatolni fogja. Az AssignExpressions-nak string literálnak kell lenni:
startaddress
Egy direktívát helyez el az object-fájlban, minek hatására a szerkesztőprogram a program kezdőcímét a paraméterben megadott függvényre állítja:
Fordító-specifikus pragmák:
Fordító-specifikus pragmák definiálhatók, ha a fordítóprogram készítő szervezet vagy cég nevével kezdődnek (prefixe), hasonlóan, mint a verzió-azonosítóknál:
A fordítóprogramnak hibát kell jeleznie, ha ismeretlen pragmával találkozik, akkor is, ha ezek fordító specifikusak (nyilván egy másik fordítóról van szó, mert a sajátját csak felismeri). Ebből következik, hogy ezeket a pragmákat érdemes version blokkba ágyazni: