PDA

View Full Version : اسکریپت نویسی: برنامه نویسی سطح بالاتر برای قرن 21



eshpilen
چهارشنبه 03 فروردین 1390, 23:21 عصر
اسکریپت نویسی: برنامه نویسی سطح بالاتر برای قرن 21
مقاله ای از John K. Ousterhout
آزمایشگاههای Sun Microsystems
مارچ 1998

افزایش ها در سرعت رایانه و تغییرات در ترکیب اپلیکیشن درحال مهمتر کردن بیشتر و بیشتر زبانهای اسکریپتی برای اپلیکیشن های آینده هستند. زبانهای اسکریپتی از این جهت از زبانهای سیستمی تفاوت دارند که آنها برای اتصال اپلیکیشن ها به همدیگر طراحی شده اند. آنها برای دستیابی به یک سطح بالاتر از برنامه نویسی و توسعهء سریعتر اپلیکیشن از یک مشی بدون نوع (typeless) استفاده میکنند.

در طول 15 سال گذشته یک تغییر بنیادین در روشی که مردم برنامه های رایانه را مینویسند درحال رخ دادن بوده است. آن تغییر یک گذار از زبانهای سیستمی همچون سی و سی++ به زبانهای اسکریپتی همچون پرل یا Tcl است. هرچند مردم زیادی در حال مشارکت در این تغییر هستند، عدهء کمی میدانند که تغییری در حال رخ دادن است و عدهء حتی کمتری میدانند که چرا آن درحال اتفاق افتادن است. این مقاله توضیح خواهد داد که چرا زبانهای اسکریپتی بسیاری از کارهای برنامه نویسی را در قرن آینده بهتر از زبانهای سیستمی اداره خواهند کرد.
زبانهای اسکریپتی برای کارهای متفاوتی نسبت به زبانهای سیستمی طراحی شده اند و این منجر به تفاوت های بنیادین در زبانها میشود. زبانهای سیستمی برای ساختن ساختمان های داده ای و الگوریتم ها از صفر که از بدوی ترین اجزای رایانه همچون کلمه های حافظه شروع میشوند طراحی شده بودند. در مقابل، زبانهای اسکریپتی برای اتصال طراحی شده اند: آنها فرض میکنند که مجموعه ای از کامپوننت های قوی وجود دارند و عمدتا برای اتصال کامپوننت ها طراحی شده اند. زبانهای سیستمی از نوع نوعگذاری قوی (strongly typed) هستند تا به مدیریت پیچیدگی کمک کنند، درحالیکه زبانهای اسکریپتی بدون نوع هستند تا اتصالات میان کامپوننت ها را ساده کرده و توسعهء سریع اپلیکیشن را فراهم سازند.
زبانهای اسکریپتی و سیستمی مکمل هستند، و بیشتر پلتفرم های رایانه ای از سال 1960 هر دو نوع زبانها را شامل شده اند. این زبانهای معمولا همراه با همدیگر در فریمورک های کامپوننت بکار میروند که کامپوننت ها با زبانهای سیستمی ایجاد شده و بوسیلهء زبانهای اسکریپتی متصل میشوند. هرچند، چند رویهء اخیر، همچون ماشین های سریعتر، زبانهای اسکریپتی بهتر، و اهمیت فزایندهء رابطهای کاربر گرافیکی و معماری های کامپوننتی و رشد اینترنت، کاربرد زبانهای اسکریپتی را به میزان زیادی افزایش داده اند. این رویه ها در طول دههء آینده ادامه پیدا خواهند کرد و اپلیکیشن های بیشتر و بیشتری بطور کامل با زبانهای اسکریپتی نوشته خواهند شد و زبانهای سیستمی عمدتا برای ایجاد کامپوننت ها بکار خواهند رفت.

-- زبانهای سیستمی

برای درک تفاوتها میان زبانهای اسکریپتی و سیستمی، مهم است بدانیم چطور زبانهای سیستمی بوجود آمدند. زبانهای سیستمی بعنوان جایگزینی برای زبان اسمبلی ایجاد شدند. در زبان اسمبلی، عملا هر جنبهء ماشین در برنامه منعکس شده است. هر عبارت برنامه نویسی نمایندهء یک دستورالعمل ماشین است و برنامه نویسان باید با جزییات سطح پایینی همچون اختصاص رجیستر و فرایند فراخوانی پراسیجرها کار کنند. بعنوان یک نتیجه، نوشتن و نگهداری برنامه های بزرگ در زبانهای اسمبلی دشوار است.
در اواخر 1950، زبانهای سطح بالاتر همچون Lisp، فرترن، و Algol شروع به پدیدار شدن کردند. در این زبانها، عبارت ها دیگر دقیقا معادل دستورالعمل های ماشین نبودند؛ یک کامپایلر هر عبارت را در کد منبع به یک توالی از دستورالعمل های باینری تبدیل میکند. در طول زمان یک سری از زبانهای سیستمی از Algol بوجود آمدند که شامل PL/1، پاسکال، سی، سی++ و جاوا است. زبانهای سیستمی پرفورمنس کمتری نسبت به زبانهای اسمبلی دارند اما اجازه میدهند تا اپلیکیشن ها بسیار سریعتر توسعه بیابند. بعنوان یک نتیجه، زبانهای برنامه نویسی سیستمی تقریبا بصورت کامل جایگزین زبانهای اسمبلی برای توسعهء اپلیکیشن های بزرگ شدند.

-- زبانهای سطح بالاتر

زبانهای سیستمی به دو شکل با زبان اسمبلی تفاوت دارند: آنها سطح بالاتر هستنند و آنها نوع قوی (strongly typed) هستند. اصطلاح «سطح بالاتر» به معنای آنست که جزییات زیادی بصورت خودکار انجام میشوند، بنابراین برنامه نویسان میتوانند کد کمتری را برای انجام کار یکسانی بنویسند. بطور مثال:

- اختصاص رجیستر بوسیلهء کامپایلر انجام شده و بنابراین برنامه نویس نیازی به نوشتن کد برای انتقال اطلاعات بین رجیسترها و حافظه ندارد.
- روند فراخوانی رویه ها (Procedure calling sequences) بصورت خودکار تولید میشوند؛ برنامه نویسان نیازی ندارند دربارهء انتقال آرگومانها به و از پشتهء فراخوانی نگران باشند.
- برنامه نویسان میتوانند کلمات کلیدی ساده ای همچون while و if را برای ساختارهای کنترلی استفاده کنند؛ کامپایلر تمام جزییات دستورالعمل ها را برای پیاده سازی ساختارهای کنترلی تولید میکند.

بطور میانگین، هر خط از کد در یک زبان سیستمی به حدود پنج دستورالعمل ماشین ترجمه میشود، در مقایسه با یک دستورالعمل بر هر خط در یک برنامهء اسمبلی (م: حذف بخشی از متن). برنامه نویسان میتوانند تقریبا تعداد یکسانی خط کد را در هر سال صرفنظر از زبان بنویسند، بنابراین زبانهای سیستمی اجازه میدهند تا اپلیکیشن ها بسیار سریعتر از زبانهای اسمبلی توسعه داده شوند.

-- نوعگذاری (Typing)

تفاوت دوم میان زبان اسمبلی و زبانهای سیستمی نوعگذاری است. من اصطلاح نوعگذاری را برای رجوع به حدی که اطلاعات پیش از استفاده اش مشخص میشود استفاده میکنم. در یک زبان نوع قوی، برنامه نویس اعلان میکند که هر قطعه از اطلاعات چگونه استفاده خواهد شد، و زبان از استفاده از اطلاعات به هر شکل دیگری جلوگیری میکند. در یک زبان نوع ضعیف (weakly typed)، محدودیتهای از پیش تعیین شده برای روی چگونگی استفاده از اطلاعات وجود ندارند؛ معنای اطلاعات صرفا بوسیلهء روشی که آنها استفاده میشوند تعیین میشود، نه بوسیلهء هر قول و قرارداد قبلی.
رایانه های مدرن اساسا بدون نوع هستند. هر کلمهء حافظه میتواند هر نوعی از مقدار را نگهداری کند، همچون یک عدد صحیح، یک عدد اعشاری، یک اشاره گر، یا یک دستورالعمل. معنای یک مقدار بوسیلهء روش استفادهء آن تعیین میشود. اگر شمارندهء برنامه (program counter) به یک کلمه از حافظه اشاره کند با آن بصورت یک دستورالعمل رفتار میشود؛ اگر یک کلمه بوسیلهء یک دستورالعمل جمع صحیح مورد ارجاع قرار گیرد، با آن بصورت یک عدد صحیح رفتار میشود؛ و غیره. کلمهء یکسانی میتواند به شکلهای مختلف در زمانهای مختلف استفاده شود.
در مقابل، زبانهای سیستمی امروزی نوع قوی هستند. بطور مثال:
- هر متغییر در یک زبان سیستمی باید با یک نوع خاص همچون متغییر یا اشاره گر به رشته اعلان شود، و بایست به شکلهایی استفاده شود که برای آن نوع مناسب هستند.
- داده و کد جدا شده اند؛ ایجاد کد بصورت on the fly، اگر غیرممکن نباشد، دشوار است.
- متغییرها میتوانند در داخل ساختارها یا اشیایی با زیر ساختارهای بخوبی تعریف شده و رویه ها یا متدهایی برای دستکاری آنها جمع شوند. یک شیء از یک نوع نمیتواند جاییکه یک شیء از نوع دیگری مورد انتظار است استفاده شود.

نوعگذاری چند مزیت دارد. نخست، برنامه های بزرگ را بوسیلهء روشن کردن اینکه چطور چیزها استفاده میشوند و تمیز دادن میان چیزهایی که باید با آنها بصورت متفاوتی رفتار شود بیشتر قابل مدیریت میسازد. دوم، کامپایلرها اطلاعات نوع را برای آشکارسازی بعضی انواع مشخص از خطاها، همچون تلاشی برای استفاده از یک عدد اعشاری بعنوان یک اشاره گر استفاده میکنند. سوم، نوعگذاری پرفورمنس را بوسیلهء اجازه دادن به کامپایلرها برای تولید کد اختصاصی بهبود میدهد. برای مثال، اگر یک کامپایلر بداند که یک متغییر همیشه یک مقدار عدد صحیح را نگهداری میکند، سپس آن میتواند دستورالعمل های عدد صحیح را برای دستکاری آن متغییر تولید کند؛ اگر کامپایلر نداند که نوع یک متغییر چیست، آن باید دستورالعمل های اضافه ای را برای چک کردن نوع متغییر در زمان اجرا تولید کند. شکل 1 یک مجموعهء متنوع از زبانها را بر اساس سطح برنامه نویسی و قدرت نوعگذاری مقایسه میکند.

-- زبانهای اسکریپتی

زبانهای اسکریپتی همچون پرل، پایتون، Rexx، Tcl، ویژوال بیسیک، و شل های یونیکس یک استایل برنامه نویسی کاملا متفاوت نسبت به زبانهای سیستمی را ارائه میدهند. زبانهای اسکریپتی فرض میکنند که مجموعه ای از کامپوننت های سودمند از پیش در زبانهای دیگر وجود دارند. آنها برای نوشتن اپلیکیشن ها از صفر درنظر گرفته نشده اند بلکه بیشتر برای ترکیب کردن کامپوننت ها درنظر گرفته شده اند. برای مثال Tcl و ویژوال بیسیک میتوانند برای چیدن مجموعه هایی از کنترل های رابط کاربری بر روی صفحه استفاده شوند، و اسکریپت های شل یونیکس برای سوار کردن برنامه های فیلتر کننده در خط لوله ها (pipeline - م: اصطلاحی در روش اتصال ورودی و خروجی برنامه ها در خط فرمان) استفاده میشوند. زبانهای اسکریپتی اغلب برای گسترش ویژگیهای کامپوننت ها استفاده میشوند؛ هرچند، آنها به ندرت برای الگوریتم های پیچیده و ساختارهای داده ای که معمولا توسط کامپوننت ها فراهم میشوند مورد استفاده قرار میگیرند. به زبانهای اسکریپتی بعضی اوقات تحت عنوان زبانهای متصل کننده/چسباننده (glue languages) یا زبانهای یکپارچه سازی سیستم (system integration languages) ارجاع میشود.

-- زبانهای اسکریپتی عموما بدون نوع هستند

برای ساده کردن کار اتصال کامپوننت ها، زبانهای اسکریپتی تمایل دارند تا بدون نوع باشند. همهء چیزها بطور یکسانی بنظر میرسند و بطور یکسانی رفتار میکنند تا بتوانند قابل تبادل باشند. برای مثال، در Tcl یا ویژوال بیسیک یک متغییر میتواند در یک لحظه یک رشته را نگهداری کند و دفعهء بعد یک عدد صحیح را. کد و داده اغلب قابل تبادل هستند، بنابراین یک برنامه میتواند برنامهء دیگری را نوشته و آن را درجا (on the fly) اجرا کند. زبانهای اسکریپتی اغلب رشته گرا (string-oriented) هستند، چراکه این یک نمایش یک شکل را برای بسیاری چیزهای متفاوت فراهم میاورد.
یک زبان بدون نوع بهم متصل کردن کامپوننت ها را خیلی ساده تر میکند. محدودیت های از پیش تعیین شده ای بر روی آنکه چیزها چطور میتوانند استفاده شوند وجود ندارد، و همهء کامپوننت ها و مقدارها به روش یک شکلی معرفی میشوند. بنابراین هر کامپوننت یا مقدار میتواند در هر شرایطی استفاده شود؛ کامپوننت هایی که برای یک مقصود طراحی شده اند میتوانند برای مقاصد کاملا متفاوتی که هرگز بوسیلهء طراح پیشبینی نمیشدند بکار روند. برای مثال، در شل های یونیکس (Unix shells) تمام برنامه های فیلتر یک جریان (stream) از بایتها را از ورودی خوانده و یک جریان از بایتها را در خروجی مینویسند. هر دو برنامه میتوانند بوسیلهء ضمیمه کردن خروجی یک برنامه به ورودی برنامهء دیگر بهم متصل شوند. فرمان شل روبرو سه فیلتر را برای شمارش تعداد خطهایی در متن انتخاب شده که حاوی کلمهء scripting هستند بهم متصل میکند: select | grep scripting | wc
برنامهء select متنی را که درحال حاضر در روی صفحهء نمایش انتخاب شده است میخواند و متن را در خروجی خودش چاپ میکند؛ برنامهء grep ورودی خودش را میخواند و در خروجی خطهایی را که شامل کلمهء scripting هستند چاپ میکند؛ برنامهء wc تعداد خطهای موجود در ورودی اش را میخواند. هر یک از این برنامه ها میتوانند در تعداد بیشماری شرایط دیگر برای انجام کارهای متفاوتی بکار روند.
طبیعت نوع قوی زبانهای سیستمی استفادهء مجدد را مشکل میکند. آن برنامه نویسان را تشویق میکند تا یک مجموعهء متنوع از رابطهای (interface) ناسازگار را بنویسند که هریک از آنها اشیایی از نوع خاصی را نیاز دارد. کامپایلر از استفاده از هر نوع دیگری از اشیاء با رابط مورد نظر جلوگیری میکند، حتی اگر آن میتوانست مفید باشد. پس برای استفاده از یک شیء جدید با یک رابط جدید، برنامه نویس باید کد تبدیلی را برای ترجمه بین نوع شیء و نوع مورد انتظار بوسیلهء رابط بنویسند. این خود باعث میشود که به کامپایل مجدد بخشی یا تمام اپلیکیشن نیاز باشد؛ بسیاری اپلیکیشن ها امروزه در شکل باینری توزیع میشوند و بنابراین این کار امکان ندارد.
برای تقدیر از فواید یک زبان بدون نوع، به فرمان Tcl زیر توجه کنید:


button .b -text Hello! -font {Times16} -command {puts hello}

این فرمان یک کنترل دکمهء جدید که یک رشتهء متنی را با یک فونت 16point Times نمایش داده و یک پیغام کوتاه را موقعی که کاربر روی کنترل کلیک میکند چاپ میکند ایجاد میکند. این فرمان شش نوع مختلف از چیزها را در یک عبارت ترکیب میکند: یک نام فرمان (button)، یک کنترل دکمه (.b)، نام پراپرتی ها (-text، -font، -command)، رشته های ساده (Hello! و hello) یک نام فونت (Times 16) که یک نام typeface (ا Times) و یک اندازه در واحد نقطه (16) را شامل میشود، و یک اسکریپت Tcl (ا puts hello). زبان Tcl تمام این چیزها را بوسیلهء رشته ها به شکل مشابهی نشان میدهد. در این مثال، پراپرتی ها میتوانند در هر ترتیبی مشخص شوند و پراپرتی های مشخص نشده مقدارهای پیشفرض را بدست میاورند؛ بیش از 20 پراپرتی در این مثال بصورت مشخص نشده بودند.
مثال یکسان وقتی در جاوا پیاده سازی شود نیاز به 7 خط کد در دو متد دارد. با سی++ و MFC آن به حدود 25 خط کد در سه procedure نیاز دارد. تنها تعیین فونت به چندین خط کد در MFC نیاز دارد:


CFont *fontPtr = new CFont();
fontPtr->CreateFont(16, 0, 0, 0, 700,
0, 0, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH|FF_DONTCARE,
“Times New Roman”);
buttonPtr->SetFont(fontPtr);

بسیاری از این کد نتیجهء نوع قوی بودن است. برای تعیین فونت یک دکمه، متد SetFont آن باید فراخوانی شود، اما به این متد باید یک اشاره گر به یک شیء CFont پاس شود. این خود باعث میشود نیاز باشد یک شیء جدید اعلان و مقداردهی اولیه شود. برای مقداردهی اولیهء شیء CFont متد CreateFont آن باید فراخوانی شود، اما متد CreateFont یک اینترفیس غیرمنعطف دارد که نیاز دارد 14 آرگومان مختلف مشخص شود. در Tcl، مشخصه های اساسی فونت (typeface Times, size 16 points) میتوانند بلافاصله بدون هیچ اعلان یا تبدیلی استفاده شوند. بعلاوه، Tcl اجازه میدهد تا رفتار دکمه مستقیما در فرمانی که دکمه را ایجاد میکند درج شود، درحالیکه در سی++ یا جاوا آن باید در یک متد بصورت جداگانه اعلان شده قرار داده شود (در عمل، یک مثال جزیی مانند این احتمالا بوسیلهء یک محیط توسعهء گرافیکی که پیچیدگی زبان زیرین را پنهان میکند مدیریت خواهد شد. کاربر مقدار پراپرتی ها را در یک فرم وارد کرده و محیط توسعه کد را تولید میکند. اما، در شرایط پیچیده تر، همچون اختصاص شرطی مقدار پراپرتی ها یا رابطهای تولید شده بصورت برنامه ای، توسعه دهنده باید کد را در زبان زیرین بنویسد).
ممکن است بنظر برسد که طبیعت بدون نوع زبانهای اسکریپتی میتواند به خطاها اجازه بدهد تا آشکارسازی نشوند، اما در عمل زبانهای اسکریپتی همانقدر امن هستند که زبانهای سیستمی هستند. برای مثال، یک خطا رخ خواهد داد اگر اندازهء فونت مشخص شده برای مثال دکمهء بالا یک رشتهء غیر عدد صحیح همچون xyz باشد. زبانهای اسکریپتی چک کردن خطای خود را در آخرین لحظهء ممکن انجام میدهد، وقتی که یک مقدار استفاده میشود. نوع قوی بودن اجازه میدهد تا خطاها در زمان کامپایل آشکارسازی شوند، بنابراین از هزینهء اجرای چک های زمان اجرا اجتناب میشود. هرچند، قیمت پرداخته شده برای کارایی، محدودیت هایی بر روی آنکه اطلاعات چطور میتوانند استفاده شوند است؛ این موجب کد بیشتر و برنامه هایی با انعطاف کمتر میشود.

