Wednesday, December 20, 2006

Ruby (2)

قبلا درباره Ruby و ویژگی های آن(بطور کلی) مطالبی نوشتم. در این قسمت قصد دارم جزئیات بیشتری را مطرح کنم. در این بخش بیشتر به این مسئله خواهم پرداخت که چرا کد نوشته شده به زبان Ruby خلاصه تر از کدی هست که به بسیاری از زبان های دیگر مانند جاوا، سی شارپ و C++ نوشته می شود. ساده ترین دلیلی که برای این امر می توان بیان کرد این است که Ruby چیز اضافه ای ندارد. این جمله در نگاه اول شاید عجیب به نظر برسد ولی در ادامه سعی می کنم منظور خودم را واضح تر بیان کنم. بسیاری از ویژگیهایی که در اینجا بیان شده می توانند مزایا و معایبی داشته باشند ولی در هر حال هدف اصلی در Ruby افزایش Productivity بوده است. هنر طراحان Ruby در این بوده که در عین افزایش Productivity توانسته اند تا حد زیادی دیگر ویژگی های مثبت زبان مانند قابلیت نگهداری(Maintainability)، مقیاس پذیری (بیشتر منظورم مقیاس پذیری در جهت انجام پروژه های بزرگ و با حجم زیاد کد است تا مقیاس پذیری از انواع دیگر که یک مسئله پیاده سازی است) و وضوح کد را حفظ کنند. در ادامه گرچه به برخی از ویژگی های Ruby پرداخته ام ولی قصدم آموزش این زبان نیست.

انواع داینامیک:

همان طور که قبلا اشاره کردم در Ruby نوع(Type) متغیر ها داینامیک هستند و در زمان اجرا مشخص می شوند(و البته داینامیک بودن به معنی weakly typed بودن نیست). این امر باعث می شود نیازی به تعریف نوع متغیر ها و مقدار بازگشتی توابع وجود نداشته باشد. از طرفی در زبان های کامپایلری بسیاری از کد ها صرفا بخاطر توجیه کامپایلر نوشته می شود! وقتی با Ruby کار می کنید کم کم به این نتیجه می رسید که تعداد کلاس هایی که برای تولید یک برنامه باید بنویسید بسیار کمتر از تعداد کلاس های نوشته شده در بسیاری دیگر از زبان ها است. برای مثال بسیاری از Super Class ها و متد هایی که Overload شده در Ruby مورد نیاز نیست. حتی در Ruby چیزی با نام Overload کردن متد وجود ندارد.

یکی دیگر از ساختار هایی که به نظر من برای توجیه کامپایلر ایجاد شده، همان چیزی است که در Java 5 و C# 2 به آن Generics و در C++ به آن Templates می گویند(گرچه این ساختارها در سه زبان ذکر شده تفاوت زیادی با هم دارند ولی هر سه تقریبا به یک منظور در زبان گنجانده شده اند). در زبان های داینامیک (مانند Ruby) اصلا نیازی به چنین ساختاری وجود ندارد.

قبلا به این مسئله اشاره کردم که تصمیم گیری در مورد بسیاری از ویژگی های زبان یک tradeoff را تحمیل می کند و هر مزیتی می تواند عیبی را نیز به همراه داشته باشد. یکی از مشکلات عمده ای که زبان های داینامیک(و از جمله آنها Ruby) دارند این است که چون اطلاعات نوع ها در زمان توسعه نرم افزار موجود نیست، به همین خاطر عموما IDE های این زبان ها نمی توانند به اندازه IDE های زبان های کامپایلری مانند Java و C# به برنامه نویس کمک کنند. البته از آنجایی که IDE های زبان Ruby هنوز به اندازه ابزار های مشابه خود در Java و C# توسعه نیافته و به تکامل نرسیده اند شاید این مقایسه درست نباشد ولی در هر حال حداقل در ابتدای کار دل کندن از IDE های قدرتمندی مثل eclipse و intellij برای یک برنامه نویس جاوا و Visual Studio.NET برای کسانی که تحت پلت فرم .NET کار می کنند سخت است.

انواع داده توکار:

Ruby دارای انواع داده توکار (build in) زیر است:

· String: مانند بسیاری دیگر از زبان ها، رشته ها در Ruby جزء انواع توکار هستند. ولی رشته ها در Ruby نسبت به بسیاری دیگر از زبان ها از قدرت بیشتری برخوردار هستند. برای مثال رشته هایی که داخل double quotation قرار می گیرند، می توانند شامل متغیر ها و یا عبارات نیز باشند(همانند Perl)

a = 10

puts "#{a} plus one is #{a + 1}"

#10 plus one is 11

· Fixnum, Float: بیانگر اعداد اعشاری و صحیح هستند. نکته جالب در مورد اعداد در Ruby این است که در حالت عادی اعداد به اندازه word کامپیوتری هستند که برنامه روی آن اجرا می شود ولی اگر اندازه اعداد از اندازه word کامپیوتر بزرگتر شود(overflowRuby بطور خودکار اندازه اعداد را بزرگ کرده و محاسبات لازم را نیز خود انجام می دهد. به همین خاطر هیچ وقت در Ruby سرریز محاسباتی رخ نمی دهد.

· Range: Ruby نوع داده توکاری دارد که در دیگر زبان ها خیلی متداول نیست. 1..10 دنباله اعداد 1 تا 10 را نشان می دهد و 'a'..'c' دنباله ای از کاراکترهای a تا c است. Range ها نیز مانند اعداد در Ruby شیء هستند. قطعه کد زیر فاکتوریل عدد 50 را تولید می کند. دقت کنید که عدد تولید شده بزرگ تر از آن است که در word کامپیوتر ذخیره شود.

n = 50

fact = 1

(2..n).each {|i| fact = fact * i}

puts fact

#30414093201713378043612608166064768844377641568960512000000000000

· آرایه ها: آرایه ها یکی دیگر از انواع داده توکار در Ruby هستند. آرایه های Ruby می توانند انواع مختلفی را در خود جای دهند و در هنگام نیاز بطور خودکار اندازه آنها افزایش پیدا می کند.

a = [1, 2, 0]

a << 3

a = a.sort

a.each{|i| puts i}

#0 1 2 3

· Hash: نوع داده Hash در Ruby مشابه Hashtable یا Dictionary در بسیاری دیگر از زبان ها است. پشتیبانی توکار Ruby از این نوع بسیاری از کارها را آسان کرده است.

map = {'one'=>1, 'two'=>2}

map['three'] = 3

map.each{|key, val| puts "#{key} = #{val}"}

#three = 3

#two = 2

#one = 1

No comments: