Logo

ماركو كانتو:
أساسي باسكال

الفصل 3
الأنواع، المتغيرات، والثوابت

اعتمدت لغة باسكال الأصلية عل بعض المفاهيم البسيطة، والتي اصبحت الآن عامة في لغات البرمجة. المفهوم الأول هو نوع البيانات data type. النوع يحدد القيم التي يمكن للمتغيرات ان تتخذها، والعمليات التي يمكن انجازها عليها. ان مفهوم النوع أقوى في باسكال مقارنة بلغة س، حيث انواع البيانات الحسابية غالبا ما تكون متبدلة، وهي أقوى بكثير من النسخ الأصلية للغة بيسك، حيث لاتملك مثل هذا المفهوم.

المتغيرات

تتطلّب باسكال ان تكون كل المتغيرات معرّفة قبل استخدامها. وحتى في الوقت الذي تعرّف فيه المتغير، يجب أن تحدّد نوع البيانات. ها هنا بعض نماذج تعريف المتغيرات:

var
  Value: Integer;
  IsCorrect: Boolean;
  A, B: Char;

المصطلح var يمكن استخدامه في اماكن مختلفة في الكود، كأن يكون في بداية توليف وظيفة أو اجراء، او ان يتم تعريف المتغيرات محليا local في الروتين ، أو داخل الوحدة لتعريف متغيرات جامعة global. بعد مصطلح var تأتي قائمة اسماء المتغيرات، متبوعة بشارحة واسم نوع البيانات. يمكنك كتابة اكثر من اسم متغير واحد في السطر الواحد، كما هو في آخر تعليمة أعلاه.

حالما تقوم بتحديد متغير من نوع ما، تستطيع ان تقوم فقط بمباشرة العمليات الداعمة لنوع بياناته. على سبيل المثال، يمكنك استعمال القيمة البولية للاختبار و القيمة الصحيحة في التعبير الرقمي. لايمكنك مزج القيم البولية والصحيحة (كما هو الأمر مع لغة س).

باستخدام تخصيصات بسيطة، نستطيع كتابة التوليف التالي:

Value := 10;
IsCorrect := True;

لكن التعليمة التالية ليست صحيحة، لأن المتغيرين يملكان نوع بيانات مختلف:

Value := IsCorrect; // error

اذا حاولت تحويل هذا التوليف، فان دلفي تقوم باصدار خطأ تحويل رفق هذا التوضيح: Incompatible types: 'Integer' and 'Boolean'. عادة، مثل هذه الأخطاء هي أخطاء برمجية، لأنه لامعنى لتخصيص قيمة True أو False لقيم من نوع بيانات صحيح. يجب أن لا تلوم دلفي على مثل هذه الأخطاء. هي فقط تنبهك لوجود خطأ ما في التوليف.

بالطبع، غالبا مايمكن تبديل قيمة متغير من نوع بيانات الى نوع مختلف. في بعض الحالات، هذا التبديل يكون آليا، لكن عادة ما تحتاج الى استدعاء وظائف محددة في النظام لتغيير التمثيل الداخلي للبيانات.

تستطيع في دلفي ان تخصص قيمة تمهيدية لمتغير جامع global variable أثناء تعريفك له. مثلا، تستطيع كتابة:

var
  Value: Integer = 10;
  Correct: Boolean = True;

تقنية التمهيد initialization هذه تصلح فقط للمتغيرات الجامعة، وليس للمتغيرات المعرفة داخل نطاق اجراء أو مسار.

الثوابت

تسمح باسكال ايضا بتعريف ثوابتا constants لتسمية القيم التي لاتتغير خلال عمل البرنامج. لتعريف ثابت لاتحتاج لتحديد نوع البيانات، فقط تخصيص قيمة ابتدائية. المحوّل سيتفحّص القيمة وآليا يستخدم نوع بياناته المناسب. ها هنا بعض امثلة التعريفات:

const
  Thousand = 1000;
  Pi = 3.14;
  AuthorName = 'Marco Cantù';

يقرر دلفي نوع البانات للثابت بناء على قيمته. في المثال أعلاه، الثابت Thousand يفترض ان يكون من نوع صحيح صغير SmallInt ، اصغر نوع صحيح يمكنه احتواء القيمة. اذا اردت الطلب من دلفي استخدام نوع محدد؛ يمكنك ببساطة اضافة اسم النوع في التعريف، كما هو في:

const
  Thousand: Integer = 1000;

عندما تقوم بتعريف ثابت، يستطيع المحوّل أن يختار بين أن يخصص موقعا في الذاكرة للثابت، و يحفظ فيه قيمته، أو أن ينسخ قيمته الحقيقية في كلّ مرة يتم فيها استعمال الثابت. الأسلوب الثاني يبدو معقولا خاصة بالنسبة للثوابت البسيطة.