-- زبانهای اسکریپتی تفسیر میشوند

تفاوت کلیدی دیگر بین زبانهای اسکریپتی و سیستمی آن است که زبانهای اسکریپتی معمولا تفسیر میشوند، درحالیکه زبانهای سیستمی معمولا کامپایل میشوند. زبانهای تفسیر شونده قابلیت تغییرات سریع را در زمان توسعه با حذف زمانهای کامپایل فراهم میکنند. مفسرها همچنین اپلیکیشن ها را بوسیلهء اجازه دادن کاربران به برنامه ریزی اپلیکیشن ها در زمان اجرا منعطف تر میسازند. برای مثال، بسیاری از ابزارهای ترکیب و تحلیل برای مدارهای مجتمع شامل یک مفسر Tcl هستند؛ کاربران برنامه ها اسکریپت های Tcl را برای مشخص کردن طراحی شان و کنترل عملیات ابزارها مینویسند. مفسرها همچنین با تولید کد بصورت درجا امکان ایجاد اثرهای قدرتمند را میدهند. برای مثال، یک مرورگر وب بر اساس Tcl میتواند یک صفحهء وب را با ترجمهء HTML به یک اسکریپت Tcl با استفاده از معدودی جایگزینی عبارات منظم (regular expression) تجزیه کند. آن سپس اسکریپت Tcl را برای نمایش صفحه بر روی صفحهء نمایش اجرا میکند.
زبانهای اسکریپتی از زبانهای سیستمی پرفورمنس کمتری دارند، بخشی بخاطر آنکه آنها از مفسرها بجای کامپایلرها استفاده میکنند اما همچنین بخاطر آنکه اجزای پایهء آنها برای قدرت و استفادهء آسان انتخاب شده اند تا یک نگاشت با پرفورمنس بالا به سخت افزار زیرین. برای مثال، زبانهای اسکریپتی اغلب در شرایطی که یک زبان سیستمی از یک مقدار باینری که در یک کلمهء منفرد حافظه جا میگیرد استفاده خواهد کرد از رشته های با طول متغییر استفاده میکنند، و آنها از hash table ها در جایی که زبانهای سیستمی از آرایه های ایندکس شده استفاده میکنند استفاده میکنند.
خوشبختانه، معمولا پرفورمنس یک زبان اسکریپتی یک مشکل عمده نیست. اپلیکیشن ها برای زبانهای اسکریپتی عموما کوچکتر از اپلیکیشن ها برای زبانهای سیستمی هستند، و پرفورمنس یک زبان اسکریپتی تمایل دارد تا بوسیلهء پرفورمنس کامپوننت هایی مورد احاطه قرار گیرد که معمولا در یک زبان سیستمی پیاده میشوند.
زبانهای اسکریپتی از زبانهای سیستمی سطح بالاتر هستند از این جهت که یک عبارت منفرد بطور میانگین کار بیشتری را انجام میدهد. یک عبارت عادی در یک زبان اسکریپتی صدها یا هزاران دستورالعمل ماشین را اجرا میکند، درحالیکه یک عبارت عادی در یک زبان سیستمی درحدود پنج دستورالعمل ماشین را اجرا میکند (همانطور که شکل 1 نشان میدهد). بخشی از این تفاوت بخاطر آنست که زبانهای اسکریپتی از مفسرها استفاده میکنند، اما خیلی از این تفاوت بخاطر آنست که عملیات اولیه در زبانهای اسکریپتی امکانات بیشتری دارند. برای مثال، در پرل فراخوانی یک جایگزینی عبارت منظم تقریبا به آسانی فراخوانی یک جمع عدد صحیح است. در Tcl، یک متغییر میتواند trace هایی را پیوند شده به آن داشته باشد تا تعیین مقدار متغییر باعث اثرات جانبی شود؛ برای مثال، یک trace میتواند برای آپدیت نگه داشتن مقدار متغییر در روی صفحهء نمایش بکار رود.
زبانهای اسکریپتی اجازه میدهند تا توسعهء سریع کاربردهای اتصال گرا انجام شود. جدول 1 پشتیبانی روایتی برای این ادعا فراهم میکند. آن چند اپلیکیشن را توصیف میکند که در یک زبان سیستمی پیاده سازی شده بودند و سپس در یک زبان اسکریپتی پیاده سازی مجدد شدند یا بعکس. در همهء موارد، نسخهء اسکریپتی نیاز به کد و زمان توسعهء کمتری نسبت به نسخهء زبان سیستمی داشته است؛ اختلاف از یک فاکتور 2 تا یک فاکتور 60 متغییر است. زبانهای اسکریپتی فایدهء کمتری فراهم میکنند وقتی که آنها برای نخستین پیاده سازی استفاده میشوند؛ این اشاره میکند که هر پیاده سازی مجدد از تجربهء بدست آمده از نخستین پیاده سازی سود قابل توجهی میبرد و اختلاف واقعی بین اسکریپت نویسی و برنامه نویسی سیستمی به احتمال بیشتر یک فاکتور از 5 تا 10 میباشد. منافع اسکریپت نویسی همچنین بسته به اپلیکیشن است. در مثال آخر در جدول 1، بخش رابط کاربر گرافیکی اپلیکیشن اتصال گرا است اما بخش شبیه ساز اینطور نیست؛ این میتواند توضیح دهد که چرا اپلیکیشن مورد نظر نسبت به اپلیکیشن های دیگر کمتر از اسکریپت نویسی سود برده است.
ااطلاعات جدول بوسیلهء توسعه دهندگان مختلف Tcl در پاسخ به مقاله ای که در گروه خبری comp.lang.tcl پست شده بود فراهم شده بود.

-- ابزارهای مختلف برای کارهای مختلف

یک زبان اسکریپتی یک جایگزین برای یک زبان سیستمی نیست یا بعکس. هر یک برای یک مجموعه از کارهای متفاوت مناسبند. برای اتصال و یکپارچه سازی سیستم، اپلیکیشن ها میتوانند از 5 تا 10 بار سریعتر بوسیلهء یک زبان اسکریپتی توسعه داده شوند؛ زبانهای برنامه نویسی سیستمی نیاز به مقدار زیادی کدهای پایه و کد تبدیل برای اتصال قطعات دارند، درحالیکه این میتواند مستقیما توسط یک زبان اسکریپتی انجام شود. برای الگوریتم های پیچیده و ساختمان داده ها، نوعگذاری قوی یک زبان سیستمی مدیریت برنامه را ساده تر میسازد. جاییکه سرعت اجرا یک مسئلهء کلیدی است، یک زبان سیستمی میتواند 10 تا 20 برابر سریعتر از یک زبان اسکریپتی اجرا شود زیرا آن چک های زمان اجرای کمتری انجام میدهد.

بقیهء مقاله در پست بعدی (بعلت محدودیت حجم پست در فروم)...

eshpilen
چهارشنبه 03 فروردین 1390, 23:22 عصر
ادامهء پست قبلی...

در تصمیمگیری برای اینکه برای یک کار خاص از یک زبان اسکریپتی استفاده کنیم یا یک زبان سیستمی، به پرسشهای زیر توجه کنید:

- آیا کار اصلی اپلیکیشن اتصال کامپوننت های از پیش آماده است؟
- آیا اپلیکیشن یک مجموعهء متنوع از چیزهای مختلف را دستکاری میکند؟
- آیا اپلیکیشن شامل یک رابط کاربر گرافیکی است؟
- آیا اپلیکیشن مقدار زیادی دستکاری رشته انجام میدهد؟
- آیا امکانات اپلیکیشن در طول زمان به سرعت رشد میکند؟
- آیا اپلیکیشن نیاز دارد گسترش پذیر باشد؟

جوابهای مثبت به این سوالات اشاره میکنند که یک زبان اسکریپتی بخوبی برای اپلیکیشن کار خواهد کرد. از طرف دیگر، جوابهای مثبت به پرسشهای زیر اشاره میکنند که یک زبان سیستمی برای اپلیکیشن مناسبتر است:

- آیا اپلیکیشن الگوریتم ها یا ساختمان داده های پیچیده ای را پیاده سازی میکند؟
- آیا اپلیکیشن مجموعه های داده ای بزرگی را دستکاری میکند؟ بطور مثال، تمام پیکسل های موجود در یک تصویر را، بطوریکه سرعت اهمیت حیاتی دارد.
- آیا امکانات اپلیکیشن بخوبی تعریف شده و به کندی تغییر کننده هستند؟

