یکی از مفاهیم مهم دیگری که به وسیلهی پاسکال مورد تأکید قرار گرفته است, مفهوم روال است, که اساساً متشکل از یک رشته دستورالعمل با نام واحد است که میتوان با استفاده از آن نام آنها را به کرات فراخوانی کرد. به این ترتیب, لازم نیست که دستورالعملهای یکسانی را چندین بار تکرار کنید, و چون فقط یک نسخه از این مجموعه دستورالعملها وجود دارد, میتوانید به آسانی آن را در تمام برنامه تغییر دهید. از این دیدگاه, روالها را ساز و کار اصلی میتوان همبندی (encapsulation) کد دانست. پس از معرفی دستور روالها (syntax) در پاسکال, مثالی در این زمینه ارائه خواهم داد.
پردازهها و توابع در پاسکال
روالها در پاسکال بر دو نوعاند: پردازه (procedure) و تابع (function). از نظر تئوری, پردازه عملی است که از رایانه میخواهید انجام دهد, و تابع محاسبهای است که مقداری برمیگرداند. تفاوت مهم این دو نوع در این است که تابع مقدار برگشتی دارد و پردازه ندارد. هر دو نوع پردازه میتوانند پارامترهای متعدد از انواع مختلف داشته باشند.
اما به طور کلی, اختلاف بین توابع و پردازهها بسیار محدود است: میتوانید تابعی را برای انجام عملی فراخوانید و از مقدار برگشتی آن (که ممکن است رمز خطای اختیاری یا چیزی مانند آن باشد) هیچ استفادهای نکنید و یا اینکه میتوانید پردازهای را فراخوانید که مقدار حاصل را از طریق یکی از پارامترهای خود برمیگرداند (بعداً در این فصل در بارهی پارامترهای اشاره بیشتر صحبت خواهیم کرد). در اینجا تعریف یک پردازه و دو تابع را میبینید. هر دو تابع کار یکسانی را انجام میدهند, اما طرز نوشتن آنها اندکی متفاوت است:
procedure Hello;
begin
ShowMessage ('Hello world!');
end;
function Double (Value: Integer) : Integer;
begin
Double := Value * 2;
end;
// or, as an alternative
function Double2 (Value: Integer) : Integer;
begin
Result := Value * 2;
end;
استفاده از Result به جای نام تابع برای اختصاص مقدار برگشتی تابع اینک بیش از پیش گسترش یافته است, و به نظر من, معمولاً متن را خواناتر میکند.
وقتی این روالها تعریف شدند, میتوانید آنها را یک یا چند بار فراخوانی کنید. وقتی پردازه را فراخوانید, عمل تعریف شده را برای شما انجام میدهد, و تابع مقدار مورد نظر را برمیگرداند:
procedure TForm1.Button1Click (Sender: TObject);
begin
Hello;
end;
procedure TForm1.Button2Click (Sender: TObject);
var
X, Y: Integer;
begin
X := Double (StrToInt (Edit1.Text));
Y := Double (X);
ShowMessage (IntToStr (Y));
end;
توجه: در حال حاضر, نگران دستور (syntax) نوشتن دو پردازهی بالا, که در حقیقت متد هستند, نباشید. کافی است روی یک فرم دلفی دو دکمه قرار دهید, و در زمان طراحی, روی آنها دوکلیک کنید تا محیط دلفی کد پشتیبان لازم را برای شما آماده کند. اینک کافی است سطر بین begin و end پر کنید. برای تدوین کد بالا باید یک کنترل ادیت (Edit) هم به فرم اضافه کنید.
این برمیگردیم به مفهوم همبندی کد که قبلاً گفتم. وقتی تابع Double را را فراخوانی میکنید, لازم نیست که دقیقاً آلگوریتم پیادهسازی (implementation) آن را بدانید. اگر بعداً راه بهتری برای دو برابر کردن اعداد پیدا کنید, میتوانید کد تابع را عوض کنید, ولی کد فراخوانی تابع تغییری نمیکند (گرچه اجرای آن سریعتر خواهد بود!). برای پردازهی Hello هم همین اصل مصداق دارد: میتوانیم با تغییر دادن کد این پردازه, خروجی برنامه را تغییر دهیم, و اثر متد Button2Click نیز خودبخود متفاوت خواهد شد. مثلاً میتوانیم کد را به صورت زیر تغییر دهیم:
procedure Hello;
begin
MessageDlg ('Hello world!', mtInformation, [mbOK]);
end;
نکته: وقتی یک از توابع یا پردازههای دلفی, و یا هرگونه متد VCL را فراخوانی میکنید, باید تعداد و نوع پارامترها را به خاطر داشته باشید. به محض اینکه نام متد و پرانتز باز را نوشتید, ویرایشگر دلفی با باز کردن یک راهنمای کنارپر (fly-by hint) لیست پارامترهای تابع یا پردازه را نشان میدهد. این ویژگی را پارامترهای کد (Code Parameters) میگویند, و بخشی از فناوری بینش کد (Code Insight) است.
پارامتر های اشاره
در روالهای پاسکال, امکان پارامتردهی به مقدار و به اشاره وجود دارد. روش پیشفرض, پارامتردهی به مقدار است: مقدار مورد نظر روی پشته کپی میشود, و روال از کپی مقدار استفاده میکند, نه اصل مقدار.
پارامتردهی به اشاره به معنای آن است که مقدار پارامتر به روی پشته کپی نمیشود (احتراز از کپی معمولاً به معنای اجرای سریعتر برنامه است). در عوض, برنامه حتی در درون کد روال, به اصل مقدار اشاره میکند. این کار به پردازه یا تابع امکان میدهد که مقدار پارامتر را تغییر دهند. پارامتردهی با اشاره با کلیدواژهی var مشخص میشود.
این فن در اکثر زبانهای برنامهنویسی وجود دارد. گرچه C فاقد این روش است, ولی در C++ با نماد & (پارامتردهی به اشاره) میتوان از این روش بهره جست. در Visual Basic هر پارامتری که به عنوان ByVal مشخص نشده باشد, به اشاره پارامتردهی میشود.
در مثال زیر با استفاده از کلیدواژهی var پارامتردهی به اشاره صورت گرفته است:
procedure DoubleTheValue (var Value: Integer);
begin
Value := Value * 2;
end;
در این حالت, از پارامتر هم برای دادن یک مقدار به پردازه و هم برای برگرداندن یک مقدار جدید به کد فراخواننده استفاده شده است. وقتی مینویسید:
var
X: Integer;
begin
X := 10;
DoubleTheValue (X);
مقدار متغیر X برابر با 20 میشود, زیرا تابع از یک اشاره به محل اصلی X استفاده میکند, و بر مقدار اولیهی آن تأثیر میگذارد.
پارامتردهی به اشاره برای نوعهای ترتیبی, رشتههای نوع قدیمی, و رکوردهای بزرگ مفهوم پیدا میکند. در واقع, شیءهای دلفی همواره به مقدار پارامتردهی میشوند, زیرا خودشان اشارهاند. بنا بر این، پارامتردهی یک شیء به اشاره چندان معنایی ندارد (غیر از موارد خیلی خاص), زیرا به معنای پارامتردهی "یک اشاره با یک اشاره" است.
رفتار رشتههای دراز دلفی اندکی متفاوت است: اینها مانند اشاره رفتار میکنند, ولی اگر از چند متغیر رشتهای که به رشتهی واحدی در حافظه اشاره میکنند, مقدار یک متغیر را تغییر دهید, قبل از تغییر دادن, آن متغیر از مقدار رشته کپیبرداری میکند. وقتی یک رشتهی دراز به عنوان پارامتر داده میشود, این پارامتر تنها از نظر مصرف حافظه و سرعت عمل مانند اشارهها رفتار میکند.
در دلفی 3, نوع پارامتر جدیدی به نام خروجی (out) معرفی شد. پارامترهای خروجی هیچگونه مقدار اولیه ندارند, و تنها برای برگرداندن یک مقدار مورد استفاده قرار میگیرند. این پارامترها را فقط باید برای پردازهها و توابع COM استفاده کرد؛ به طور کلی, بهتر است از پارامترهای var که کارآیی بیشتری دارند, استفاده به عمل آید. جز از نظر نداشتن مقدار اولیه, پارامترهای out درست مانند پارامترهای var رفتار میکنند.
پارامتر های ثابت
به جای پارامترهای اشاره, میتوانید از پارامترهای const استفاده کنید. از آنجا که در درون روال نمیتوان به پارامتر ثابت مقدار جدیدی اختصاص داد, لذا تدوینگر میتواند پارامتردهی را بهینهسازی کند. تدوینگر ممکن است روشی مانند پارامتردهی به اشاره اتخاذ کند (یا اشارهی ثابت به اصطلاح زبان C++), ولی رفتار آن در هر حال مانند پارامتردهی به مقدار خواهد بود, زیرا روال مقدار اولیه را تغییر نخواهد داد.