ملاحظة: نسخ 16-بت من دلفي تسمح لك بتغيير قيمة الثابت محدد النةع في زمن التشغيل، كما لو كان متغيرا. نسخة 32-بت لازالت تسمح بهذا السلوك من اجل التوافقية مع السابق وذلك عندما تقوم بتمكين موجّه المحوّل $J ، او بالتعليم على مؤشر Assignable typed constants في صفحة المحوّل في نافذة خيارات المشروع Project Options . وبالرغم من أن هذا هو التوصيف الافتراضي، فانه ينصح بقوة كفنيّات البرمجة أن لاتستعمل هذه الخدعة. ان تخصيص قيمة جديدة لثابت يمنع كل تشذيبات المحول على الثواب. واذا اضطررت لهذا، ببساطة قم بتعريف متغيرات، كبديل.

ثوابت الجمل الموردية

عندما تحدد ثابت جملة، فبدلا من كتابة:

const
  AuthorName = 'Marco Cantù';

يمكنك بدءاً من دلفي 3 أن تكتب التالي:

resourcestring
  AuthorName = 'Marco Cantù';

في كلتا الحالتين انت تحدد ثابتا؛ قيمة لاتقم بتغييرها خلال زمن التشغيل. الفرق فقط في كيفية الانجاز. ثابت الجملة المحدد بواسطة الموجّه resourcestring يخزّن ضمن موارد البرنامج resources، في جدول للجمل.

لكي ترى هذه الامكانية فعليا، قم بالاطلاع على مثال ResStr ، والذي له زرّا رفق التوليف التالي:

resourcestring
  AuthorName = 'Marco Cantù';
  BookName = 'Essential Pascal';

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage (BookName + #13 + AuthorName);
end;

ناتج الجملتين يظهر في سطرين منفصلين لأن الجملتين مفصولتين بالحرف الدّال لسطر جديد newline (مشار اليه بقيمته الرقمية في #13 وهو ثابت نوع حرف).

الجانب المثير في هذا البرنامج هو انك اذا تفحصّته بمستكشف للموارد resource explorer (هناك واحد متوفر في الأمثلة التي تأتي مع دلفي) سوف ترى الجمل الجديدة ضمن الموارد. هذا يعني بأن الجمل ليست جزءا من التوليف المحول ولكنها خزّنت في منطقة منفصلة في الملف التنفيذي (ملف EXE).

ملاحظة: باختصار، مزايا الموارد هي في الكفاءة في مناولة الذاكرة التي تقوم بها ويندوز، وفي امكانية توطين localizingالبرنامج (ترجمة الجمل الى لغات مختلفة) بدون الحاجة الى تعديل توليفها المصدري source code.

أنواع البيانات

في باسكال توجد عدة انواع بيانات سابقة التحديد predefined data types ، والتي يمكن تقسيمها الى ثلاث مجموعات: الانواع التراتبية ordinal types، الأنواع الحقيقية real types و الجمل strings. سوف نناقش الانواع التراتبية في الأقسام التالية، بينما يتم تغطية الجمل لاحقا في هذا الفصل. في هذا القسم سوف أقدم ايضا بعض الأنواع المحددة من قبل مكتبات دلفي (ليست محددة من قبل المحوّل)، والتي يمكن اعتبارها انواع سابقة التحديد predefined types.

تتضمن دلفي ايضا نوع بيانات بدون نوع non-typed ، تسمّى متباين variant ، سيتم مناقشتها في الفصل العاشر من هذا الكتاب. غريب جدا ان يكون المتباين نوعا بدون مايناسبه من تحقق من النوع. لقد تم ادخال هذا النوع في دلفي 2 لمناولة آليات او ال اي OLE Automation.

الأنواع التراتبية

الأنواع التراتبية Ordinal types مبنية على مفهم الترتيب أو التوالي و التتابع. ليس بامكانك فقط مقارنة قيمتين لمعرفة أيهما الأكبر، ولكن يمكنك أيضا معرفة القيمة التي تلي او تسبق قيمة أخرى، أو تقوم بحساب أدني أو أعلى قيمة محتملة.

أكثر ثلاث أنواع تراتبية سابقة التحديد هي الصحيح Integer، البولي Boolean، و الحرف Char. عموما، هناك عددا من الأنواع الأخرى ذات العلاقة والتي لها معنى مشابها ولكن لها تمثيلا ومدى قيم مختلفين. جدول 3.1 التالي يعرض انواع البيانات التراتبية المستخدمة لتمثيل الأرقام.

جدول 3.1: أنواع البيانات التراتبية للأرقام

Size الحجم Signed معلّم
Range المدى
Unsigned غير معلّم
Range المدى
8 bits ShortInt
-128 to 127
Byte
0 to 255
16 bits SmallInt
-32768 to 32767
Word
0 to 65,535
32 bits LongInt
-2,147,483,648 to 2,147,483,647
LongWord (بدءاً من دلفي 4)
0 to 4,294,967,295
64 bits Int64
16/32 bits Integer Cardinal

كما ترى، هذه الأنواع لها علاقة بالتمثيلات المختلفة للأرقام، حسب عدد الجزئيات bits المستخدمة للتعبير عن القيمة، وحسب وجود أو غياب جزئية العلامة. القيم المعلّمة signed values يمكنها أن تكون موجبة أو سالبة، لكن لها مدى أصغر من القيم، وذلك لأن المتاح من الجزئيات للقيمة نفسها قد نقصت بواحدة. تستطيع أن ترجع الى مثال المدى الذي سيناقش في القسم التالي، من أجل معرفة المدى الفعلي لقيم كل نوع.

المجموعة الأخيرة (والمشارة ب 16/32) تشير الى القيم التي لها تمثيلا مختلفا في نسخ 16-بت و 32-بت من دلفي. الصحيح Integer و الرئيسي Cardinal يستعملان بكثرة، لأنهما يطابقان التمثيل الفطري للأرقام في المعالج الحسابي CPU.

الأنواع الصحيحة في دلفي 4

في دلفي 3، الأرقام ذات 32 بت غير المعّلمة والمشار اليها بنوع رئيسي cardinal كانت سابقا قيم 31 بت، بمدي يبلغ حتى 2 قيقابايت. قدمت دلفي 4 نوع جديد رقمي غير معلّم، LongWord ، والذي يستخدم فعليا قيمة 32 بت تبلغ حتى 4 قيقابايت. وأصبح نوع كاردينال الآن اسما مرادفا لنوع لونغوورد الجديد. لونغوورد يسمح ب 2GB اكثر اضافية من البيانات يمكن عنونتها من قبل رقم غير معّلم، كما أشير اليه سابقا. أكثر من هذا، فإنه يماشي التمثيل الفطري للأرقام في المعالج الحسابي.

نوع آخر جديد تم ادخاله في دلفي 4 و نوع int64 ، والذي يمثل أعدادا صحيحة تبلغ 18 رقم. هذا النوع الجديد مدعوم بالكامل من قبل بعض اجرائيات routines الأنواع التراتبية (مثل High و Low)، والإجرائيات الرقمية (مثل Inc و Dec)، وإجرائيات تبديل الجمل string-conversion (مثل IntToStr). ومن أجل التبديل العكسي، من جملة ألى رقم، هناك وظيفتين جديدتين: StrToInt64 و StrToInt64Def.

البولي

القيم البولية غير النوع البولي نادرة الاستعمال. بعض القيم البولية لديها تمثيل خاص وذلك لمتطلبات وظائف ويندوز Windows API functions. الأنواع هي ByteBool، WordBoolو LongBool.

في دلفي 3 ومن أجل التوافق مع فيجوال بيسك و آليات OLE، فان انواع البيانات ByteBool، WordBool، و LongBool تم تعديلهم لتمثيل القيم True بـ -1، بينما القيمة False لازالت 0. نوع البيانات Boolean ظلّت كما هي (True هي 1، , False هي 0). إذا قمت باستعمال سبك نوع typecast صريح في برنامج بدلفي 2، فإن نقل البرنامج الى نُسخ لاحقة من دلفي قد ينتج عنه بعض الأخطاء.

الأحرف

أخيرا هناك تمثيلين مختلفين للأحرف: ANSIChar و WideChar. النوع الأول يمثل أحرفا ذات جزئيات ثمان 8-bit، تتماشى مع مجموعة أحرف انسي ANSI والمستخدمة تقليديا من قبل ويندوز؛ التمثيل الثاني الأحرف 16-جزئية ، وتتماشى مع أحرف يونيكود الجديدة Unicode والمدعومة بالكامل من قبل ويندوز ن ت، وجزئيا من قبل ويندوز 95 و 98. معظم الوقت سوف تستعمل ببساطة نوع حرف Char ، والذي في دلفي 3 تطابق ANSIChar. ليكن معلوما، على أي حال، ان أول 256 من حروف يونيكود توافق تماما حروف انسي ANSI.

أحرف الثوابت يمكن تمثيلها بمجموعة رموزها، كما في 'k'، او بمجموعة أرقامها، كما في #78. الأخيرة يمكن التعبير عنها ايضا ياستخدام الوظيفية Chr ، كما في Chr (78). التبديل المعاكس يمكن اجراؤه بواسطة الوظيفة Ord.

بصفة عامة يكون من الأحسن استخدام مجموعة الرموز عند الإشارة الى الأحرف، والأرقام، والعلامات. عند الإشارة الى أحرف خاصة، ستستخدم مجموعة الأرقام عموما بدلا من ذلك. القائمة التالية تتضمن بعض أكثر الأحرف الخاصة استعمالا:

مثال Range

لإعطائك فكرة عن الاختلاف من مدى لآخر في بعض الأنواع التراتبية، قمت بكتابة برنامج دلفي بسيط أسميته Range. بعض النتائج تظهر في الشكل 3.1.

الشكل 3.1: مثال Range يظهر بعض المعلومات حول انواع البيانات التراتبية (الأرقام الصحيحة في هذه الحالة).

برنامج Range مبني على نموذج form بسيط، به ستة أزرار buttons (كلّ مسمّاة حسب نوع البيانات التراتبية) وبعض الملصقات labels لمختلف المعلومات، كما هو مبيّن في الصورة 3.1. أستخدمت بعض الملصقات لتحوي نصّا ثابتا، الأخرى لعرض المعلومات عن النوع في كلّ مرّة يُضغط فيها على زرّ.

في كلّ مرّة تضغط فيها على الأزرار، يقوم البرنامج بتحديث الملصقات بحسب الناتج. ملصقات مختلفة تعرض نوع البيانات، عدد البايت المستعملة، و أقصى وأدني قيمة يمكن للنوع أن يخزّنها. كل زرّ يملك مايخصّه من مسار method تجاوب الحدث OnClick لأن التوليف المستخدم لحساب القيم الثلاث يختلف قليلا من زرّ لآخر. مثلا، هاهنا التوليف المصدري لحدث OnClick للزرّ الخاص بنوع الصحيح (BtInteger):

procedure TFormRange.BtnIntegerClick(Sender: TObject);
begin
  LabelType.Caption := 'Integer';
  LabelSize.Caption := IntToStr (SizeOf (Integer));
  LabelMax.Caption := IntToStr (High (Integer));
  LabelMin.Caption := IntToStr (Low (Integer));
end;

إذا كنت تملك بعض الخبرة في البرمجة بدلفي، يمكنك تفحّص التوليف لفهم كيفية عمله. بالنسبة للمبتدئين، يكفي ملاحظة الإستخدام للوظائف الثلاثة: SizeOf وHigh و Low. نواتج الوظيفتين الأخيرتين هما تراتبيات من نفس النوع (في هذا الحالة، أعداد صحيحة)، وناتج وظيفة SizeOf هي دائما عدد صحيح. القيمة المرتجعة من هذه الوظائف الثلاث تترجم أولا إلى جُمل بإستخدام وظيفة IntToStr، ثم تُنسخ في لافتات captions الملصقات الثلاث.

المسارات المرتبطة بالأزرار الأخرى تشبه كثيرا المسار المذكور أعلاه. الإختلاف الفعلي الوحيد هو نوع البيانات الذي تم تمريره كمحدد لمختلف الوظائف. الصورة 3.2 تعرض ناتج تنفيذ البرنامج تحت ويندوز 95 بعد أن تم إعادة تحويله recompile بواسطة نسخة 16-بت من دلفي. بمقارنة الشكل 3.1 و الشكل 3.2، يمكنك رؤية الإختلاف بين نوع البيانات الصحيح ذو 16-بت وذلك ذو 32-بت.

الشكل 3.2: ناتج نسخة 16-بت من مثال Range، يعرض مرّة أخرى معلومات عن العدد الصحيح.

حجم نوع الصحيح Integer يتباين بحسب المعالج الحسابي ونظام التشغيل المستخدم. في ويندوز 16-بت، المتغير الصحيح يسع 2 بايت. بينما في ويندوز 32، سعة الصحيح 4 بايت. لهذا السبب، عندما تعيد تحويل مثال Range، ستحصل على نتائج مختلفة.

التمثيلين المختلفين لنوع الصحيح ليست بمشكلة، طالما أن برنامجك لايضع أية إفتراضات عن حجم الصحيح. إذا ما حدث وقمت بحفظ عدد صحيح في ملف بإستخدام نسخة ثم حاولت استرجاعه بنسخة أخرى، فسوف تواجه بعض المتاعب. في هذه الحالة، يجب أن تختار نوع بيانات مستقل عن بيئة التشغيل (مثل LongInt أو SmallInt). لأغراض الحسابات الرياضية أو توليف عام، أفضل مراهنة لديك هو أن تلتزم تمثيل الصحيح النمطي لبيئة التشغيل المعينة-- هذا يعني، ان تستخدم نوع الصحيح-- لأنه المفضّل لدى المعالج الحسابي. نوع الصحيح Integer يجب أن يكون خيارك الأول عندما تعالج أعدادا صحيحة. و لا تستخدم تمثيلا مختلفا إلا إذا وجدت سببا قاهرا لذلك.

إجرائات الأنواع التراتبية

بعض إجرائيات النظام system (إجرائيات محددة في لغة باسكال وفي وحدة النظام في دلفي system unit)يمكنها تتعامل مع الأنواع التراتبية ordinal types. هي معروضة في الجدول 3.2. المبرمجون بلغة س++ سوف يلاحظون بأن النسختين من إجرائية Inc، مع محدد أو اثنين، يطابقان معاملات ++ و += (نفس الأمر مع إجرائية Dec).

الجدول 3.2: إجرائيات نظام للأنواع التراتبية

الإجرائية الغرض
Dec تخفيض decrease المتغير الذي يتم تمريره كمحدد، بمقدار واحد أو بمقدار قيمة المحددالثاني الاختياري.
Incزيادة increase المتغير الذي يتم تمريره كمحدد، بمقدار واحد أو بمقدار القيمة المعطاة.
Oddيرجع اثبات إذا كانت القيمة المعطاة عددا فرديا odd.
Pred يرجع القيمة التي تسبق تلك المعطاة بحسب الترتيب المقرر في نوع البيانات، السابق predecessor.
Succيرجع القيمة التي تلي تلك المعطاة، التالي successor.
Ord يرجع رقما يدل على ترتيب order القيمة المعطاة ضمن مجموعة القيم في نوع البيانات.
Low يرجع أدنى low قيمة ضمن مدى النوع التراتبي المعطى كمحدد.
High يرجع أعلى high قيمة ضمن مدى نوع البيانات التراتبي.

لاحظ ان بعض هذه الإجرائيات، عندما يتم تطبيقها على الثوابت constants، فإن المحوّل يقوم بتقييمها آليا واستبدالها بقيمتها. مثلا اذا قمت باستدعاء High(X) حيث X معرّفة كصحيح، فالمحوّل يستطيع ببساطة تبديل التعبير بآخر يمثل أعلى قيمة محتملة لنوع بيانات الصحيح.

الأنواع الحقيقية

تقوم الأنواع الحقيقية بتمثيل أرقام النقطة العائمة بعدة أشكال. أصغر حجم تخزين تمثلها الأرقام الوحيدة Single ، والتي تنفذ بقيمة ذات 4-بايت. ثم هناك الأرقام النقطة العائمة المضاعفة Double، المنفذة بعدد 8 بايت، والأرقام الممتدّة Extended ، والمنجزة بعدد 10 بايت. كل هذه أنواع بيانات نقطة عائمة مع اختلاف في الضبط والدقة precision.

في دلفي 2 ودلفي 3 نوع الحقيقي Real له نفس التعريف الذي في نسخة 16-بت؛ لقد كانت بنوع 48-بت. لكن تم تخفيض استخدامه من قبل بورلاند، والتي اقترحت بأن تقوم باستعمال أنواع الوحيد والمضاعف والممتد بدلا منه. سبب اقتراحهم هذا هو ان الشكل القديم ذو 6-بايت ليس مدعوما من قبل معالجات انتل Intl كما انه ليس معروضا ضمن القائمة الرسمية للأنواع الحقيقية والتي اصدرتها IEEE. ولكي يتم تلافي المشكلة تماما، قامت دلفي 4 بتعديل التعريف الخاص بنوع الحقيقي حتى يمثل الشكل القياسي لرقم عائم النقطة ذو 8 بايت (64-بت).

بالإضافة إلى ميزة استخدام تعريفا قياسيا متفق عليه، هذا التغيير يسمح للمكونات components باصدار سمات properties مبنية عل نوع حقيقي، الشيء الذي لم يكن دلفي 3 يسمح به. أما العيوب فقد تبرز مشاكل التوافقية. في حالة الضرورة، وعند الاصرار على طريقة دلفي 2 و 3 في تعريف النوع، يمكنك تجاوز احتمال انعدام التوافقية؛ وذلك باستخدام خيار المجمّع التالي:

{$REALCOMPATIBILITY ON}

هناك أيضا نوعان غريبان من أنواع البيانات: Comp ويصف رقم صحيح كبير جدا باستخدام 8 بايت (والذي يمكنه احتواء ارقام ذات 18 خانة عشرية)؛ و Currency عملة (ليست متوفرة في دلفي 16-بت) وهي تشير الى قيمة بنقطة عشرية ثابتة مع اربع خانات عشرية، و بنفس تمثيل 64-بت كما في نوع Comp. كما يوحي الإسم، نوع بيانات عملة Currency أضيف لمناولة القيم النقدية شديدة الدقة، مع أربع خانات عشرية.

لا نستطيع بناء برنامج يشبه مثال Range بتطبيق انواع بيانات حقيقية، لأننا لايمكننا استخدام وظائف High و Low أو Ord مع متغيرات نوع حقيقي. الأنواع الحقيقية تمثل (نظريا) مجموعة لانهائية من الأرقام، بينما الأنواع التراتبية تمثل مجموعة ثابتة من القيم.

ملاحظة: دعوني أشرح ذلك بطريقة أفضل. عندما يكون لديك الرقم الصحيح 23، يمكنك أن تقرّر ماهي القيمة التي تليه. الأرقام الصحيحة نهائية (لديها مدى محدد ولديها ترتيب). الأرقام عائمة النقطة هي غير نهائية حتى ضمن المدى القصير، وليس لديها ترتيب: في الواقع، كم توجد قيمة بين 23 و 24 ؟ و ما هو الرقم الذي يلي 23.46 ؟ هل هو 23.47، 23.461، أو 34.4601 ؟ هذا الأمر يصعب معرفته بالفعل.

لهذا السب، يبدو الأمر معقولا حين نسأل عن ترتيب موضع حرف w ضمن مدى نوع بيانات حرف char، و لكن ليس من المعقول ابدا أن نسأل نفس السؤال عن الرقم 7143.1562 ضمن مدى نوع بيانات النقطة العائمة. بالرغم انه بالتأكيد تستطيع معرفة ما إذا كان ;رقم حقيقي ما لديه قيمه أعلى من قيمة رقم آخر، فإنه من غير المنطقي أن نسأل عن عدد الأرقام الحقيقية الموجودة قبل رقم ما (هذا معني وظيفة Ord).

الأنواع الحقيقية لديها دورا محدودا في ذلك الجزء من التوليف البرمجي الخاص بواجهة المستخدم user interface (الجانب الخاص بويندوز)، لكنها مدعومة بالكامل من قبل دلفي، بما في ذلك جانب قواعد البيانات. ان دعم مواصفات IEEE القياسية لأنواع النقطة العائمة تجعل من لغة اوبجكت باسكال مناسبة تماما لنطاق واسع من البرامج التي تتطلب حسابات رقمية. إذا كنت مهتما بهذا الجانب، يمكنك إلقاء نظرة على الوظائف الرياضية المقدمة من دلفي وذلك في ملف وحدة system (انظر Delphi Help من أجل تفاصيل أكثر).

ملاحظة: لدلفي ايضا ملف وحدة Math التي تحدد إجرائيات رياضية أكثر تقدما، تغطي وظائف حساب المثلثات (مثل وظيفة ArcCosh)، مالية (مثل وظيفة InterestPayment)، و إحصائية (مثل إجرائية MeanAndStdDev). هناك العديد من هذه الإجرائيات، بعضها تبدو غريبة بالفعل بالنسبة لي، مثل إجرائية MomentSkewKurtosis (سأدع هذا الأمر لك لمعرفته) .

التاريخ والوقت

تستخدم دلفي أيضا أنواعا حقيقية real types لمناولة معلومات التاريخ والوقت. وليكون الأمر أكثر دقّة حدّدت دلفي نوع بيانات TDateTime. وهو نوع نقطة عائمة، لأن النوع يجب أن يكون واسعا بما يكفي لإحتواء السنوات، الأشهر، الأيام، الساعات، الدقائق، والثواني، نزولا إلى دقة تبلغ جزء من ألف من الثانية، كلّ ذلك في متغير واحد. التواريخ تخزّن كإجمالي عدد الأيام منذ 12/30/1899 (مع قيم سالبة تشير إلى التواريخ ما قبل 1899) في الجزء الصحيح integer من قيمة TDateTime.

نوع TDateTime ليس نوعا مسبق التحديد بحيث يفهمه المحوّل، لكن قد تمّ تعريفه في ملف وحدة system كالتالي:

type
  TDateTime = type Double;

إستخدام TDateTime يعدّ بسيط، لأن دلفي تحوي عددا من الوظائف التي تتعامل مع هذا النوع. يمكنك أن تجد قائمة بهذه الوظائف في الجول 3.3.

الجدول 3.3: إجرائيات نظام لنوع TDateTime

الإجرائيةالبيان
Nowاسترجاع التاريخ والوقت الحالي في قيمة على هيئة TDateTime.
Date استرجاع فقط التاريخ الحالي.
Time استرجاع فقط الوقت الحالي.
DateTimeToStrتحويل قيمة التاريخ والوقت الى جملة، باستخدام المعلومات المبدئية؛ من أجل تحكم أكثر في التحويل استخدم وظيفة FormatDateTime.
DateTimeToStringنسخ قيم التاريخ والوقت في حيّز جملة string buffer وفق المعلومات الابتدائية.
DateToStrتحويل جانب التاريخ في قيمة TDateTime الى جملة.
TimeToStr تحويل جانب الوقت في قيمة TDateTime الى جملة.
FormatDateTimeصياغة التاريخ والوقت باستخدام صيغة محدّدة، تستطيع ان تحدد أية قيمة تريد عرضها وأية صيغة تستعمل، منتجة صياغة غنية للجملة.
StrToDateTimeتحوبل جملة تحوي معلومات التاريخ والوقت الى قيمة TdateTime، مظهرة رفضا exception في حالة وجود خطأ في صيغة الجملة.
StrToDateتحويل جملة تحوي قيمة تاريخ الى صيغة TDateTime.
StrToTimeتحويل جملة تحوي قيمة وقت الى صيغة TDateTime.
DayOfWeekيسترجع رقم ترتيب اليوم في الأسبوع حسب قيمة TDateTime المعطاة.
DecodeDateاسترجاع قيم السنة، الشهر، و اليوم من قيمة تاريخ.
DecodeTimeاسترجاع قيمة الوقت.
EncodeDateتحويل قيم السنة، الشهر، و اليوم إلى قيمة TDateTime.
EncodeTimeتحويل قيم الساعة، الدقيقة، الثانية، وأجزاء الثانية إلى قيمة TDateTime.

من أجل أن ترى كيف يتم استعمال نوع البيانات هذا و بعض الإجرائيات الخاصة به، قمت ببناء برنامج بسيط، أسميته TimeNow. النموذج الرئيسي في هذا المثال به زرّ Button و قائمة ListBox. عندما يبدأ البرنامج يقوم آليا بحساب وعرض الوقت والتاريخ الحالي. في كلّ مرّة يتم فيها الضغط على الزرّ، يقوم البرنامج بعرض الزمن المنقضي منذ بدء البرنامج.

فيما يلي التوليف الموصول بحدث OnCreate الخاص بالنموذج:

procedure TFormTimeNow.FormCreate(Sender: TObject);
begin
  StartTime := Now;
  ListBox1.Items.Add (TimeToStr (StartTime));
  ListBox1.Items.Add (DateToStr (StartTime));
  ListBox1.Items.Add ('Press button for elapsed time');
end;

التعليمة الأولى تنادي وظيفة Now ، التي تسترجع التاريخ و الوقت الحاليين. القيمة المسترجعة تُخزّن في متغيّر StartTime ، والذي تم تعريفه كمتغير خارجي global كالتالي:

var
  FormTimeNow: TFormTimeNow;
  StartTime: TDateTime;

لقد أضفت فقط التعريف الثاني، حيث أن دلفي تقوم بتوفير الأول. حيث يكون مبدئيا كالتالي:

var
  Form1: TForm1;

عند تغير اسم النموذج form، يتم تحديث هذا التصريح آليا. ان استخدام متغيرات جامعة global لا يعدّ حقيقة أفضل الطرق: سيكون من الأفضل لو تم استخدام حقل خاص private field تابع لطبقة النموذج form class، موضوع له علاقة ببرمجة التوجّه الكائني object-oriented programming تم مناقشته في كتاب التحكم بدلفي 4 Mastering Delphi .

التعليمات الثلاث التالية تضيف ثلاثة عناصر الى مكوّن القائمة يمين النموذج، مع النتائج التي تراها في الشكل 3.3. السطر الأول يحتوي على الجزء الخاص بالوقت في قيمة TDateTime محوّلا الى جملة، الثاني يحتوي جزء التاريخ من نفس القيمة. في نهاية التوليف أضيف تذكير بسيط.

الشكل 3.3: ناتج مثال TimeNow عند البدء.

الجملة الثالثة يستبدلها البرنامج عندما يضغط المستعمل على زرّ Elapsed "المنقضى":

procedure TFormTimeNow.ButtonElapsedClick(Sender: TObject);
var
  StopTime: TDateTime;
begin
  StopTime := Now;
  ListBox1.Items [2] :=  FormatDateTime ('hh:nn:ss',
    StopTime - StartTime);
end;

التوليف يسترجع الوقت الجديد ويحسب الفرق بينه وبين قيمة الوقت المخزّن عند ابتداء البرنامج. ولأننا نحتاج الى استخدام القيمة التي سبق حسابها في سياق حدث مختلق، كان علينا أن نخزّنها في متغير جامع. في الواقع توجد بدائل أفضل، مبنية على مفهوم الطبقات classes.

ملاحظة: التوليف الذي يقوم باستبدال القيمة الحالية في الجملة الثالثة يستعمل دليل index 2. السبب في ذلك ان بنود القائمة مبنية على الصفر are zero-based: البند الأول رقمه 0، الثاني رقم 1، و الثالث رقم 3. سنرى المزيد من ذلك عندما نناقش المصفوفات.

بجانب استدعاء DateToStr و TimeToStr يمكنك استعمال وظيفة FormatDateTime الأكثر قوة، كما فعلت في المسار method الأخير أعلاه (انظر ملف مساعدة دلفي من أجل تفاصيل محددات الصياغة). لاحظ أيضا أن قيم الوقت والتاريخ تُبدّلان إلى جُمل بحسب توصيف الدوليّات international في ويندوز. دلفي يقرأ هذه القيم من النظام، و يوزعها في عدد من الثوابت الجامعة global constants المُعرّفة في ملف وحدة SysUtils. نذكر منها:

DateSeparator: Char;
ShortDateFormat: string;
LongDateFormat: string;
TimeSeparator: Char;
TimeAMString: string;
TimePMString: string;
ShortTimeFormat: string;
LongTimeFormat: string;
ShortMonthNames: array [1..12] of string;
LongMonthNames: array [1..12] of string;
ShortDayNames: array [1..7] of string;
LongDayNames: array [1..7] of string;

يوجد المزيد من الثوابت الجامعة تتعلق بالعُملة و صياغة رقم النقطة العائمة. يمكنك الحصول على قائمة كاملة بها من ملف مساعدة دلفي تحت العنوان Currency and date/time formatting variables.

انواع ويندوز الخاصة

أنواع البيانات السابقة التحديد والتي سبق أن استعرضناها حتى الآن هي جزء من لغة باسكال. تتضمن دلفي أنواع بيانات أخري مجددة من قبل ويندوز. أنواع البيانات هذه ليست جزءاً مكمّلا في اللغة، ولكنها جزءا من مكتبات libraries ويندوز. أنواع ويندوز تتضمن أنواع ابتدائية جديدة (مثل DWORD و UINT)، و العديد من التسجيلات records (أو بنيات structues)، و عددا من الأنواع المؤشّرة pointer، وغيرها.

من بين أنواع بيانات ويندوز، فإن النوع الأكثر أهمية تمثله المماسك handles، الفصل 9 يناقش ذلك.

تلبيس النوع و تحويلات النوع

كما رأينا، لا يمكنك تخصيص متغير لآخر من نوع مختلف. إذا أردت ذلك، يوجد خياران. الخيار الأول هو تلبيس النوع typecasting ، والذي يستخدم رمز وظائفي بسيط ، باسم نوع البيانات المطلوب:

var
  N: Integer;
  C: Char;
  B: Boolean;
begin
  N := Integer ('X');
  C := Char (N);
  B := Boolean (0);

يمكنك التلبيس بين أنواع البيانات ذات نفس الحجم. عادة مايكون الأمر مأمونا عند التلبيس بين الأنواع التراتبية، أو بين الأنواع الحقيقية، ولكن يمكنك التلبيس بين أنواع مؤشّرة pointer (وأيضا الكينونات objects) طالما تكون مدركا لما تفعله.

التلبيس، بصفة عامة، عادة برمجية خطيرة، لأنه يسمح لك بالوصول إلى قيمة كما لو أنها ممثلة بشكل آخر. و طالما ان التمثيلات الداخلية لأنواع البيانات عموما غير متجانسة، فأنت تخاطر بالتسبب بأخطاء صعبة التتبع. لهذا السبب، يجب عليك عموما تجنب عمليات تلبيس النوع.

الخيار الثاني هو استخدام إجرائيات تحويل النوع. الإجرائيات الخاصة بمختلف أنواع التحويلات تم تلخيصها في الجدول 3.4. بعض هذه الإجرائيات تعمل مع أنواع بيانات سيجري الحديث عنها في الأقسام التالية. لاحظ ان الجدول لا يحوي الإجرائيات الخاصة بالأنواع الخاصة (مثل TDateTime أو المتبياين variant) أو الإجرائيات الموجّه خصّيصا للتشكيل والصياغة formating، مثل الإجرائيات الفعّالة Format و FormatFloat.

جدول 3.4: إجرائيات النظام الخاصة بتحويل البيانات

الإجرائيةالبيان
Chrتحويل ترقم تراتبي الى حرف ANSI.
Ordتحويل قيمة نوع تراتبي إلى رقم يشير إلى ترتيبه.
Roundتحول قيمة نوع حقيقي إلى قيمة نوع صحيح، تقريب القيمة.
Truncتحول قيمة نوع حقيقي إلى قيمة نوع صحيح، تشذيب القيمة.
Intارجاع الجزء الصحيح بقيمة نقطة عائمة.
IntToStrتحويل الرقم إلى جملة.
IntToHexتحويل الرقم إلى جملة بتمثيل ستعشري hexadecimal.
StrToIntتحويل جملة إلى رقم، مع إبداء رفض لو كانت الجملة لا تمثل رقما صحيحا و سليما.
StrToIntDefتحويل جملة إلى رقم، مع استخدام القيمة الإبتدائية إذا كانت غير سليمة.
Valتحويل الجملة إلى رقم (إجرائية قديمة في تربو باسكال، محتفظ بها من أجل التوافقية).
Strتحويل رقم إلى جملة، باستخدام محددات الصياغة إجرائية قديمة في تربو باسكال، محتفظ بها من أجل التوافقية).
StrPasتحويل جملة مقفلة بصفر null-terminated إلى جملة بنسق باسكال Pascal-style. هذا التحويل يتم آليا بالنسبة بالنسبة للجمل نوع AnsiString في دلفي 32-بت. (انظر إلى القسم الخاص بالجمل لاحقا في هذا الفصل.)
StrPCopyنسخ جملة بنسق باسكال إلى جملة مقفلة بصفر. هذا التحويل يتم بتلبيس بسيط لنوع PChar في دلفي 32-بت. (انظر إلى القسم الخاص بالجمل لاحقا في هذا الفصل.)
StrPLCopyينسخ قسما من جملة بنسق باسكال الى جملة مقفلة بصفر.
FloatToDecimalتحويل قيمة نقطة عائمة إلى تسجيلة record تتضمن التمثيل العشري (exponent، أعداد، علامة)
FloatToStrتحويل قيمة نقطة عائمة إلى ما يمثلها كجملة باستخدام الصياغة الافتراضية.
FloatToStrFتحويل قيمة نقطة عائمة إلى ما يمثلها كجملة باستخدام صياغة محددة.
FloatToTextتحويل قيمة نقطة عائمة إلى حيّز جملة string buffer، باستخدام صياغة حددة.
FloatToTextFmtمثل الإجرائية السابقة، تحويل قيمة نقطة عائمة إلى حيّز جملة، باستخدام صياغة مُحددة.
StrToFloatتحويل جملة باسكال إلى قيمة نقطة عائمة.
TextToFloatتحويل جملة مقفلة بصفر إلى قيمة نقطة عائمة.

ملخّص

في هذا الفصل استكشفنا المفهوم الأساسي للنوع في باسكال. لكن اللغة لديها ميزة أخرى مهمة جدا: انها تسمح للمبرمجين بتعريف أنواع بيانات جديدة خاصة، تدعى بأنواع البيانات المحددة بالمستعمل user-defined data types. هذا هو موضوع الفصل التالي.

الفصل التالي: أنواع البيانات المحدّدة بالمستعمل

حقوق النسخ محفوظة لماركو كانتو؛ وينتش ايطاليا © Copyright Marco Cantù, Wintech Italia Srl 1995-2000
حقوق الترجمة: خالد الشقروني ، 2000