بیشتر پلتفرم های اصلی پردازشی در طول 30 سال گذشته هردوی زبانهای سیستمی و اسکریپتی را فراهم کرده اند. برای مثال، یکی از نخستین زبانهای اسکریپتی، البته یک مورد زمخت، زبان کنترل وظیفه (Job Control Language) بود که برای چیدن job step ها در OS/360 استفاده میشد. هر job step منفرد در PL/1، فرترن یا زبانهای اسمبلی نوشته میشد که زبانهای سیستمی آن زمان بودند. در ماشین های یونیکس دههء 1980، زبان C برای برنامه نویسی سیستمی و برنامه های شل همچون sh و csh برای اسکریپت نویسی بکار میرفتند. در جهان رایانه های شخصی دههء 1990، سی و سی++ برای برنامه نویسی سیستمی و ویژوال بیسیک برای اسکریپت نویسی بکار میروند. در دنیای اینترنت که اکنون درحال شکل گیری است، جاوا برای برنامه نویسی سیستمی و زبانهایی همچون جاوااسکریپت، پرل، و Tcl برای اسکریپت نویسی استفاده میشوند.
زبانهای اسکریپتی و سیستمی همزیست هستند. استفاده شده با همدیگر، آنها محیطهای برنامه نویسی با قدرت استثنایی را تولید میکنند. زبانهای سیستمی برای ایجاد کامپوننت های موجودی که سپس میتوانند بوسیلهء زبانهای اسکریپتی سوار شوند استفاده میشوند. برای مثال، بسیاری از جاذبهء ویژوال بیسیک آنست که برنامه نویسان سیستمی میتوانند کامپوننت های ActiveX را در زبان سی بنویسند و برنامه نویسان کمتر خبره میتوانند آن کامپوننت ها را در اپلیکیشن های ویژوال بیسیک استفاده کنند. در یونیکس نوشتن اسکریپت های شل که اپلیکیشن های نوشته شده با سی را فراخوانی میکنند آسان است. یکی از دلایل عمومیت Tcl بخاطر توانایی گسترش زبان بوسیلهء نوشتن کد C که فرامین جدیدی را پیاده سازی میکند است.

-- اسکریپت نویسی درحال رشد است

زبانهای اسکریپتی برای زمان طولانی ای وجود داشته اند، اما در سالهای اخیر چندین فاکتور برای افزایش اهمیت آنها ترکیب شده اند. مهمترین فاکتور یک تغییر در ترکیب اپلیکیشن ها به سمت اپلیکیشن های اتصالی است. سه مثال از این تغییر، رابطهای کاربر گرافیکی، اینترنت، و فریمورک های کامپوننت هستند.

- رابطهای کاربر گرافیکی

رابطهای کاربر گرافیکی نخست در اوایل دههء 1980 ظاهر شدند و تا انتهای دهه فراگیر شدند؛ GUI ها اکنون نصف یا بیشتر از مجموع تلاش در بسیاری از پروژه های برنامه نویسی را تشکیل میدهند. GUI ها اساسا اپلیکیشن های اتصالی هستند. هدف نه ایجاد امکانات جدید، بلکه ایجاد اتصالات میان یک مجموعه از کنترل های گرافیکی و عملیات داخلی اپلیکیشن است.
من از هیچ محیط توسعهء سریع برای GUI که بر اساس یک زبان سیستمی بنا شده باشد اطلاعی ندارم. خواه محیط ویندوز است، خواه MacintoshToolbox، خواه Unix Motif، مشخص شده است که تولکیت های GUI بنا شده بر اساس زبانهایی همچون سی یا سی++ برای یادگیری سخت هستند، برای استفاده زمخت هستند، و در نتایجی که تولید میکنند نامنعطف هستند. بعضی از این سیستمها ابزارهای گرافیکی خوبی برای طراحی layout صفحهء نمایش دارند که زبان زیرین را پنهان میکند، اما چیزها به محض اینکه طراح مجبور به نوشتن کد میشود دشوار میشوند. برای مثال، برای فراهم کردن رفتارها برای عناصر رابط. همهء بهترین محیطهای توسعهء سریع GUI بر اساس زبانهای اسکریپتی بنا شده اند: ویژوال بیسیک، HyperCard، و Tcl/Tk.

- اینترنت

رشد اینترنت همچنین باعث محبوبیت زبانهای اسکریپتی شده است. اینترنت چیزی بیشتر از یک ابزار اتصال نیست. آن هیچ پردازش یا دیتای جدیدی را ایجاد نمیکند؛ آن بسادگی مقدار عظیمی از چیزهای موجود را در دسترسی آسان قرار میدهد. زبان ایدئال برای بیشتر کارهای برنامه نویسی اینترنت زبانی است که همهء کامپوننت های متصل شده را قادر میکند با همدیگر کار کنند؛ یعنی، یک زبان اسکریپتی. برای مثال، پرل برای نوشتن اسکریپت های CGI عمومیت یافته است و جاوااسکریپت برای اسکریپت نویسی در صفحات وب.

- فریمورک های کامپوننت

مثال سوم از کاربردهای اسکریپت گرا فریمورک های کامپوننت همچون ActiveX و Java-Beans است. هرچند زبانهای برنامه نویسی سیستمی برای ایجاد کامپوننت ها خوب کار میکنند، کار سوار کردن کامپوننت ها به فرم اپلیکیشن ها بیشتر برای اسکریپت نویسی مناسب است. بدون یک زبان اسکریپتی خوب برای دستکاری کامپوننت ها، بخش زیادی از قدرت یک فریمورک کامپوننت از دست میرود. این میتواند بخشی از این واقعیت را توضیح دهد که چرا فریمورک های کامپوننت روی رایانه های شخصی، جایی که ویژوال بیسیک یک ابزار اسکریپت نویسی راه دست را فراهم میکند، موفقتر بودنده اند تا روی پلتفرم هایی همچون Unix/CORBA که فریمورک کامپوننت شامل اسکریپت نویسی نیست.

-- فناوری اسکریپت نویسی بهتر

دلیل دیگر برای عمومیت فزایندهء زبانهای اسکریپتی بهبودها در فناوری اسکریپت است. زبانهای مدرن اسکریپتی همچون Tcl و پرل فاصلهء زیادی از زبانهای اسکریپتی اولیه همچون JCL دارند. برای مثال، JCL حتی حلقه های تکرار پایه را نداشت و شل های یونیکس اولیه از پراسیجرها پشتیبانی نمیکردند. فناوری اسکریپت حتی امروز هنوز نسبتا نابالغ است. برای مثال، ویژوال بیسیک درواقع یک زبان اسکریپتی نیست؛ آن ابتدا بعنوان یک زبان سیستمی ساده پیاده سازی شده بود، سپس تغییر پیدا کرد تا برای اسکریپت نویسی مناسبتر شود. زبانهای اسکریپتی آینده حتی بهتر از آنهایی خواهند بود که امروزه در دسترس هستند.
فناوری اسکریپت همچنین از سرعت همیشه در حال افزایش سخت افزار رایانه سود برده است. در گذشت تنها راه برای بدست آوردن پرفورمنس قابل قبول در هر اپلیکیشن از هر درجهء پیچیدگی ای معمولا استفاده از یک زبان برنامه نویسی سیستمی بود. در بعضی موارد، حتی زبانهای سیستمی به اندازهء کافی کارا نبودند و بنابراین اپلیکیشن ها باید در زبان اسمبلی نوشته میشدند. اما، ماشین ها امروزه 100 تا 500 برابر سریعتر از ماشین های 1980 هستند، و پرفورمنس هر 18 ماه دوبرابر میشود. امروزه، بسیاری اپلیکیشن ها میتوانند در یک زبان تفسیر شده پیاده سازی شوند و هنوز پرفورمنس عالی داشته باشند. برای مثال، یک اسکریپت Tcl میتواند مجموعه هایی با چندین هزار شیء را دستکاری کند و هنوز پاسخ دهی خوب محاوره ای داشته باشد. همچنان که رایانه ها سریعتر میشوند، اسکریپت نویسی برای برنامه های بزرگتر و بزرگتری جذاب میشود.

-- برنامه نویسان گهگاهی (Casual programmers)

