-سوال: به نظر شما آیا برنامه نویسی مبتنی بر template و برنامه نویسی عام توسط بیشتر برنامه نویسان مد نظر قرار خواهد گرفت؟ یا اینکه این روش به STL محدود خواهد شد ـ مثل manipulator ها که به جز کتابخانه iostream در جای دیگری استفاده نشده اند.
-جواب: نمیدانم. قبل از اینکه ایده های پشت STL وارد جریان عمومی شود زمان زیادی طول خواهد کشید.اگه چیزی ازش بیرون بیاید تقریبا ۱۰ تا ۱۵ سال طول می کشد.
-سوال: چیزی که من را همیشه متعجب کرده این است که چه طور STL به این سرعت توسط کمیته استانداردسازی ++C پذیرفته شد. یعنی این کمیته ها بسیار محتاط و محافظه کار هستند. توضیح شما چیست؟
-جواب: حمایت Bjae Stroustrup حیاتی بود. Bjae واقعا می خواست STL در استاندارد باشد و اگر Bjae چیزی را بخواهد، آن را به دست خواهد آورد. او خیلی یکدنده است. حتی مرا مجبور کرد در STL تغییراتی بدهم که به جز او برای کس دیگری انجام نمی دادم ـ البته من هم یکدنده هستم اما او با اراده ترین شخصی است که می شناسم. او چیزها را ممکن می کند. من مدتی را صرف فهماندن اینکه STL درمورد چیست به او کردم، اما وقتی که آن را گرفت برای جا انداختن آن آماده شد. او همچنین در STL سهم داشت از این جهت که با این عقیده که برای برنامه نویسی چندین روش معتبر وجود دارد حدود یک دهه علیه هجمه های بی پایان و تبلیغات دروغین ایستادگی کرد و ترکیبی از انعطاف، کارایی، سربارگذاری و ایمنی نوع (type safety) را در template قرار داد که موجب شد STL امکان پذیر شود. تمایل دارم که به روشنی اعلام کنم که Bjae طراح زبان شاخص نسل من است.
-سوال: STL پر از استفاده خلاقانه از template است مثل نوع های سمبلیک که از کلاسها صادر می شود یا تطبیق الگوی الگوریتمهای سربارگذاری شده با برچسب تکرارگرها. در واقع هیچ کتاب استاندارد برنامه نویسی ++C درباره این اصطلاحات صحبت نکرده. چه طور شد که شما به این اصطلاحات در کدهای ++C رسیدید؟
-جواب: من دقیقا می دانستم به چه چیزی می خواهم برسم. پس با زبان آنقدر ور رفتم تا به چیزی که بخواهم برسم. اما چندین سال طول کشید تا تمام تکنیک ها را کشف کنم. و من بسیاری شروع های اشتباه هم داشته ام. مثلا من سالها صرف کردم که برای وراثت و [چیزهای] مجازی، کاربردهایی پیدا کنم که بعد فهمیدم این سازوکارها اساسا ناقص هستند و نباید استفاده شوند. بسیار خوشحالم که کسی نمی تواند مراحل میانه راه را مشاهده کند ـ چون بسیاری از آنها خیلی احمقانه بود. سالها طول کشید که همه چیز نسبتا مناسب شود. همچنین اینکه Bjae می خواست بعضی خواص را به زبان اضافه کند تا بعضی اصطلاحات من امکان پذیر شود هم کمک کننده بود. او یکبار به این کار گفت «طراحی زبان فی البداهه».
-سوال: به نظر شما بهترین روش آموزش برنامه نویسی عام و STL به برنامه نویسان ++C چیست؟ به نظر شما تکنیک های برنامه نویسی شیء گرا باید قبل، بعد یا همزمان با STL آموخته شود؟
-جواب: من در نظر دارم یک درس برنامه نویسی عام در SGI ارائه کنم. امیدوارم که این موجب ایجاد یک کتاب شود. البته معلوم شده که من یک نویسنده تنبل هستم. من هرگز مقاله ای را به پایان نمی رسانم مگر همکاری داشته باشم که انجامش دهد.
-سوال: من در Lycos جستجو کردم تا مقالات شما را بیابم که فقط دو عنوان پیدا شد: دستورالعمل STL و رزومه ای از شما جهت ارائه STL به کمیته استانداردسازی.
-جواب: درسته من تنبلم البته نه به این حد. من تقریبا 20 مقاله و یک کتاب منتشر کرده ام. بسیاری از آنها در سایت های مختلف STL قرار دارند. (احتمالا در سایت Dave Musser تعدادی قرار داشته باشد).
-سوال: کدام کتاب؟
-جواب: کتاب زیر
"The Ada Generic Library: Linear List Processing Packages", by David R. Musser and Alexander A. Stepanov, Compass Series, Springer-Verlag, 1989
که البته خیلی خواندنی نیست.
-سوال: STL محدودیت کامپایلرهای ++C را نشان می دهد. کامپایلرهای کنونی ++C هم هنوز قادر نیستند بعضی کدهای STL را کامپایل کنند. شما چه طور توانستید STL را توسعه بدهید و تست کنید؟
من بر سر کامپایل STL مقدار زیادی از موهایم سفید شد. حقیقت تاسف بار این است که بسیاری از پیاده سازی های کنونی STL بهینه نیست چون هنگام توسعه STL مجبور بودم از کامپایلرهایی استفاده کنم که محدودیت و باگ داشت. خوشبختانه Bjae به من کمک کرد که در مورد خاصیتهای پیاده سازی نشده تصوری از نحوه کارشان داشته باشم. وقتی شما بتوانید از طراح زبان بپرسید این خاصیت زبان دقیقا چه کاری انجام می دهد بسیار کمک کننده است.
-سوال: تخصیص دهنده ها (allocator) چگونه به STL اضافه شدند. چه اندیشه ای در مورد آن داشتید؟
-جواب: من تخصیص دهنده را در مواجهه با معماری اینتل ابداع کردم. از نظر تئوری، ایده بدی نیست یعنی لایه ای که تمام چیزهای حافظه را داخل خود کپسوله کند: اشاره گرها، ارجاع ها، ptrdiff_t و size_t. اما در عمل کارایی ندارند. در مثال زیر:
vector<int, alloc1> a(...);
vector<int, alloc2> b(...);
نمی شود به این صورت نوشت:
find(a.begin(), a.end(), b[1]);
چون [b[1 یک alloc2::reference را برمی گرداند نه &int . که عدم تطابق نوع می تواند رخ دهد. لازم است روشی که هسته زبان با ارجاع ها دارد تغییر کند تا تخصیص دهنده ها مفید واقع شوند.
-سوال: آیا این می تواند یک ایراد جدی برای template های ++C باشد؟ می شه یک کلاس را با یک آرگومان template تعریف کرد اما تخصصی کردن های مختلف از نظر نوع، سازگار نیستند. در عوض زیرکلاسهای مختلف (از نظر شیء گرایی) از یک کلاس با کلاس ریشه از نظر نوع، سازگار هستند.
-جواب: فکر کنم مساله عمیقتر از این باشد. *T در این زبان حک شده. به طور کلی معتقدم که لازم است زبان برنامه نویسی از پایه طراحی شود که بشود با آن به شکلی استوار برنامه نویسی عام انجام داد. انتظار می کشم کسی مرا برای فقط انجام این کار استخدام کند.
-سوال: من در سایت D.Musser دو پیاده سازی از hash table پیدا کردم که هر دو کار می کردند و کاملا هوشمند بودند ـ خیلی هوشمندتر از hash table هایی که در کتابخانه ها یافت می شوند. چرا hash table در STL قرار داده نشد؟
-جواب: سیاست. باید در STL باشند. پیاده سازی جدید STL که انجام دادیم اینها را در بر گرفته. در کل لازم است ما سازوکاری جهت اضافه کردن چیزهای مختلف به STL ایجاد کنیم. در عین حال، STL یک چارچوب قابل توسعه است یعنی قابلیت توسعه آن زیاد است. ساختمان های داده زیادی هستند که در STL نیستند مثل لیست پیوندی یک طرفه، ماتریسها و گراف. SGI می خواهد توسعه STL را رهبری کند.
-سوال: آیا شما هنوز دارید روی STL کار می کنید؟ چه کاری انجام می دهید؟
گروه من در SGI شامل Matt Auste و Hans Boehm و من یک نسخه جدید از STL را به اتمام رسانده. که شامل محتوی های (container) هش، تخصیص حافظه ایمن از نخ (thread safe)و مستندات شکیل تحت وب است. SGI آن را به طور عمومی عرضه کرده است
http://www.sgi.com/Technology/STL . ما امیدواریم که STL را در حال رشد نگه داریم. ساختمانهای داده چندبعدی، مانایی و چندنخی در بین چیزهایی است که برنامه داریم آنها را اضافه کنیم. البته معلوم نیست چه قدر طول می کشد که اینها را انجام بدهیم. مدیران من از فعالیتهای مربوط به برنامه نویسی عام و STL حمایت نمی کنند. سخت است که به آنها توضیح بدهم که چرا SGI باید جهت توسعه کتابخانه هزینه بدهد. (همچنین توضیح دادن این مساله به مدیریت HP هم سخت بود. آنها ۵ ماه بعد از پذیرفته شدن STL در استاندارد، پروژه من را لغو کردند).
-سوال: به نظر می رسد STL هنوز کاستی هایی دارد.مورد اول HP STL هنوز ازنظر نخ ها ایمن نیست. مورد بعد، template ها موجب شده اند مقدار زیادی کد در فایلهای سرآیند قرار بگیرند. ما نمی توانیم کتابخانه های واقعی از template ها یا کتابخانه های مشترک (shared library) یا dll ی از template های نمونه سازی نشده داشته باشیم: به عبارت دیگر STL بیشتر یک کتابخانه زمان کامپایل است. آخرین کاستی هم این است که تقریبا هیچ ابزار CASE یا روش OOD از برنامه نویسی عام پشتیبانی نمی کند. مثلا هیچ کدام از ابزارهای CASE اجازه تعریف تابعهای عام را نمی دهند. همچنین با روش Booch می توان template را نشان داد اما دیاگرامهای ایجاد شده (حداقل برای من) حس ایجاد نمی کنند.
-جواب: SGI STL از نظر نخ ها ایمن است. مساله دوم را می توان با کامپایل جداگانه (در صورتی که توسط استاندارد پذیرفته شود) حل کرد. ایده کامپایل جداگانه توسط John Wilkinson و Jim Dehnert و Matt Auste که در شرکت SGI هستند طراحی شده. البته این پیشنهاد در استاندارد رای آورد اما تا کامپایلرها قادر شوند کامپایل جداگانه انجام دهند مدتی طول می کشد. بر این باورم که کامپایل جداگانه نهایتا مستلزم این است که کتابخانه های مشترک از template ها هم با کد جابجا شوند. طراحی ابزارهایی جهت کار با برنامه نویسی عام، سخت نیست. و کاملا مطمئنم اگر بازاری برای آن وجود داشته باشد، Grady Booch هم روش خودش را تغییر می دهد که بتوان با برنامه نویسی عام کار کرد.
-سوال: یک چیز زجرآور برای برنامه نویس ++C این است که کمیته های استاندارد شناختی از همدیگر ندارند. OMG استانداردی برای برنامه نویسی توزیع شده (CORBA) تعریف کرده اما پیاده سازی CORBA در ++C بدون توجه به STL صورت گرفته. آنها کلاسهای مختص خودشان را تعریف کرده اند مثل <Sequence<T و CORBA::String. همین مساله در مورد ODMG و استاندارد ODMG-93 برای پایگاه داده شیء گرا رخ داده است. چرا این طور شده است؟ آیا قرار است چیزی تغییر کند؟
-جواب: من آنقدر پیر شده ام که نمی توانم تمام استانداردهای شبکه که در دهه ۷۰ آمدند را به خاطر بیاورم. الان چه کسی آنها را به خاطر می آورد؟
-سوال: برنامه نویسی عام در یک محیط توزیع شده به چه صورت خواهد بود؟ برنامه نویسی عام بر این ایده مبتنی است که کامپایلر در زمان کامپایل، تمام نوع ها را می شناسد. که این در محیط توزیع شده صدق نمی کند. راه حل آن آیا یکپارچه شدن نوعی ORB با کامپایار هست؟ یا برنامه نویسی عام به طور ساده برای برنامه نویسی توزیع شده مناسب نیست ـ به عبارتی در این مورد از Java باید استفاده کرد؟
-جواب: برنامه نویسیس عام کاری به زمان کامپایل یا زمان اجرا ندارد. مشکلی که من در OOP دیدم این است که نه تنها کند است بلکه امکان بیان ساده ترین الگوریتم ممکن در آن وجود ندارد. ببینید طرح max به این صورت است:
max: T x T -> T
این طرح را نمی توان در Java بیان کرد چونکه ارث بردن از کلاس یا اینترفیس T باعث می شود طرح max به صورت زیر در بیاید:
max: T' x T -> T
که لازم است بین دو طرح، تبدیل هم وردا (covariant transformation) صورت بگیرد. و همچنین [در مورد برنامه نویسی توزیع شده] باید بتوان یک نوع را از نوع دیگر استخراج کرد. یعنی مفهوم نوع مجازی که یک جدول-م (v-table) باشد که در آن خصوصیات نوع وجود داشته باشد.
-سوال: تکرارگر (iterator) چیست؟
تکرارگرها از ادغام دو نظریه به وجود آمده اند. اولین نظریه، نظریه نام است (handle, cookie, address). نام، چیزی است که به چیز دیگر اشاره می کند (*operator). که ما به این، نظریه ی تکرارگر بدیهی می گوییم. علاوه بر اینکه می توان به جایی که به آن اشاره شده دست یافت ، برای یک نام، تساوی منطبق با اصل زیر تعریف می شود:
i == j iff &*i == &*j
یعنی دو تکرارگر مساوی هستند اگر و تنها اگر آنها به یک شیء اشاره کنند. ( البته، تساوی، باید با تمام اصول موضوعه استاندارد منطبق باشد). نظریه دوم نظریه عملیات خَلَف (successor operation) یا (i++) می باشد که با اصلاح آن داریم : خَلَف - سَلَف (++ و --) و جمع ( ++ و -- و + و -) منطبق با اصول موضوعه استاندارد. و در واقع اشاره گر، مدلی از تکرارگر با دسترسی تصادفی (random access iterator) می باشد.
-سوال: بعضی بحث می کنند که اشاره گر، روشی برای جا انداختن هر چیز عجیب و غریب و ناگوار داخل حافظه است. Java و Delphi با ممنوع کردن اشاره گر کار درستی انجام دادند.
-جواب: اگر اشاره گر از این جهت ممنوع شود که از محاسبه با اشاره گر ها جلوگیری شود کار خوبی است. محاسبه با اشاره گر فقط باید در جایی که در C و ++C اجازه داده شده مورد استفاده قرار گیرد یعنی برای استفاده از اشاره گر به عنوان آرایه. اما ممنوع کردن اشاره گر به طور کلی حماقت است. اگر در یک زبان، اشاره گر یا ارجاع نباشد به عنوان یک مثال ساده نمی توانیم یک تابع swap عام ایجاد کنیم.
-سوال: واژه رسته (category) در بین جامعه ++C کاربردهای مختلفی دارد. بر چه اساس شما از اصطلاح رسته های تکرارگرها استفاده می کنید؟
-جواب: به معمولا برای این جور چیز ها از واژه مفهوم (concept) استفاده می کنم.
-سوال: من قبلا سعی کرده ام یک لیست پیوندی یک طرفه به سبک STL درست کنم. اما تصمیم گرفتم تابع عضو ()size را پیاده سازی نکنم. چون با این کار مجبور بودم یک متغیر اضافی داخل لیست پیوندی داشته باشم [که باعث مصرف حافظه می شد] که سایز لیست را در خودش ذخیره کند تا من با پیچیدگی زمانی ثابت بتوانم سایز لیست را به دست بیاورم. که این را بر اساس سی دی ++C انجام دادم. تصمیم درست چیست؟
-جواب: در لیستهای STL تابع ()size پیچیدگی زمانی خطی دارد. و تصمیم درستی هم بوده چون اگر کاربری هم بخواهد تعداد عناصر لیست را ذخیره داشته باشد کار ساده ای است، اما معمولا ما نیازی به آن نداریم در نتیجه با زمان خطی آن را به دست می آوریم(چون به ندرت استفاده می شود می توانیم به نوعی بگوییم زمان ثابت دارد). اما کمیته استاندارد اصرار کرد من آن را به زمان ثابت تغییر بدهم. من اختیاری نداشتم. نهایتا مجبور خواهیم شد این ملزومات را تغییر دهیم.
-سوال: من بررسی می کردم که چه طور می توانم یک درخت را به سبک STL ایجاد کنم که به چند مشکل برخوردم: هر گره یک پدر و دو فرزند دارد. حرکت به سمت پدر را با عملگر -- می شود نشان داد، اما برای حرکت به سمت فرزندان به دو عملگر ++ نیاز داشتم. تکرارگرها را چه طور می توانیم برای ساختمان های غیر خطی مثل درخت و گراف مورد استفاده قرار دهیم؟
-جواب: حتی روی یک ساختمان متوالی ما تکرارگرهای مختلفی می توانیم داشته باشیم. به عنوان مثال می توانم از تکرارگر معکوس (Reverse) نام ببرم. تکرارگرهای جهنده (Stride) هم خیلی مهم هستند و نهایتا داخل STL قرار خواهند گرفت.
-سوال: اعتراف می کنم که چیزی نمی دانم. تکرارگر جهنده چیست؟
-جواب: از i به سمت i+5 و سپس i+10 رفتن.
-سوال: چه تفاوتی با تکرارگر تصادفی دارد؟
-جواب: تکرارگر جهنده یک اداپتور تکرارگر است که محدوده (ابتدا و انتها) یک تکرارگر با دسترسی تصادفی را می گیرد و یک تکرارگر با دسترسی تصادفی را اراپه می کند که با اعمال ++ روی آن یک جهش انجام می شود ( توالی تکرارگر که n قدم بعد قرار دارد).
-سوال: این از چه نظر با مساله پیمایش درخت مرتبط می شود؟
-جواب: منظورم این نیست که تکرارگر جهنده یا تکرارگر معکوس ارتباطی با پیمایش درخت دارند بلکه منظورم این است که می توان برای هر ساختمان داده بر اساس جهت پیمایش، انواع مختلف تکرارگر داشت. مثلا در مورد درخت می توان پیمایش رو به عقب یا رو به جلو داشت.
-سوال: معمولا به این مشکل بر می خورم: آیا من این تابع را باید به صورت تابع عضو تعریف کنم یا یک تابع عام (سراسری)؟ در STL چه دیدگاهی پشت این تصمیم بوده؟
-جواب: تا جای ممکن تابع سراسری داشته باشید. اگر دو تابع begin و end سراسری بودند خیلی جالب تر می بود که باعث می شد آن را برای آرایه های C تعریف کنیم. خیلی جالب تر می بود اگر *operator سراسری می بود با تعریف پیش فرض زیر:
template <class T>
T& operator*(T& x) { retu x;}template <class T>
const T& operator*(const T& x) { retu x;}
که به ما این امکان را می داد که به شکل زیر عمل کنیم:
copy(0, 25, ostream_iterator<int>("n"));
در کل برای اشیایی که تکرارگر نباشند، *operator باید خود شیء را برگرداند. معنای یک چیز که نام [یا اشاره گر] نباشد عبارت است از خود همان چیز. حتی من عاشق این هستم که سازنده ها و مخرب را به شکل سراسری بنویسم. اگر زبان این اجازه را می داد می شد کارهای عجیبی انجام داد.
-سوال: اگر به شکلی که شما گفتید یک *operator عام ایجاد کنم و در برنامه ام تعریف زیر را داشته باشم:
template <class T> class SmartPtr {
T* ptr;
public:
SmartPtr(T* _ptr = 0) : ptr(_ptr){}
T* operator*() const {retu ptr;}
// ...
};
با این حساب در کد زیر ابهام ایجاد نمی شود؟
int i=0;
SmartPtr<int> sp(&i);
int j= *i; // apply SmartPtr<int>::operator* or
// operator<SmartPtr<int>? both are user defined
-جواب: خیر ابهامی به وجود نمی آید. در مقابل تعریف سراسری، تعریف شما توسط کامپایلر انتخاب می شود. که این به علت تخصصی کردن جزئی (partial specialization) رخ می دهد.
-سوال: کنجکاو شدم که چرا در STL یک اداپتور «محتوی مرتب شده» sorted container وجود ندارد؟
-جواب: set یک محتوی مرتب شده است.
-سوال: set اداپتور نیست. جدای از محتوی هایی که از تکرارگر با دسترسی تصادفی پشتیبانی می کنند ، چرا می شود که ساختمان heap باشد اما محتوی مرتب شده نباشد؟
-جواب: در نظر داشته باشید که به علت اندازه STL مشکل یود که همه اینها را در آن بگذاریم. من مجبور شدم تعداد زیادی کامپوننت مفید را دور بریزم. (مثلا ببینید که بر سر hash table چه آمد).
-سوال: چرامستنداتی برا تابع adjust_heapــ در سرایند <heap.h> وجود ندارد. این تابع جهت استفاده از heap در الگوریتم Dijkstra لازم است.
-جواب: من دشواری های زیادی برای قرار دادن تابع های heap در استاندارد داشتم. در اصل می خواستم تمام تابعهای کمکی در STL کاملا در رویت باشد. اما سیاست اجازه نداد.
-سوال: پذیرش این که سیاستی در مورد تابعهای heap صورت گرفته برای من کمی سخت است.
-جواب: این در مورد یک تابع خاص نیست بلکه در مورد تعدادی از آنها است. شخص Bjae مسوول این است که تعداد کامپوننت های STL را به نصف آن کاهش داده است. سعی او بر این بود که برای کم کردن انتقاد ها، حجم STL را تا جای ممکن کوچک کند.
-سوال: آیا تا به حال در ایتالیا برای کار یا تفریح آمده اید؟
-جواب: بله من ۱۰ روز در پیتزا بودم و از فلورانس و لوکا بازدید کردم. رویای من رفتن به آسیزی است. من قلبا فرانسیسکن هستم. من در پرده دوم اپرای توسکا و پرده سوم اپرای لاتراویاتا گریه کردم. من دانته (به زبان ایتالیایی!) را در بسترم مطالعه می کنم. من عاشق پاستا، پروسیوتو و کیانتی هستم. با اینکه من یک سنت گرا هستم، بیشتر شبیه پاپ ژان بیست و سوم هستم تا پاپ پیوس دوزادهم.
-سوال: اگر شما دانته نسخه اصلی را می توانید بخوانید باید خیلی خوب ایتالیایی بلد باشید. چون تعداد کمی ایتالیایی ها این توانایی را دارند!
-جواب: ایتالیایی من خیلی ضعیف است. من دانته ایتالیایی را به این صورت می خوانم که ترجمه آن در جلو من است. یک قطعه از متن را با صدای بلند به زبان ایتالیایی می خوانم سپس به ترجمه اش نگاه می کنم.
-سوال: الکس از شما خیلی ممنونم. امیدوارم به ایتالیا بیایید و آسیزی را ببینید و در شهر قدیمی آسیزی ـ شاید جذاب ترین شهر قرون وسطی ایتالیا ـ دانته را بخوانید.
برچسب:
نویسنده: محمد رضا جوادیان
تاريخ: چهارشنبه
5 خرداد
1395 ساعت: 14:33