|
در بسیاری کامپیوترها ،اعمال با دقت بالا بیشتر از اعمال با دقت کمتر وقت نمی گیرند .این باعث می شوند که مفاهیم شمارشی بالاترین دقت ممکن را برای اعمال داخلی موقتی به کار ببرند . فلسفه مورد بحث این نیست که زبان را به پائین مقسوم علیه سخت افزاری محدود کنیم بلکه آن را قادر به بهرهبرداری از بهترین توانایی های سخت افزار مورد نظر نماییم .
برای اعمال ممیز شناور و مقادیر واسطه دستورات یک دقت بالاتر می تواند به کار رود . تنها حد پایین دقت توسط نوع عملوندها مشخص می شود نه حد بالای آن . نکته پیاده سازی : در ماشین های اینتل x 86 برای نمونه انتظار می رود ( اما لازم نیست ) که محاسبات واسطه ای در دقت کامل هشتاد بیتی که توسط سخت افزار پیاده سازی می شود انجام شود .
امکان دارد که در مسیر استفاده از مقادیر موقت و زیر عبارات معمول ، کد بهینه شده یک جواب دقیقتر از کد بهینه نشده فراهم سازد .
الگوریتم ها باید طوری نوشته شود که براساس حداقل دقت محاسبات کار کند . آنها نباید در مواقعی که دقت واقعی بالاتر است افت عملکرد یابند یا شکست بخورند . انواع double یا float برخلاف نوع گسترش یافته فقط باید در موارد زیر به کار رود :
۱. کاهش مصرف حافظه برای آرایه های بزرگ .
۲. داده ها و آرگومان های توابع سازگار با C .
در زبان های موجود ، یک تلاش عجیب برای به زور جا دادن انواع مختلط در تسهیلات تعریف نوع موجود مانند قالب ها ،ساختمان ها و … وجود داردو تمام این ها معمولاً در نهایت با شکست مواجه میشود.
شکست می خورند چون مفاهیم اعمال مختلط می تواند بسیار دقیق باشد و کامپایلر نمی داند که برنامه نویس در تلاش برای انجام چه کاری است بنابراین نمی تواند پیاده سازی معنایی را بهینه نماید .
تمام این کارها برای اجتناب از اضافه کردن یک نوع جدید انجام شده است . اضافه کردن یک نوع جدید بدین معناست که کامپایلر می تواند تمامی مفاهیم اعمال مختلط را دقیق پیاده کند . پس برنامه نویس می تواند بر یک پیاده سازی صحیح ( یا حداقل دارای ثبات ) اعداد مختلط اعتماد کند .
همراه بودن با یک بسته نوع مختلط برای یک نوع موهومی مورد نیاز است .یک نوع موهومی برخی از پیامدهای ظریف معنایی را حذف می کند و کارآیی را بهبود می بخشد بدون اینکه مجبور به انجام اعمال اضافی روی قسمت حقیقی واضح صفر ، باشیم . الفاظ موهومی دارای یک پسوند i می باشند .
هیچ املای خاص برای نوع مختلط وجود ندارد فقط یک نوع حقیقی و موهومی را با هم جمع کنید :
افزودن دو نوع جدید به زبان کافی است از این رو انواع مختلط و موهومی دارای دقت توسعه یافته هستند . هیچ نوع اعشاری مختلط و موهومی یا نوع دابل مختلط یا موهومی وجود ندارد ( توجه : راه برای افزودن آنها در آینده باز است ) .
اعداد مختلط دارای دو صفت خاصه هستند :
c . re is 4.5
c . im is 2i
حسابگر ممیز شناور IEEE 754 شامل توانایی تنظیم کردن چهار روش گرد کردن است . D املایی خاص برای دسترسی به آنها افزوده است : [ blah , blah , blah ]
حسابگر ممیز شناور IEEE 754 می تواند پرچمهای مختلف را براساس آن چه در یک محاسبه رخ داده است تنظیم نماید : [ blah , blah , blah ]. این پرچمها می توانند به وسیله املای زبان SET / Reset شوند .
علاوه بر عملگرهای مقایسه معمولی < , < = , > , >= , == , != زبان D تعداد بیشتری که خاص اعداد ممیز شناور است اضافه می کند .
هر برنامه غیر جزیی نیاز به تخصیص و آزاد سازی حافظه دارد . هر چه پیچیدگی ، اندازه و کارآیی برنامه ها افزایش می یابد تکنیکهای مدیریت حافظه مهمتر می شوند . D اختیارات متعددی در زمینه مدیریت حافظه پیشکش می کند .
سه روش پایه تخصیص حافظه در D :
۱. داده استاتیک : در سگمنت داده پیش فرض تخصیص می یابند .
۲. داده پشته : در پشته برنامه CPU تخصیص می یابند .
۳. داده زباله جمع آوری شده : به صورت پویا در heap جمع آوری زباله تخصیص می یابند .
قسمت بعدی تکنیک ها را برای استفاده از آنها توضیح می دهد به همراه برخی قابلیت های پیشرفته:
رشته ها ( و آرایه ها ) copy – on – write
فرستادن یک آرایه به یک تابع را در نظر بگیرید و احتمالاً تغییر دادن آرایه و برگرداندن آرایه جدید . از آنجا که آرایه ها با ارجاع فرستاده می شوند نه با مقدار ، یک پیامد وخیم این است که ندانیم محتویات آرایه از آن کیست ؟ برای مثال تابعی که آرایه ای از کاراکترها را به حروف بزرگ برمی گرداند .
توجه کنید که نسخه []S که فراخوانی شد تغییر هم کرد شاید این اصلاً آن چیز مورد توقع نبود یا بدتر آنکه []S ممکن است تکه ای از حافظه فقط خواندنی باشد .
اگر یک کپی از S همواره توسط تابع ساخته می شد به طور ناکارا و بدون لزوم ،زمان و حافظه برای حروفی که خودشان بزرگ هستند مصرف می شد .
راه حل پیاده سازی copy – on – write است که یعنی یک کپی ساخته می شود فقط اگررشته ها نیاز به تغییر دارند . بعضی زبان های پردازنده رشته ها این عمل را به عنوان پیش فرض انجام می دهند اما هزینه بسیار سنگین است .
در نتیجه آن رشته “abcdwF” پنج مرتبه بوسیله تابع کپی می شود. برای اینکه از این قرارداد به نحوی با حداکثر کارآیی استفاده شود باید به صورت واضح در کد ظاهر شود .
copy – on – write پروتکلی است که به وسیله توابع پردازش آرایه ها در کتابخانه ی زمان اجرای phibo زبان D پیاده سازی شده است .
D زبانی دارای جمع آوی زباله کامل می باشد . بدین معنی که هیچ وقت نیاز به آزادسازی حافظه نیست . فقط به هنگام نیاز حافظه را تخصیص دهید و جمع آور زباله به طور دوره ای تمام حافظه بی استفاده را به توده حافظه آزاد برمی گرداند .
برنامه نویسان C ++ , C که به کنترل دستی حافظه هنگام تخصیص و آزاد سازی آن عادت دارند احتمالاً به مزایا و تأثیر جمع آوری زباله یقین ندارند . تجربهی پروژه های جدید که با در نظر گرفتن جمع آوری زباله نوشته شده اند همچنین پروژه های موجود که به سبک جمع آوری زباله برگردانده شده اند نشان می دهد که :
۱. برنامه های دارای جمع آور زباله سریعتر هستند . این واضح است اما دلایلی قابل بیان است .
۲. شمارش در جاعات یک روش معمول برای حل مسائل تخصیص حافظه آشکار است . کد پیاده سازی اعمال اضافه و تفریق هر جا که انتساب صورت می گیرد یکی از دلایل کندی است .
۳.پنهان کردن کد مذکور در پس کلاسهای اشاره گر هوشمند به افزایش سرعت کمک نمی کند . ( روش شمارش ارجاعات به هیچ وجه راه حل عمومی نیست جایی که ارجاعات حلقه ای هرگز حذف نمی شوند . )
۴. مخرب های کلاس برای آزادسازی منابع مورد نیاز یک شیئ به کار می رود . برای اغلب کلاسها این منابع ، حافظه تخصیص یافته است . با جمع آوری زباله اغلب مخرب ها خالی می شوند و در نهایت می توانند دور انداخته شوند .
۵. تمام مخرب هایی که حافظه را آزاد می کنند می توانند معنی دار شوند در مواقعی که اشیاء ، بر روی پشته تخصیص حافظه می یابند . برای هر کدام مکانیزمی باید در نظر گرفته شود طوری که اگر یک استثناء رخ داد تمام مخربها از هر چارچوب فراخوانی شوند تا هر حافظه تخصیص یافته برای آنها را رها کنند . اگر مخرب ها نامربوط شوند هیچ نیازی برای در نظر گرفتن چارچوب های خاص پشته برای پردازش استثناها نیست در نتیجه کد سریعتر اجرا می شود .
۶. تمام کدهای لازم برای مدیریت حافظه می تواند برای تکامل جزیی اضافه شود . برنامه بزرگتر کمتر در حافظه اصلی و بیشتر آن در حافظه مجازی قرار می گیرد و آرامتر و کندتر اجرا می شود .
۷. جمع آور حافظه هنگامی صورت می گیرد که حافظه تنگ و کم شود . تا وقتی حافظه جا دارد برنامه در حداکثر سرعت ممکن اجرا میشود و هیچ وقتی برای آزاد کردن حافظه ، صرف نمی کند .
۸.جمع آورنده های زباله مدرن ، اکنون به مراتب پیشرفته تر و سریع تر هستند . جمع آورنده های تولید کننده و کپی کننده ، قسمت عمده ناکارایی الگوریتم های جارو کردن و اختصاص دادن را حذف می کنند .
۹.جمع آورنده های زباله مدرن فشرده سازی توده حافظه را انجام می دهند . فشرده سازی توده مراقب است که تعداد صفحاتی که به طور فعال به وسیله یک برنامه ارجاع شده اند را کاهش دهد بدین معنی که دسترسی های حافظه احتمالاً بیشتر به حافظه می رسند تا به مبادله حافظه .
۱۰. جمع آورنده های زباله حافظه استفاده شده را اصلاح می کنند . بنابراین به رخنه های حافظه - که باعث می شوند برنامه های با اجرای طولانی مدت آن قدر حافظه مصرف کننده تا سیستم هنگ کند- تن در نمی دهد .
۱۱. برنامه های دارای جمع آور زباله دارای اشکالات کمتر یافتن اشاره گرها می باشند به این خاطر که هیچ ارجاع سرگردان به حافظه آزاد شده نمی ماند .
۱۲. برنامه های دارای جمع آور زباله برای گسترش و اشکال زدایی سریعترند . چون هیچ نیازی برای گسترش ، اشکال زدایی ، امتحان ، یا ابقاء کد آزاد سازی حافظه دستی وجود ندارد .
۱۳. برنامه های دارای جمع زباله به طور معنی داری کوچکترند چون هیچ کد آزادسازی حافظه وجود ندارد و از این رو نیازی به پردازشگرهای استثناها برای آزاد سازی حافظه وجود ندارد .
جمع آوی زباله یک نوشداروی همه کاره نیست بعضی اشکالات هم دارد :
۱. وقتی یک مجموعه برنامه همزمان اجرا می شود قابل پیشگویی نیست بنابراین برنامه به طور دلخواه می تواند مکث کند.
۲. زمانی که برای اجرای یک مجموعه مصرف می شود نامحدود است با اینکه در عمل بسیار کوتاه است اما ضمانتی وجود ندارد .
۳. تمام رشته های اجرا به غیر از رشته جمع آوری زباله در حالی که جمع آوری در جریان است باید مکث کند .
۱. کنترل نوع قوی تر
۲. مقدار دهی اولیه به صورت واضح مورد نیاز است
۳. مجاز نبودن متغییرهای محلی به کار نرفته
۴. عدم ' ; ' تکی در بدنه حلقه ها
۵. عمل انتساب ،مقادیر بولی بر نمی گرداند.
۶. از رده خارج کردن API های متروک
۱. عبارات اثبات صحت ( )assert
۲. کنترل مرزهای آرایه
۳. case تعریف نشده در استثنای switch
۴. استثنای تجاوز از اندازه حافظه
۵. ورودی ، خروجی و طراحی یکسان کلاس به وسیله کنتراکت
تقدم عملگر و قوانین سنجش
D عملگرهای C و قوانین تقدم آنها را حفظ می کند همچنین ترتیب قوانین سنجش و قوانین تقدم . این از اشکالات ریز که از ابتدای برنامه نمایان می شود جلوگیری می کند .
دسترسی مستقیم به API های C
نه تنها D نوع داده های مطابق با C دارد همچنین دسترسی مستقیم به توابع C را فراهم می سازد . هیچ نیازی به نوشتن توابع بسته بندی شده یا کدی برای کپی کردن اجزای متراکم یک توده به صورت یک به یک نیست.
پشتیبانی از تمام نوع داده های C
ارتباط با هر API زبان C و یا کد کتابخانه ای C ممکن است . این پشتیبانی تمام انواع C 99 را در بر می گیرد . D شامل توانایی صف بندی اعضای ساختمان برای مطمئن شدن از سازگاری با فرمتهای داده خارجی می باشد.
پردازش استثنای سیستم عامل
مکانیسم پردازش استثناهای D متصل به روشی است که سیستم عامل در سطح زیرین استثناها را در یک برنامه کاربردی پردازش می کند .
نسخه سازی
D . D تکنیک if# و نبود هشدار
کامپایلرهای D هشدارهایی برای کدهای نامطمئن تولید نمی کنند . کد یا توسط کامپایلر قابل قبول است یا نیست . این خصوصیت هر گونه بحثی در این زمینه که آیا هشدار خطایی صحیح است یا نه و نیز هر بحثی در این باره که با آن هشدار چه کنیم را از بین می برد . نیاز برای هشدار کامپایلر نشانهی طراحی ضعیف زبان است .
استهلاکDeprecation
به مرور زمان ،بعضی کدهای کهنه کتابخانه با نو تر و نسخه بهتر جایگزین می شود . نسخه قدیمی باید برای پشتیبانی کدهای به جا مانده از قبل موجود باشد اما می تواند لقب مستهلک بگیرد . کدهایی که نسخه های مستهلک را به کار می گیرند ، می توانند به انتخاب برنامه نویس توسط یک سویچ کامپایلر برچسب غیر قانونی بخورند که باعث آسان شدن کار برنامه نویسان برای نشان دادن هر وابستگی به خصوصیات مستهلک می شود .
نمونه برنامه D غربال اراتستن (تست اعداد اول):
import c.stdio ;
کنترل پروژه
bit [8191] flags ;
int main (){
int i , count , prime , k , iter ;
print f(“ 10 iterations
” );
for ( iter = 1 ; iter<=10 ; iter ++ ) {
count = 0 ;
flags [ ] = 1 ;
for ( i = 0 ; i < flags . length ; i ++ ){
if ( flags [i] ) {
prime = i + i +3;
k = i + prime;
while ( k < flags . Length ) {
flags , [ k] = 0 ;
k + = prime ;
}
count + = 1;
}
}
}
print f ( “ % d primes” , count ) ;
return 0 ;
}
جمع آوری زباله (Grabage Collection)
تخصیص حافظه در D کاملاً با جمعآوری زباله همراه است. تجربه شهودی بیان میکند که تعداد زیادی از خصوصیات ++C برای کنترل رهاسازی حافظه لازم است .با وجود جمعآوری زباله، زبان بسیار سادهتر میشود.
گروهی میگویند جمعآوری زباله برای جوجه برنامهنویس ها و تنبلها است. زمانی این حرف در مورد ++C گفته میشد. اما شاید هیچ چیز در ++C نیست که با C یا اسمبلر قابل انجام نباشد .
جمعآوری زباله ، کد خسته کننده پیگیری تخصیص حافظههای مستعد خطا که در C و ++C لازم است را حذف میکند. این نه تنها بدین معناست که گسترش برنامهها سریعتر انجام میگیرد و هزینههای نگهداری کاهش می یابد ، بلکه برنامه به میزان زیادی در دفعات اجرا سریع تر است.
با وجود اینکه D یک زبان دارای جمعآوری زباله است ، اعمال new و delete میتوانند طوری تعریف شوند که به عنوان یک تخصیص دهنده حافظه ی سفارشی به کار روند.
RAII یک تکنیک پیشرفته گسترش نرمافزار برای کنترل تخصیص منابع و آزادسازی آنها است ، D از RAII در یک روش کنترل شده قابل پیشبینی که مستقل از چرخه جمعآوری زباله است پشتیبانی میکند.
D ساختمانهای سبک ساده C را پشتیبانی میکند هم برای سازگاری با ساختمان دادههای C و نیز به خاطر اینکه آنها در جاهایی که قدرت کامل کلاسها کارایی ندارد مفیدند.
Inline Assembler
درایور سخت افزار ، کاربردهای سیستمی با کارایی بالا ، سیستم های تعبیه شده و کدهای خصوصی شده ، بعضی وقتها نیاز به غرق شدن در زبان اسمبلی دارند تا کار انجام شود . در حالی که پیاده سازی های D نیاز به کارگیری اسمبلر خطی ندارند ، این خصوصیت،در زبان تعریف شده و قسمتی از آن است . اغلب نیازهای کد اسمبلی به وسیله این بخش قابل برآوری است که نیاز به اسمبلرهای جداگانه و DLL ها را مرتفع می سازد .
همچنین بسیاری از پیاده سازی های D توابع اصلی را (شبیه به پشتیبانی ذاتی C از پردازش درگاههای ورودی خروجی ، دسترسی مستقیم به عملیاتهای ممیز شناور و …) پشتیبانی می کند .
قابلیت اعتماد
یک زبان پیشرفته باید برنامه نویس را در رفع تمامی اشکالات از کد یاری کند . این کمک به چندین صورت می تواند ارائه شود . از آسان سازی کاربرد تکنیکهای قدرتمند تر ، تا گوشزد کردن کد غلط به طور آشکارا توسط کمپایلر و کنترل زمان اجرا .
معاهدات ( Contracts )
طراحی به وسیله کنتراکت (اختراع B.Meyer ) یک تکنیک انقلابی برای کمک به مطمئن شدن از صحت برنامه است و نسخه DBC زبان D شامل پیش شرطهای توابع ، پس شرطهای توابع ، یکسانی های کلاس و کنتراکتهای ثابت کننده است .
آزمایش واحد
آزمایش قسمت ها می تواند به یک کلاس افزوده شود طوری که به صورت خودکار در آغاز اجرای برنامه ، اجرا شود . این در هشدار دادن اینکه پیاده سازی کلاس در هر بار ساخته شدن ،سهواً با شکست مواجه نشده است مفید است . آزمایش واحد قسمتی از کد کلاس را تشکیل می دهد. ایجاد آنها یک بخش طبیعی پروسه ی گسترش کلاس ها خواهد شد برخلاف پشت گوش انداختن کد تمام شده از دسترس گروه آزمایش.
آزمایش واحد در دیگر زبان ها قابل انجام است. اما تا خود زبان شامل این مفهوم نباشد، نتیجه جالب از آب در نمی آید . آزمایش واحد یک خصوصیت اصلی و بارز در D است . برای توابع کتابخانه ای به خوبی عمل می کند، هم ضمانت می کند که تابع حقیقتاً کار می کند و هم با مثال بیان می کند که تابع چگونه کار می کند . خیل کثیرمنابع کدهای کاربردی و کتابخانه های ++C موجود در اینترنت برای دانلود را در نظر بگیرید . چه تعداد از آنها با تستهای کلی همراه است ( تست واحد را هم در نظر نگیرید ) ؟ کمتر از یک درصد . روش معمول این است که اگر کامپایل شده است اجرا هم می شود و شگفت زده خواهیم شد اگر هشدارهای کامپایلر اشکالات واقعی باشند .
در کنار طراحی با کنتراکت ، آزمایش واحد ، D را به مراتب به بهترین زبان برای نوشتن قابل اعتماد و کاربردهای سیستمی قدرتمند تبدیل می کند.
اکنون اشکال زدایی بخشی از املای زبان است ( debug ) . که در زمان کامپایل قابل فعال یا غیر فعال شدن است بدون کاربرد دستورات پیش پردازنده یا ماکروها . املای debug یک ابزار تشخیص سازگار، استوار و قابل حمل و قابل فهم را فعال می کند که بفهمد آیا نیاز است که کد منبع قادر بر ایجاد هر دو کامپایل اشکال زدایی و کامپایل نهایی باشد ؟
مدل برتر try–catch-finally به جای مدل فقط try–catch به کار رفته است .دیگر هیچ نیازی نیست که اشیای زائد ایجاد کنیم فقط برای اینکه معناهای نهایی را توسط مخرب ( destructor ) پیاده سازی کنیم .
هماهنگی و هم روندی(Synchronization)
برنامه سازی چند رشته ای (Multi Thread Programming) متداول تر می شود و D مبناهایی برای ساخت برنامه های چند رشته ای فراهم می کند . هم روند سازی می تواند هم در سطح متد و هم در سطح شیئ انجام شود .
synchronize int func ( ) {.}
توابع هم روند (سنکرون) در هر زمان فقط به یک رشته (Thread) اجازه می دهند که آن تابع را اجرا کند . عبارت synchronize در اطراف قطعه ای از عبارات انحصار متقابل(mutex)ایجاد می کند و دسترسی به وسیله شیئ یا به صورت عمومی را کنترل می کند .
۱. آرایه های دینامیک به جای اشاره گر ها
۲. متغیرهای ارجاعی به جای اشاره گر ها
۳. اشیای ارجاعی به جای اشاره گرها
۴.جمع آوری زباله به جای کنترل دستی حافظه
۵. مبانی پیش ساخته موجود برای هم روندی رشته ها
۶. عدم وجود ماکرویی که به طور غیر عمدی به کد آسیب بزند .
۷. توابع inline به جای ماکروها
۸. کاهش وسیع نیاز به اشاره گرها
۹. سایز انواع مرکب واضح و مشخص است
۱۰. عدم شک در مورد علامت دار بودن کاراکتر ها
۱۱. عدم نیاز به دو بار اعلان در کد منبع و فایلهای header
۱۲. پشتیبانی واضح از تجزیه و تحلیل برای افزودن کد اشکال زدایی
۱. به طور واقع بینانه ، هیچکس قصد تبدیل میلیونها خط از C/++C به D ندارد و از آنجا که D کد منبع اصلاح نشده C/++C را کامپایل نمیکند ، برای این مورد مناسب نیست. (D به هرحال API های C را به خوبی پشتیبانی میکند).
۲. برنامه های خیلی کوچک : یک زبان اسکریپتی یا دارای مفسر مانند Perl , Dmdscript , Python احتمالاً مناسبتر است.
۳. به عنوان زبان برنامهنویسی برای شروع: برای مبتدیها Python یا java مناسبتر است . D برای برنامه نویسان متوسط تا پیشرفته یک زبان دوم عالی است .
۴. زبان به کاربرد کلمات صحیح وسواس دارد. D یک زبان عملی است و هر خصیصه از آن ترجیحاً قابل مقایسه و ارزیابی در همان حداست تا در حد ایدهآل . به طور مثال D ساختارها و مفاهیمی دارد که به طور مجازی نیاز به اشارهگرها را برای امور پیش پا افتاده ازبین میبرد. به طور مشابه تغییر نوعها هنوز وجود دارد برای آن جایی که سیستم نوع ، نیاز به نادیده گرفتن دارد.
خصوصیات اصلی D
این قسمت برخی خصوصیات جالبتر D(نسبت به C) را در دستههای مختلف طبقهبندی میکند.
کلاسها : طبیعت شییء گرای D از کلاسها آغاز میشود. مدل وراثت ، وراثت یگانه است که با روابط تقویت میشود. شییء کلاس در ریشهی درخت وراثت می نشیند. بنابراین تمام کلاسها یک مجموعه متداول تابعی را اجرا میکنند. کلاسها به وسیله ارجاع معرفی میشوند و چنان کد پیچیدهای برای آنکه پساز استثناها پاک شود نیاز نیست.
تعریف مجدد عملگرها: میتوان کلاس را برآن واداشت که با استفاده از عملگرهای موجود ، سیستم نوع را برای پشتیبانی نوعهای جدید گسترش دهد. مثلاً ایجاد کلاس اعداد بزرگ و سپس تعریف مجدد عملگرهای (/,*,_,+) برای توانایی استفاده از آن ها در املای عبارات جبری معمولی.
فراوری( Productivity)
پیمانهها : فایلهای منبع دارای ارتباطی یک به یک با پیمانهها هستند. به جای include# نمودن یک فایل از اعلان ها ، فقط پیمانه را import مینماییم. هیچ نگرانی در مورد importهای متعدد از همان پیمانه نیست همچنین نیازی به پوشاندن فایلهای header با ifndef# یا endif# یا pragma once# و از این قبیل نیست.
اعلان در برابر تعریف
++C معمولاً نیاز دارد که توابع و کلاسها دوبار اعلان شوند یک اعلان که در فایلهای header صورت میگیرد و تعریف که در فایل منبع با پسوند “C.” . این یک روند مستعد خطا و کسل کننده است . به طور واضح برنامهنویس فقط نیاز دارد که یک بار آن را بنویسد و سپس کامپایلر باید دادههای اعلان را بسط دهد و برای وارد کردن نمادین در دسترس قرار دهد. دقیقاً آن گونه که D میکند:
مثال:
class ABC
{
int func() { return 7; }
static int z = 7;
}
int q;
دیگر نیاز به تعریف جدای توابع عضو، اعضای استاتیک ، extern ها یا املاهایی مانند زیر نیست:
int ABC::func() { return 7; }
int ABC::z = 7;
extern int q;
تذکر : البته در ++C توابع جزیی مانند {;return 7} به صورت inline هم نوشته میشوند اما توابع پیچیده نه. علاوه برآن اگر یک ارجاع بعد از آن موجود باشد تابع نیاز به الگو دارد که از قبل موجود باشد مثال زیر در ++C کار نمی کند.
class Foo
{
int foo(Bar *c) { return c->bar; }
};
class Bar
{
public: int bar() { return 3; }
};
اما کد همارز در D کار می کند:
class Foo
{
int foo(Bar c) { return c.bar; }
}
class Bar
{
int bar() { return 3; }
}
اینکه یک تابع D به صورت inline است یا نه توسط تنظیمات بهینهساز قابل کنترل است .
قالبهای D روشی واضح برای پشتیبانی برنامهسازی عمومی همراه با قدرت اختصاصیسازی به صورت قسمت به قسمت ، پیشنهاد میکند.
آرایههای شرکتپذیر
آرایههای شرکتپذیر آرایههایی هستند با یک نوع داده قراردادی (اختیاری) به عنوان ایندکس به جای آنکه به یک ایندکس از نوع اعداد صحیح محدود باشند. در اصل آرایههای شرکتپذیر جدولهای در هم سازی(hash ) هستند. این آرایهها ساختن سریع ، کارا و خالی از اشکال جدولهای سمبل را آسان مینماید.
تعریف نوعهای C و ++C در حقیقت نام مستعار نوع هستند طوریکه هیچ نوع جدیدی به طور واقعی مطرح نمیشود. D ، تعریف نوعهای واقعی پیادهسازی میکند جایی که:
typedef int handle;
به طور واقعی یک نوع جدید به نام handle ایجاد میکند . بر کنترل نوع تأکید شده است و تعریف نوعها در تعریف مجدد توابع شریک میشوند. برای مثال :
int foo(int i);
int foo(handle h);
نوع bit
نوع داده پایه بیت است و D یک نوع داده با نام bit دارد . این امر بیش از همه در ساخت آرایههایی از بیتها مفید است:
bit [ ] foo;
D توقع پشتیبانی از توابع معمول از جمله توابع عمومی ، توابع مجدد تعریف شده ، توابع inline ، توابع عضو ، توابع مجازی ، اشارهگرها به توابع و … را داشته است علاوه برآن :
توابع میتوانند درون توابع دیگر قرار گیرند. این امر در ساخت کد ، خاصیت locality و تکنیکهای بستهبندی توابع بسیار مفید است.
لفظهای توابع Functionliterals
توابع بینام میتوانند به طور مستقیم در یک عبارت جای داده شوند.
توابع محصور شده و توابع عضو کلاس بوسیله وکالت (delegate) میتوانند ارجاع داده شوند که این باعث آسان تر شدن و type safe شدن برنامهسازی عمومی میشود.
این خصوصیسازی نه تنها کمک میکند که توابع خود مستندتر شوند بلکه بسیاری از موارد لزوم اشارهگرها را بدون قربانی کردن هیچ چیز حذف و امکاناتی را برای کمک بیشتربه کامپایلر در پیدا کردن اشکالات کد فراهم میکند.
بدین ترتیب برای D این امکان فراهم میشود که مستقیماً با یک بازه وسیعتری از APIهای بیگانه ارتباط برقرار کند. و هیچ نیازی برای کارهای جانبی مانند زبانهای تعریف ارتباطات وجود ندارد.
آرایههای C اشتباهات متعددی دارند که میتوانند تصحیح شوند:
۱. اطلاعات بعد با آرایه همراه نیست و بنابراین باید ذخیرهشده و جداگانه ارسال شود . مثال کلاسیک این مورد پارامترهای argc و argv هستند که به main فرستاده میشوند.
main (int argc , char*argv[])
۲. آرایهها اشیاء سطح اول نیستند. وقتی یک آرایه به عنوان پارامتر به یک تابع فرستاده میشود به یک اشارهگر برگردانده میشود . حتی با اینکه الگوی تابع به طور گیج کنندهای می گوید که این آرایه است. وقتی این برگرداندن انجام میشود تمام اطلاعات نوع آرایه گم میشود.
۳.آرایههای C قابل تغییر اندازه نیستند . این بدان معنی است که حتی چیزهای ساده ،انبوه و متراکم میگردد. مانند یک پشته که نیازدارد به عنوان یک کلاس پیچیده ساخته شود.
۴.مرز یک آرایه C قابل کنترل نیست چون اصلاً مرز آرایه مشخص نیست.
۵.آرایهها در C با علامت [ ] پس از شناسه اعلان میشوند . این به یک املای بیخود و گیج کننده در اعلان اشیایی مانند اشارهگر به یک آرایه میانجامد :
int (*array ) [3];
در D علامت [ ] در سمت چپ قرار میگیرد که فهم آن بسیار سادهتر است.
int [3] * array; // اعلان یک اشارهگر به یک آرایه سهتایی از اعداد صحیح
Long [ ] func (int x); //تابعی که آرایه ای از اعداد صحیح بلند را برمی گرداند
آرایههای D در چهار نوع میآیند : اشارهگرها ، آرایههای استاتیک ، آرایههای دینامیک و آرایههای شرکتپذیر ،قسمت آرایهها را ببنید !
پردازش رشتهها آن قدر متداول است (و آن قدر در C و ++C زمخت و بدترکیب) که نیازمند پشتیبانی مستقیم در زبان برنامه سازی است. زبانهای مدرن از جمله D ، الحاق رشتهها ، کپی کردن و … را در دست میگیرند . رشتهها رهاورد مستقیم پردازش بهینه شده آرایهها هستند.