یک دلیل نهایی برای افزایش استفاده از زبانهای اسکریپتی یک تغییر در جامعهء برنامه نویسی است. بیست سال پیش، بیشتر برنامه نویسان برنامه نویسان خبره ای بودند که روی پروژه های بزرگ کار میکردند. از برنامه نویسان آن دوره انتظار میرفت که چندین ماه را برای تسلط یافتن بر یک زبان و محیط برنامه نویسی آن صرف کنند، و زبانهای برنامه نویسی سیستمی برای چنان برنامه نویسانی طراحی شده بودند. اما، از زمان ورود رایانهء شخصی، برنامه نویسان گهگاهی بیشتر و بیشتری به جامعهء برنامه نویسی پیوسته اند. برای این افراد، برنامه نویسی عملیات اصلی شغلی شان نیست؛ آن یک ابزاری است که آنها گهگاه برای کمک کردن به شغل اصلی شان استفاده میکنند. مثالهایی از برنامه نویسی گهگاه، کوئری های سادهء دیتابیس یا ماکروها برای یک صفحهء گسترده است.
برنامه نویسان گهگاهی مایل نیستند تا ماهها برای یادگیری یک زبان برنامه نویسی سیستمی وقت صرف کنند، اما آنها اغلب میتوانند بقدر کافی درمورد یک زبان اسکریپتی در چند ساعت یاد بگیرند تا بتوانند برنامه های مفیدی بنویسند. زبانهای اسکریپتی برای یادگیری ساده تر هستند زیرا آنها سینتاکس ساده تری نسبت به زبانهای سیستمی دارند و آنها ویژگیهای پیچیده ای مثل اشیاء و تردها را حذف میکنند. برای مثال، ویژوال بیسیک را با ویژوال سی++ مقایسه کنید؛ عدهء معدودی از «برنامه نویسان گهگاهی» تلاش خواهند کرد تا از ویژوال سی++ استفاده کنند، اما بسیاری از آنها اپلیکیشن های مفیدی را بوسیلهء ویژوال بیسیک ساخته اند.
حتی امروز، تعداد اپلیکیشن هایی که در زبانهای اسکریپتی نوشته شده اند بسیار بیشتر از تعداد اپلیکیشن هایی است که در زبانهای سیستمی نوشته شده اند. بر روی سیستمهای یونیکس، تعداد خیلی بیشتری اسکریپت شل وجود دارند تا برنامه های سی، و تحت ویندوز تعداد خیلی بیشتری برنامه و اپلیکیشن های ویژوال بیسیک وجود دارند تا سی یا سی++. البته، بیشتر بزرگترین و عمومی ترین اپلیکیشن ها با زبانهای سیستمی نوشته شده اند، و بنابراین یک مقایسه بر اساس تعداد کل خطهای کد یا تعداد کپی های نصب شده ممکن است هنوز برتری زبانهای سیستمی را نشان دهد. بهرحال، زبانهای اسکریپتی پیش از این یک نیروی عمده در توسعهء اپلیکیشن هستند و سهم بازار آنها در آینده افزایش خواهد یافت.

-- نقش اشیاء

زبانهای اسکریپتی بوسیلهء متخصصان زبانهای برنامه نویسی و مهندسی نرم افزار بیشتر مورد نادیده گیری واقع شده اند. درعوض، متخصصان توجه خود را روی زبانهای برنامه نویسی سیستمی شیء گرا همچون سی++ و جاوا متمرکز کرده اند. بطور گسترده باور شده است که برنامه نویسی شیء گرا قدم عمدهء بعدی در تحول زبانهای برنامه نویسی بوده است. اغلب ادعا میشود که ویژگیهای شیء گرایی همچون نوعگذاری قوی و ارث بری زمان توسعه را کاهش میدهند، استفادهء مجدد از نرم افزار را افزایش میدهند، و خیلی از مشکلات دیگر شامل آنهایی که بوسیلهء زبانهای اسکریپتی حل میشوند را حل میکنند.
برنامه نویسی شیء گرا عملا چه مقدار منفعت را فراهم کرده است؟ متاسفانه من مقدار کافی داده های کمیتی برای پاسخ قطعی به این سوال مشاهده نکرده ام. به عقیدهء من، اشیاء تنها یک منفعت متوسط را فراهم میکنند: احتمالا 20 تا 30 درصد بهبود در تولید اما نه مطمئنا یک فاکتور 2 برابر، فاکتور 10 که به کنار. بنظر میرسد اکنون سی++ همانقدر که مورد علاقه است مورد ناسزاگویی قرار میگیرد، و بعضی متخصصان زبان درحال شروع به صحبت علیه برنامه نویسی شیء گرا هستند. اشیاء آنقدری که اسکریپت نویسی بازدهی را بالا میبرد بازدهی را بالا نمیبرند، و فواید برنامه نویسی شیء گرا میتوانند در زبانهای اسکریپتی بدست آیند.
برنامه نویسی شیء گرا یک بهبود بزرگ در بازدهی را فراهم نمیکنم زیرا آن نه سطح برنامه نویسی را بالا میبرد و نه استفادهء مجدد را تشویق میکند. در یک زبان شیء گرا همچون سی++، برنامه نویسان هنوز با واحدهای کوچک پایه ای کار میکنند که میباید با جزییات زیادی توصیف و دستکاری شوند. در تئوری، پکیج های قدرتمند کتابخانه میتوانستند توسعه داده شوند، و اگر این کتابخانه ها بصورت گسترده استفاده میشدند میتوانستند سطح برنامه نویسی را بالا ببرند. اما، معدودی از چنان کتابخانه هایی وجود دارند. نوعگذاری قوی بیشتر زبانهای شیء گرا باعث ایجاد پکیج های تعریف شده در محدودهء باریکی میشود که برای استفادهء مجدد دشوار هستند. هر پکیج به اشیایی از یک نوع خاص نیاز دارد؛ اگر دو پکیج باید با همدیگر کار کنند، کد تبدیل کننده باید نوشته شود تا میان نوع هایی که پکیج ها نیاز دارند ترجمه کند.
مشکل دیگر با زبانهای شیء گرا تاکید آنها بر ارث بری است. ارث بری پیاده سازی (Implementation inheritance)، که در آن یک کلاس کدی را که برای کلاس دیگر نوشته شده بود قرض میگیرد، یک ایدهء بد است که مدیریت و استفادهء مجدد نرم افزار را دشوارتر میکند. آن پیاده سازی کلاسها را بهم پیوند میدهد که هیچ کلاسی نمیتواند بدون دیگری فهم شود. یک زیرکلاس نمیتواند بدون دانستن اینکه متدهای به ارث رسیده چطور در سوپرکلاس هایش پیاده سازی شده اند فهمیده شود، و یک سوپرکلاس نمیتواند بدون فهمیدن اینکه چطور متدهایش در زیرکلاس ها به ارث برده شده اند فهمیده شود. در یک سلسله مراتب کلاس پیچیده، هیچ کلاس منفردی نمیتواند بدون فهمیدن تمام کلاسهای دیگر در سلسله مراتب درک شود. حتی بدتر، یک کلاس نمیتواند از سلسله مراتب خود برای استفادهء مجدد جدا شود. ارث بری چندگانه این مشکلات را حتی بدتر میکند. ارث بری در پیاده سازی باعث درهم پیچیدگی و شکنندگی مشابهی میشود که وقتی عبارت های goto بیش از حد ااستفاده میشوند دیده شده است. بعنوان یک نتیجه، سیستمهای شیء گرا اغلب از پیچیدگی و عدم استفادهء مجدد رنج میبرند.
ااز طرف دیگر، زبانهای اسکریپتی، عملا استفادهء مجدد زیادی از نرم افزار را ایجاد کرده اند. مدلی که آنها از آن پیروی میکنند آنست که کامپوننت ها در یک زبان سیستمی ساخته میشوند و سپس در اپلیکیشن ها بوسیلهء یک زبان اسکریپتی به همدیگر چسبانده میشوند. این تقسیم کار یک فریمورک طبیعی را برای استفادهء مجدد فراهم میاورد. کامپوننت ها برای استفادهء مجدد طراحی میشوند، و اینترفیس های بخوبی تعریف شده میان کامپوننت ها و اسکریپت ها وجود دارند که استفاده از کامپوننت ها را ساده میکنند. برای مثال، در Tcl کامپوننت ها فرمانهای سفارشی پیاده سازی شده در C هستند؛ آنها همچون فرمانهای درونی (built-in) بنظر میرسند و بنابراین فراخوانی آنها در در اسکریپت های Tcl ساده است. در ویژوال بیسیک، کامپوننت ها توسعه های ActiveX هستند که میتوانند بوسیلهء دراگ کردن آنها از پالت به روی فرم استفاده شوند.
بهرحال، برنامه نویسی شیء گرا حداقل دو ویژگی مفید را فراهم میکند. نخستین کپسوله سازی (encapsulation) است: اشیاء دیتا و کد را در یک شکلی که جزییات پیاده سازی را پنهان میکند ترکیب میکنند. این مدیریت سیستمهای بزرگ را ساده تر میکند. ویژگی مفید دوم ارث بری اینترفیس (interface inheritance) است، که در آن کلاسها متدها و رابط برنامه نویسی اپلیکیشن (API) یکسانی را با وجود آنکه آنها پیاده سازیهای متفاوتی دارند فراهم میکنند. این کلاسها را قابل تبادل ساخته و به استفادهء مجدد کمک میکند.
خوشبختانه، فواید اشیاء میتواند در زبانهای اسکریپتی و نیز زبانهای سیستمی بدست آورده شود، و تقریبا تمام زبانهای اسکریپتی پشتیبانی ای برای برنامه نویسی شیء گرا دارند. برای مثال، پایتون یک زبان اسکریپتی شیء گرا است؛ پرل 5 شامل پشتیبانی از اشیاء است؛ Object Rexx یک نسخهء شیء گرا از Rexx است؛ و Incr Tcl یک توسعهء شیء گرا برای Tcl است. یک تفاوت اینست که اشیاء در زبانهای اسکریپتی تمایل دارند تا بدون نوع باشند، درحالیکه اشیاء در زبانهای سیستمی تمایل دارند تا نوع قوی باشند.

-- زبانهای دیگر

ااین مقاله بعنوان یک تشریح برای تمام زبانهای برنامه نویسی درنظر گرفته نشده است. بسیاری ویژگیهای دیگر از زبانهای برنامه نویسی بعلاوهء قدرت نوعگذاری و سطح برنامه نویسی وجود دارند، و بسیاری زبانهای جالب وجود دارند که نمیتوانند بصورت تمیزی بعنوان یک زبان سیستمی یا زبان اسکریپتی مشخص شوند. برای مثال، خانوادهء زبانهای Lisp جایی بین برنامه نویسی اسکریپتی و سیستمی قرار میگیرند، با ویژگیهای از هر یک. Lisp پیشگام مفاهیمی همچون تفسیر و نوعگذاری دینامیک (dynamic typing) بود که اکنون در زبانهای اسکریپتی متداول هستند، همچنین مدیریت ذخیره سازی خودکار و محیطهای توسعهء یکپارچه (IDE)، که اکنون در هر دوی زبانهای اسکریپتی و سیستمی استفاده میشود.


زبانهای اسکریپتی یک مجموعه مصالحهء متفاوت از زبانهای سیستمی را نمایش میدهند. آنها نسبت به زبانهای سیستمی سرعت اجرا و قدرت نوعگذاری را واگذار میکنند اما به میزان قابل توجهی بازدهی برنامه نویسی و استفادهء مجدد از نرم افزار را بالا میبرند. این مصالحه همچنان که رایانه ها در مقایسه با برنامه نویسان سریعتر و ارزان تر میشوند بیشتر معنا پیدا میکند. زبانهای سیستمی برای ساختن کامپوننت هایی که پیچیدگی در ساختمان های داده ای و الگوریتم است مناسب هستند، درحالیکه زبانهای اسکریپتی برای کاربردهای اتصالی که پیچیدگی در اتصالات است مناسب هستند. کارهای اتصالی درحال شایع شدن بیشتر و بیشتر هستند، بنابراین اسکریپت نویسی یک پارادایم با اهمیت فزاینده در قرن بعدی خواهد بود.
من امیدوارم که این مقاله جامعهء برنامه نویسی را به سه شکل مورد تاثیر قرار خواهد داد. نخست، امیدوارم برنامه نویسان تفاوت های میان زبانهای اسکریپتی و سیستمی را وقتیکه پروژه های جدید را شروع میکنند مورد توجه قرار داده و قویترین ابزار برای هر کار را انتخاب کنند. دوم، امیدوارم که طراحان فریمورک های کامپوننت اهمیت اسکریپت نویسی را تشخیص داده و اطمینان حاصل کنند که فریمورک های آنها نه تنها شامل امکاناتی برای ایجاد کامپوننت ها بلکه همچنین شامل امکاناتی برای اتصال آنها به همدیگر است؛ نهایتا، امیدوارم که جامعهء تحقیق زبانهای برنامه نویسی مقداری از توجه خود را به زبانهای اسکریپتی منتقل خواهد کرد و کمک میکند تا زبانهای اسکریپتی حتی قویتری توسعه داده شوند. بالا بردن سطح برنامه نویسی باید مهمترین هدف برای طراحان زبان باشد، چراکه آن بیشترین تاثیر را بر روی بازدهی برنامه نویس دارد. روشن نیست که نوعگذاری قوی به این هدف کمک میکند.

==========================================

منبع: http://www.stanford.edu/~ouster/cgi-bin/papers/scripting.pdf

eshpilen
چهارشنبه 03 فروردین 1390, 23:23 عصر
طی دو پست بعدی منابع تکمیلی ای که لازم دیدم درج میشوند.

eshpilen
چهارشنبه 03 فروردین 1390, 23:24 عصر
دربارهء مولف مقالهء ترجمه شده:

John Kenneth Ousterhout رئیس شرکت Electric Cloud، و یک استاد علم رایانه در دانشگاه استنفورد است. او Electric Cloud را به همراه John Graham-Cumming تاسیس کرد. Ousterhout سابقا یک استاد علم رایانه در دانشگاه برکلی کالیفرنیا بود، جاییکه او زبان اسکریپتی Tcl و Tk که یک widget toolkit مستقل از پلتفرم است را ایجاد کرد. Ousterhout همچنین گروهی را که سیستم عامل آزمایشی Sprite و نخستین سیستم فایل log-structured را طراحی کرد رهبری کرد. Ousterhout همچنین نویسندهء اولیهء برنامهء Magic VLSI Computer-aided design است.

ااو مدرک لیسانس خود را در فیزیک از دانشگاه Yale در 1975 دریافت کرد، و دکترایش را در علم رایانه از دانشگاه Carnegie Mellon در 1980.

Ousterhout جایزهء Grace Murray Hopper را در 1987 دریافت کرد و در 1994 او یکی از اعضای انجمن Computing Machinery بود. Ousterhout همچنین عضو آکادمی ملی مهندسی است.

در 1994، Ousterhout برکلی را برای پیوستن به آزمایشگاههای Sun Microsystems ترک کرد، که تیمی را برای پیوستن به او در توسعهء Tcl استخدام کرد. پس از چندین سال در Sun، او Sun را ترک کرد و در ژانویهء 1998 شرکت Scriptics, Inc (بعدها تغییر نام داده شده به Ajuba Solutions) را برای تامین کردن ابزارهای توسعهء حرفه ای Tcl تاسیس کرد و تیم Tcl به در Sun او را پیروی کردند. Ajuba بوسیلهء Interwoven در اکتبر 2000 خریداری شد. او در 2008 به دانشگاه استنفورد پیوست.


==========================

منبع: http://en.wikipedia.org/wiki/John_Ousterhout

eshpilen
چهارشنبه 03 فروردین 1390, 23:25 عصر
دو دستگی Ousterhout

دو دستگی Ousterhout ادعای دانشمند رایانه John Ousterhout است که زبانهای سطح بالا به دو گروه تقسیم میشوند، هر یک با ویژگیها و استفاده های مجزا: «زبانهای سیستمی» و «زبانهای اسکریپتی».
این تفکیک زیربنای طراحی زبان او Tcl است.

زبانهای برنامه نویسی سیستمی معمولا ویژگیهای زیر را دارند:

- آنها از نوعگذاری استاتیک استفاده میکنند (statically typed).
- آنها از ایجاد ساختمان های داده ای پیچیده پشتیبانی میکنند.
- برنامه ها در آنها برای عملکرد تاحد زیادی مستقل از بقیهء برنامه ها درنظر گرفته شده اند.

زبانهای برنامه نویسی سیستمی تمایل دارند برای کامپوننت ها و اپلیکیشن هایی با میزان زیادی از امکانات داخلی همچون سیستمهای عامل، سرورهای دیتابیس و مرورگرهای وب بکار روند. این اپلیکیشن ها معمولا الگوریتم ها و ساختمان داده های پیچیده ای را استفاده میکنند و به پرفورمنس بالا نیاز دارند. مثالهای پیش نمونه ای از زبانهای برنامه نویسی سیستمی شامل زبانهای C و Modula-2 میشود.

در مقابل، زبانهای اسکریپتی (یا «زبانهای چسباننده» - glue languages) تمایل دارند تا ویژگیهای زیر را داشته باشند:

- آنها نوعگذاری دینامیک دارند (dynamically typed).
- آنها هیچ یا تمهیدات کمی برای ساختمان داده های پیچیده دارند.
- برنامه ها در آنها (اسکریپت ها) تفسیر میشوند.

زبانهای اسکریپتی تمایل دارند برای اپلیکیشن هایی استفاده شوند که بیشتر امکانات آنها از برنامه های دیگری حاصل میشود (که اغلب در زبانهای سیستمی پیاده سازی میشوند)؛ اسکریپت ها برای چسباندن برنامه های دیگر یا ایجاد لایه های اضافی امکانات بر روی برنامه های موجود استفاده میشوند. Ousterhout ادعا میکند که اسکریپت ها تمایل دارند کوتاه باشند و اغلب بوسیلهء برنامه نویسان کمتر خبره نوشته میشوند، بنابراین پرفورمنس اجرا کمتر از سادگی و راحتی تعامل با بقیهء برنامه ها اهمیت دارد. کاربردهای متداول برای اسکریپت نویسی شامل تولید صفحات وب، تولید گزارش، رابطهای کاربر گرافیکی، و مدیریت سیستم میشود. مثالهای پیش نمونه ای از زبانهای اسکریپتی شامل AppleScript, C Shell, DOS batch files, و Tcl هستند.

بسیاری عقیده دارند که این دو دستگی تا حد زیادی سلیقه ای است و به آن بعنوان «سفسطهء Ousterhout» یا «دو دستگی غلط Ousterhout» اشاره میکنند. درحالیکه قوی بودن در مقابل ضعیف بودن نوعگذاری، پیچیدگی ساختمان داده، و مستقل درمقابل وابسته ممکن است بعنوان ویژگیهای نامربوط بیان شوند، انتقاد معمول از دودستگی Ousterhout مربوط به تمایز کامپایل درمقابل تفسیر است، چراکه نه معنا و نه سینتاکس بطور قابل توجهی به آنکه کد به زبان ماشین کامپایل میشود، تفسیر میشود، tokenize میشود، و یا در شروع هر اجرا به بایت-کد کامپایل میشود، یا هر ترکیبی از اینها وابسته نیست. بسیاری از زبانهای برنامه نویسی بین تفسیرشدگی یا کامپایل شدگی واقع میشوند (بطور مثال Lisp, Forth, UCSD Pascal, Perl, و Java). این کامپایل درمقابل تفسیر را یک پارامتر مورد تردید در تقسیم بندی زبانهای برنامه نویسی میسازد.

====================================

منبع: http://en.wikipedia.org/wiki/Ousterhout%27s_dichotomy

eshpilen
دوشنبه 08 فروردین 1390, 23:45 عصر
با اینکه به این مقاله انتقادهایی وارد هست و بنده هم لزوما بطور دقیق و کامل با تمام بخشهای اون موافق نیستم، اما درکل بنظرم به مسائل جالب و مهمی اشاره کرده و موارد تفکیک و کاربرد ای رو بخوبی روشن کرده که واقعا کار ساده ای نیست. بخاطر اینکه محتوای این مقاله درکل خیلی مفید بنظرم رسید اون رو باوجود حجیم بودن ترجمه کردم.
بطور مثال مثالی که با استفاده از ترکیب برنامه های خط فرمان در شل یونیکس زده واقعا گویا هست و نشون میده مزیت و کاربرد بجای زبانهایی با این خصوصیات و ایجاد برنامه و عملیات مورد نظر به روش کامپوننت گرا تا چه حد کارا و مفید هست و سطح برنامه نویسی رو واقعا چقدر بالا میبره. بقول خودش این زبانها سطح برنامه نویسی رو نسبت به چیزی مثل شیء گرایی صرف که همگان خیلی روش تمرکز میکنن خیلی بالاتر میبرن. البته مسلما میشه و باید شیء گرایی رو هم با این زبانها ترکیب کرد تا به حداکثر سطح و توان مدیریت برنامه ها (بخصوص برنامه های بزرگتر و پیچیده تر) رسید. ولی شاید چون شیء گرایی در زبانهای سیستمی که طرفداران و کاربرد زیادی دارن باعث افزایش توان مدیریت و انعطاف و نگهداری و توسعهء برنامه ها میشه، خیلی روش تمرکز شده و بقول مولف اونقدری که باید به نقش و اهمیت و استفاده از زبانهای اسکریپتی توجه نشده.
همون عملیات select | grep scripting | wc رو اگر بخوایم در زبانی مثل سی یا حتی زبانهای سطح بالاتری پیاده سازی کنیم، مسلما برنامهء ما تعداد خطوط خیلی بیشتری خواهد داشت و زحمت و پیچیدگی بیشتری داره و در ضمن احتمال وجود باگ در اون خیلی بیشتر هست.

برای خود بنده همیشه تفاوت زبانهای اسکریپتی با زبانهای دیگه و علت موفقیت و کاربرد مناسب اونها همیشه سوال بود. احساس میکردم تفاوتهای کلیدی ای وجود داره و این زبانها حداقل در یکسری کاربردها واقعا مناسب هستن و مزیت دارن نسبت به زبانهای دیگه، اما دقیقا نمیتونستم بگم این تفاوت های کلیدی در کجاست و منطق اونها چیه و چطور اثر میکنن و چرا بطور مثال در برنامه نویسی وب این زبانها اینقدر کاربرد دارن و مناسب هستن.

انتقادهایی به این مقاله وارد شده که مهمترینش این هست که میگن تفکیک بر اساس روش اجرای تفسیری یا کامپایل، تفکیک دقیق و صحیحی نیست چون لزوما زبانی که این خصوصیات و کاربرد رو داره مجبور نیست به حالت تفسیر اجرا بشه. اما نکتهء جالب توجه بنظر بنده اینه که در عمل تمام یا بیشتر زبانهایی که این خصوصیات رو دارن (عمدتا بدون نوع بودن که بقیهء خصوصیات هم کم و بیش از این خصیصه منشاء میگیرن) روش اجرای اونها تفسیری هست تا کامپایل کامل. حالا علت این امر چیه و آیا کسی مثالی میتونه از زبان دیگری بیاره که خصوصیات سینتاکس/برنامه نویسی و کاربرد زبانهای اسکریپتی (اتصال و ترکیب کامپوننت ها) رو داشته باشه ولی روش اجرای اون کامپایل به کد Native باشه نمیدونم! بنده حدس میزنم که شاید علت اینکه این خصوصیات و کاربرد رو درمورد زبانهایی اسکریپتی میبینیم این باشه که پیاده سازی این خصوصیات و کاربردهای مورد نظر، با یک سیستم اجرای تفسیری خیلی ساده تر و منعطف تر هست.
الان یه چیز دیگه هم بنظرم رسید، و اون اینکه چون بدون نوع بودن همانطور که مولف در این مقاله بهش اشاره میکنه بهرصورت مستلزم چک های زمان اجرای زیادی هست که سرعت رو پایین میارن، تفاوت میان کامپایل شدن کامل به کد Native و تفسیر شدن از نظر سرعت اجرا نسبت به تفاوت سرعت همین دو حالت اجرا درمورد زبانهای نوع قوی خیلی کمتر میشه و بنابراین طراحان گزینهء مفسر رو برای اجرا انتخاب میکنن که باوجودی که سرعتش هنوز مقداری (دقیقا نمیدونم چقدر) از کامپایل کامل کمتر هست اما در عوض یکسری خصوصیات و مزایای مفید دیگه رو به محیط برنامه نویسی اضافه میکنه. مثلا یکی از این خصوصیات همون قضیه سرعت بالای توسعه و تست ها هست بخاطر اینکه نیاز به زمانها و مراحل و پیچیدگی های سیستم کامپایل حذف میشه و کافیه فایل سورس ویرایش و سپس Save بشه و بعد فورا میشه برنامه رو اجرا و تست کرد. حذف این زمانهای کامپایل مزیت کوچکی نیست و بنده هم شخصا قبلا به این مزیت اشاره کرده بودم و بطور مثال همین مزیت در عمل برام علت انتخاب زبانهای اسکریپتی در مورد بعضی برنامه ها بوده. بخصوص درمورد برنامه های آزمایشی، پیاده سازی الگوریتم های جدید، Protoype کردن و اینطور چیزها. درمورد برنامه های کوچک که بخصوص به روش ترکیب کامپوننت ها باشن هم معمولا زبانهای تفسیری بهترین گزینه هستن.
این مزیت رو با مزیت احتمالی ساده تر و منعطف تر بودن پیاده سازی زبان به روش تفسیری اگر درنظر بگیریم، احتمالا توضیح کافی میده که چرا زبانهایی با این خصوصیات و کاربرد تقریبا در تمام موارد بصورت اسکریپتی یا به عبارت دیگه همون اجرا توسط مفسر، طراحی میشن.
ضمنا مثلا درنظر بگیرید تابع Eval که در زبانهای اسکریپتی وجود داره و باهاش میشه کد رو بصورت On the fly اجرا کرد، پیاده سازیش در زبانهایی که روش اجرای اونها کامپایل باشه نیاز به درج یک سیستم کامپایلر یا مفسر کامل درخود محیط اجرای اون زبان داره. احتمالا درصورت کاربرد کامپایلر، زمان کامپایل که معمولا قابل توجه هست و اگر در بیشتر موارد از زمان تفسیر بالا نزنه ولی در کل برابر یا نزدیک زمان اجرای تفسیری هست، باعث میشه که انتخاب یک مفسر گزینهء مناسب تری باشه. و شاید به همین علت که بهرصورت نیاز هست که یک مفسر طراحی بشه، کل محیط اجرای زبان رو بصورت تفسیری پیاده سازی میکنن. چون در غیر اینصورت مجبور هستن هم یک کامپایلر و هم یک مفسر رو طراحی کنن و در محیط اجرا بگنجانن و این دو رو با هم پیوند بدن.
نکتهء دیگری که بنظرم میرسه و البته ممکنه چندان مهم و موثر نباشه اما ذکرش رو به جهت تکمیل مطلب مفید میبینم، اینه که اگر فقط تابع مخصوص اجرای کد بصورت On the fly بصورت تفسیری عمل کنه، اختلاف سرعت اجرا در بخشهای مختلف برنامه و بعضی اختلافات و ضمنا پیچیدگی های بیشتری ممکنه بین اجزای مختلف برنامه و در پیاده سازی زبان پیش بیان. بطور مثال کدی که توسط مفسر اجرا میشه آیا نیاز به ارتباط و دستکاری و تعامل با کدهای کامپایل شونده داره (و بعکس) یا نه و آیا تامین این ارتباط بین کدی که از قبل کامپایل شده و کدی که درحال اجرا توسط یک مفسر هست بصورت بقدر کافی کامل و منعطفی ممکن هست یا خیر، یا اینطور بگیم که آیا پیاده سازی چنین چیزی نمیتونه بحد قابل توجهی پیچیده بشه؟

eshpilen
سه شنبه 09 فروردین 1390, 00:16 صبح
قبلا بحثهایی داشتیم با دوستان در این فروم که یادمه مثلا میگفتن که با سی++ میشه همه نوع برنامه ای نوشت و برای همه کاری مناسبه و مثلا ویژگیهای و امکاناتی که در زبانهای دیگر وجود دارن خودشون (منظور مفسرها و کتابخانه های اونها) با همین زبانها (سی و سی++) پیاده سازی شدن و بنابراین میشه همهء اون امکانات رو در زبانهایی مثل سی++ هم داشت.
اما این مقاله و استدلالهایی که بنده داشتم بنظرم نشون میدن که این حرفها بیشتر تئوریک هستن تا عملی.
همونطور که مولف به خوبی استدلال میکنه و نشون میده، ماهیت نوع قوی زبانهایی مثل سی++ باعث میشه انعطاف اونها کم بشه و سطح برنامه نویسی اونها به حد زبانهای بدون نوع نرسه و بخصوص در زمینهء استفادهء بهینه از روش برنامه نویسی کامپوننتی مانع ایجاد میکنه. درسته ما میتونیم برنامه ها رو در زبانهای بقول مولف «سیستمی» هم بنویسیم، اما از نظر سطح برنامه نویسی اختلاف قابل توجهی با زبانهای بدون نوع وجود داره. بطور متوسط هر خط از کد یک زبان بدون نوع میتونه تعداد عملیات بیشتری رو انجام بده؛ و این یعنی بالا رفتن سطح برنامه نویسی. یعنی برنامه های ما در زبانهای نوع قوی مسلما تعداد خطوط بیشتری خواهند داشت. البته مولف این واقعیت رو بیشتر درمورد برنامه هایی که کامپوننت گرا هستن و محتوی اجزای داخلی زیاد که الگوریتم ها و ساختمان داده های پیچیده ای رو پیاده سازی میکنن نیستن، صادق میدونه. البته بر طبق مقایسهء نمونه برنامه هایی که مقایسه شدن (تصویر مربوطه رو در منبع اصلی ببینید)، در موارد دیگر هم این برتری در تعداد کمتر خطوط برنامه و زمان پیاده سازی وجود داره، اما اختلاف کمتر هست و احتمالا در اون موارد سرعت اجرای بیشتر زبانهای کامپایل شونده و نوع قوی مهمتر بحساب میاد.

و درسته که از نظر تئوریک میشه مثلا تولید و اجرای کد برنامه به شکل On the fly رو در زبان سی++ هم داشت، ولی احتمالا پیاده سازی چنین سیستمی در یک زبان کامپایل شونده و نوع قوی سخت تر و پیچیده تر و هزینه برتر از یک زبانی که با یک مفسر اجرا میشه خواهد بود. و بنظر بنده حتما باید از خودمون بپرسیم اصلا چرا هیچکدام از این زبانها چنین امکانی رو بصورت استاندارد و پیشفرض ندارن؟ و چرا حتی کمتر کتابخانهء معروفی هم چنین امکانی رو داره؟ بنده که شخصا ندیدم تاحالا. از طرف دیگه حتی در .NET هم چنین امکانی رو ندیدم که برام تعجب آور بود.

هرچیزی علتی داره. هیچ چیزی بی علت نیست.
زبانهای اسکریپتی مسلما در عمل خواص و مزایای مهمی دارن که بعضی زبانها و کاربردها با خصوصیاتی که دارن، تقریبا همیشه به روش اسکریپتی یا روشی نزدیک اون پیاده سازی میشن. این تصادفی نیست! چرا زبانهای اسکریپتی در برنامه نویسی وب فرمانروایی میکنن؟
چرا زبانهای کامپایل شونده فاقد تابعی مثل تابع Eval هستن اما (تقریبا) تمام زبانهای اسکریپتی این تابع رو دارن؟
جواب این پرسشها مسلما آموزنده هست.

FastCode
پنج شنبه 11 فروردین 1390, 13:17 عصر
سلام.
فکر میکنم کلمه فوق العاده شایسته باشه.
خیلی خوب بود.
ولی :

بنده که شخصا ندیدم تاحالا. از طرف دیگه حتی در .NET هم چنین امکانی رو ندیدم که برام تعجب آور بود.
داره.
من خودم شخصا با دات نت در زمان اجرا هم native code و هم managed code رو on the fly ایجاد و اجرا کردم.native code دهن سرویس میکنه ولی خیلی حال میده تو دات نت native code اجرا کنی.

زبونهای دیگه مثل C++ هم که هیچ مشکلی ندارند. فقط کافیه توی مغزتون یک کامپایلر in-line داشته باشید تا بفهمید چکار دارید میکنید.بقیش مشکلی نداره.

آخرش من نفهمیدم این vb استاتیک ه یا نه.ولی EVal داره.
C# در نسخه های بعد Anders Heljsberg قول داده داشته باشه.توی اون جلسه معرفی C# 4 که آقای موسوی اون موقع ها لینک فیلمش رو گزاشتن که اینطوری بود.

eshpilen
پنج شنبه 11 فروردین 1390, 19:40 عصر
من خودم شخصا با دات نت در زمان اجرا هم native code و هم managed code رو on the fly ایجاد و اجرا کردم.native code دهن سرویس میکنه ولی خیلی حال میده تو دات نت native code اجرا کنی.

زبونهای دیگه مثل C++ هم که هیچ مشکلی ندارند. فقط کافیه توی مغزتون یک کامپایلر in-line داشته باشید تا بفهمید چکار دارید میکنید.بقیش مشکلی نداره.
میشه برای اینایی که میگید نمونه کد بذارید؟
درحد مثال ساده هم باشه کافیه.

FastCode
پنج شنبه 11 فروردین 1390, 23:04 عصر
1.
http://www.atrevido.net/blog/PermaLink.aspx?guid=ac03f447-d487-45a6-8119-dc4fa1e932e1
2.
IntPtr pExecutableBuffer = VirtualAlloc(
IntPtr.Zero,
new IntPtr(byteCount),
AllocationType.MEM_COMMIT | AllocationType.MEM_RESERVE,
MemoryProtection.PAGE_EXECUTE_READWRITE);

eshpilen
جمعه 12 فروردین 1390, 22:28 عصر
http://www.atrevido.net/blog/PermaLink.aspx?guid=ac03f447-d487-45a6-8119-dc4fa1e932e1
مطمئنی این مثال ربط خاصی داره؟
تاجایی که میبینم فقط یک تکه کد کوچک و سادهء اسمبلی رو در دات نت با یک ترفند اجرا کرده. تازه اونم ظاهرا مستقیما از کد ماشین استفاده کرده و نه حتی اسمبلی!
ما درمورد تابع Eval صحبت میکنیم. این تابع یک رشته رو به زبان برنامه نویسی سطح بالا میگیره و اجرا میکنه؛ و این اجرا در فضای پراسس اصلی برنامه هست که بطور مثال کدی که توسط تابع Eval اجرا میشه میتونه به متغییرها و توابع برنامهء اصلی هم دسترسی داشته باشه.

و اون دومی چیه؟ میشه بیشتر توضیح بدی؟

FastCode
شنبه 13 فروردین 1390, 10:53 صبح
مطمئنی این مثال ربط خاصی داره؟
تاجایی که میبینم فقط یک تکه کد کوچک و سادهء اسمبلی رو در دات نت با یک ترفند اجرا کرده. تازه اونم ظاهرا مستقیما از کد ماشین استفاده کرده و نه حتی اسمبلی!
ما درمورد تابع Eval صحبت میکنیم. این تابع یک رشته رو به زبان برنامه نویسی سطح بالا میگیره و اجرا میکنه؛ و این اجرا در فضای پراسس اصلی برنامه هست که بطور مثال کدی که توسط تابع Eval اجرا میشه میتونه به متغییرها و توابع برنامهء اصلی هم دسترسی داشته باشه.

و اون دومی چیه؟ میشه بیشتر توضیح بدی؟

این بخش سختش بود.
فکر کردم با طرز کار reflection.Emit آشنا هستید.

eshpilen
شنبه 13 فروردین 1390, 23:45 عصر
ببین من ازت یه مثال ساده خواستم. دیگه مبهم حرف زدن و غیره برای چی؟
یه نمونه کد بذار که یک کد به زبان سطح بالا رو بگیره و اجرا کنه. اینقدر مشکله؟
شما که میگی این کار رو کردی. ولی شاید در یه مقیاس و شکل خیلی محدودی این کار رو کردی.
من فکر میکنم بدیهی هست که این کار بصورت نامحدود و عملی اون یا باید با یک مفسر کامل انجام بشه و یا با یک کامپایلر کامل. راه دیگری هم نداره؛ چون شما میخوای کاری رو انجام بدی که یه برنامهء عادی انجام میده و روندی که بهرصورت باید طی بشه. برای اجرا دستورات برنامه نویسی تاحالا چه راه دیگری پیدا شده؟ منظور اجرای دستوراتی هست که از پیش از اجرای برنامه مشخص نیستن و باید بصورت On the fly و در فضای پراسس اصلی اجرا بشن.
شما که میگی میشه این کار رو کرد بگو چطور معجزه شده و راه دیگری برای اجرای راحت و کامل سورس کد پیدا شده.
بنابراین تمام راههای دیگه بنظرم اصلا قابل مقایسه با کارایی تابع eval نیستن.
خلاصه طفره نرو. این کارا و ترفند بازیها درست نیست. از بیان جمله های مبهم، کلی، و بی فایده خودداری کن. طوری صحبت میکنی انگار یه پروفسور داره با یه بی سواد صحبت میکنه. این مهم نیست، اگر نمیخوای میتونی با من بحث نکنی، ولی اگر میخوای ادامه بدی و چیزی رو ثابت کنی عملا و مردانه این کار رو بکن. من از رفتار دغل کارانه متنفرم.
من میدونم دات نت امکان کامپایل کد منبع و اجراش رو داره، اما اون روش خارج از پراسس اصلی کار میکنه و معادل تابع eval نیست. البته روشهای دیگری هم بصورت ساخت دینامیک اجزای اجرایی زبان کلاسهاش در دات نت هست و دیدم، ولی ما نیاز داریم تمام کارها بصورت خودکار و راحت انجام بشه و هر کد واجد شرایطی رو بشه به این روش اجرا کرد؛ کدی که بطور مثال کاربر برنامه موقع اجرا ممکنه وارد بکنه.