مقدمة

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

وتماماً مثل اللغات المنطوقة تحتوي لغات البرمجة على عبارات أو تعبيرات (Statements)، ومثلما أن للغات المنطوقة قواعد تحكم بنية الجملة، أيضاً فإن للغات البرمجة بناء لغوي خاص بكل لغة، فمثلاً: (;A=5) هي عبارة برمجية تعني أنّ المتغير المُسمى A تساوي قيمته الرقم 5، وهذه تسمى عبارة إسناد لأننا نخصص قيمة للمتغير. حيث يمكننا إنشاء عدد لا محدود من المتغيرات طالما أنها تحوي أسماء فريدة.

استخدام العبارات (Statements) :

يمكننا باستخدام العبارات كتابة الأوامر البسيطة والمعقدة، على سبيل المثال لدينا البرنامج البسيط التالي:

 A = 5;
 B = 10;
 C = A + B;

يخبر هذا البرنامج الحاسوب بضبط المتغير الأول بالقيمة 5، وضبط المتغير الثاني بالقيمة 10، ثم جعل المتغير C يساوي مجموع قيمتي المتغيرين A و B.

بالتأكيد يمكننا تسمية المتغيرات بالاسم الذي نريد، فبدلاً من تسمية المتغير الأول بالاسم (A) مثلاً، يمكن أن يكون اسمه مثلاً (Level)، حيث يكون من المفضل دائماً تسمية الأشياء بأسماء دلالية (أسماء تدل على معنى) وذلك كي يستطيع الأشخاص الآخرون فهم الكود المكتوب عند قراءته.

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

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

في البداية سنحتاج إلى تتبع مجموعة من القيم المهمة في اللعبة، مثل المستوى الذي وصل إليه اللاعب وعدد الكرات التي ستُسَدّد وعدد الفرص. لذلك يجب علينا تهيئة المتغيرات، أي إسناد قيم محددة إلى هذه المتغيرات في بداية اللعبة، مثلاً في بداية المستوى الأول سيكون:

  • Level = 1 (رقم المستوى)

  • Balls = 4 (عدد الكرات التي يجب إيقافها)

  • Score = 0 (عدد الكرات التي تم إيقافها)

  • Chances=2 (عدد الفرص أو "الأرواح" الإضافية التي يملكها اللاعب)

ولكن كيف يستطيع البرنامج أن يعيد تهيئة المتغيرات في كل مستوى جديد بشكل آلي؟

يتم ذلك باستخدام عدة أنواع من العبارات المهمة والتي توجد في جميع لغات البرمجة دون استثناء والتي سنتعرف عليها :

If Statement | عبارة If الشرطية :

هذه العبارة يمكن فهم عملها بالشكل التالي: "إذا كان X صحيحاً، فافعل Y".

نحن نستخدم العبارات الشرطية في حياتنا بشكل يومي، مثلاً نقول : "إذا عدت من العمل مبكراً فسأذهب إلى السينما"، فإذا تحققت عبارة الشرط "العودة مبكراً من العمل" حينها سَيُنفذ الأمر التالي "الذهاب إلى السينما"، وإذا لم يتحقق الشرط فهذا يعني أن الأمر الذي يليه لن يُنفذ.

عبارة If هي بمثابة مفترق طرق والأمر الذي سيتم تنفيذه مشروط في ما إذا كان الشرط محققاً أم لا، لذلك تسمى هذه العبارات عبارات شرطية. وفي معظم لغات البرمجة تبدو جملة If كما يلي:

  if ( "هنا نكتب الشرط" )
  {
        "هنا نكتب الأوامر التي ستنفذ في حال تحقق الشرط"
  } 

وبالعودة إلى لعبتنا يمكننا كتابة التالي :

  if ( Level == 1 )
  {
       Score = 0;
       Balls = 4;
       Chances = 2;
   }

ويمكن أيضاً دمج جملة Else مع If الشرطية، حيث تعمل Else فقط في حال عدم تحقق الشرط أي أنها تعمل كخيار نهائي عند عدم تحقق الشرط المطلوب ويكون معناها "وإلَّا"، مثلاً :

   if ( Level == 1 )
  {
       Score = 0;
       Balls = 4;
       Chances = 2;
   }

   else
   {
      Balls = Level * 3;       
      Chances = Level + 1 ;
    }

هنا في حال عدم تحقق الشرط وهو "أن يكون رقم المستوى مساوياً للــ 1" فسيتم تنفيذ الكتلة الثانية من الأوامر والتي تعني أننا سنحصل على عدد الكرات في جميع المستويات عدا المستوى الأول بضرب رقم المستوى بالرقم 3، فمثلاً إذا كان رقم المستوى هو 2 "هذا يعني أن الشرط غير محقق" وبالتالي فإن عدد الكرات في هذا المستوى سيكون 6 = 3 * 2 .

أي في المستوى الثاني لدينا 6 كرات، وفي المستوى الثالث سيكون عدد الكرات: 9 = 3 * 3، وهكذا..

أما بالنسبة لعدد الفرص في حال عدم تحقق الشرط، فإن عدد الفرص سيساوي: (رقم المستوى + 1)، إذا كنا في المستوى الثالث عندها سيملك اللاعب أربع فرص وفي المستوى الرابع سيملك خمس فرص، وهكذا..

أما عن قيمة الـــ Score فإننا لا نحتاج إلى التغيير فيها، أي إذا امتلك اللاعب في المستوى الأول نقطتين فإنه سيكمل في المستوى الثاني عند نفس عدد النقاط التي كان يملكها في المستوى الأول لذلك لم نغير قيمة الــــ Score في كتلة Else.

ولتكرار تنفيذ بعض الأوامر أكثر من مرة، نحتاج إلى إنشاء حلقة.

While Loop | حلقة While :

حلقة While هي إحدى أكثر العبارات التكرارية المعروفة، حيث يتوقف عملها على تكرار تنفيذ الأوامر بينما الشرط محقق وبغض النظر عن لغة البرمجة فإنها تبدو كالتالي:

    while ("هنا نكتب الشرط")
     {
         "هنا نكتب الأوامر التي ستتكرر طالما الشرط محقق"
     }

لنقل إننا مثلاً في أوقات عشوائية وعندما يكون لدى اللاعب عدد الفرص أو "الأرواح" (Chances) أقل من 4، حينها نريد أن نهدي اللاعب فرص مجانية بحيث نعيد شحن الفرص إلى الرقم 4.

أولاً سنفترض أن اللاعب لم يعد لديه سوى فرصة واحدة للعب قبل أن يخسر اللعبة، ولشحن عدد الفرص إلى 4 سنكتب الكود التالي:

   while (Chances < 4)
    {
        Chances = Chances + 1;
    }

طريقة عمل الحلقة بسيطة جداً، في البداية يتم التحقق من الشرط: (هل عدد الفرص أقل من أربعة؟)، ونحن قلنا فعلاً أن اللاعب لا يملك سوى فرصة واحدة وبالتالي فإن الشرط محقق لذا سيتم تنفيذ الأوامر المكتوبة داخل الحلقة.

السطر : ;Chances = Chances + 1 يعني أن عدد الفرص الجديد الذي سنخزنه يساوي عدد الفرص الحالي زائد واحد، وقلنا أن عدد الفرص الحالي يساوي1 وبالتالي عدد الفرص الجديد سيكون : 2 = 1 + 1. لذا أصبح عدد الفرص الحالي بعد تنفيذ الأمر هو 2.

بعد ذلك يتم الرجوع مرة أخرى إلى الشرط لإعادة التحقق: (هل عدد الفرص أقل من اربعة؟)، والجواب نعم لأن عدد الفرص الحالي هو 2، فيتم تنفيذ الأمر مرة أخرى ونضيف 1 إلى 2 ليصبح عدد الفرص الحالي 3. ثم يعاد التحقق من الشرط: (هل عدد الفرص أقل من أربعة؟)، والجواب نعم. عدد الفرص الحالي هو 3 لذا نضيف 1 ليصبح عدد الفرص الحالي 4.

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

For Loop | حلقة For :

حلقة For أيضاً من أكثر العبارات التكرارية المعروفة، ما يميز حلقة For عن حلقة while أننا في حلقة For نستطيع تحديد عدد مرات تكرار الكود، ففي حلقة while قد يستمر تكرار الأوامر إلى مالا نهاية طالما أن الشرط محقق، أما في حلقة For فالأمر مضبوط أكثر، والشكل العام لها كالتالي:

for ("العملية التي ستنفذ على العداد" ;  "شرط الاستمرار" ; "القيمة الابتدائية للعداد" )
{
        "الأوامر التي ستتكرر"
 }

مثلاً لنفرض أننا نريد منح اللاعب نقاط إضافية كمكافأة في نهاية كل مستوى (Level) وهذه النقاط ستضاف إلى الـــ Score الخاص باللاعب، وسنحسب نقاط هذه المكافأة بناءً على عدد الفرص (Chances) التي لا يزال يملكها عند انتهاء كل مستوى، حيث سنضرب عدد الفرص بنفسه بعدد مرات يساوي رقم المستوى الذي أكمله اللاعب، بمعنىً آخر إذا أكمل اللاعب مثلاً المستوى الثالث ولا يزال لديه* Tow Chances* (فرصتين) في رصيده، فإننا نحسب نقاط المكافأة بالشكل التالي:

Reward = 2 * 2 * 2 = 8.

ضربنا الرقم 2 الذي يمثل عدد الفرص غير المستخدمة بنفسه 3 مرات لأن المستوى الذي أكمله اللاعب هو المستوى الثالث. نطبق ذلك من خلال الكود التالي:

 int Reward = 1;
 int i;
 for ( i = 1 ;   i<= Level    ;  i++)
 {
    Reward = Reward * Chances;
 }
 Score = Score + Reward;

في البداية قمنا بتعريف متغير جديد من النوع int اسمه Reward وأسندنا له القيمة 1، ثم عرفنا المتغير i الذي سيعمل كعداد داخل الحلقة، عند الوصول إلى الحلقة يتم أولاً قراءة القيمة الابتدائية للعداد i والتي جعلناها تساوي الواحد، ثم يتم التحقق من الشرط فإذا كان محققاً يتم الدخول إلى الحلقة وتنفيذ الأوامر داخلها، وفي حالتنا إن الشرط هو أن يكون رقم العداد i أصغر أو يساوي رقم المستوى Level، قلنا أن i= 1 وأنَّ Level = 3 وبالتالي فإن الشرط محقق لأن 3 => 1، لذا سينفذ الأمر داخل الحلقة والذي يعني أن القيمة الجديد للمكافأة ستكون بضرب القيمة الحالية للمكافأة بـ عدد الفرص. أي سيصبح لدينا :

2 * 1 = Reward لأن القيمة الحالية للمكافأة هي 1 وعدد الفرص 2.

بعد تنفيذ الأوامر داخل الحلقة يتم كمرحلة أخيرة إضافة 1 إلى i ليصبح i = 2 وذلك بناءً على الأمر ++i.

بعد ذلك يعاد التحقق من الشرط 3 => 2 ويعاد تنفيذ الأمر : Reward = 2 * 2 = 4، ثم نضيف 1 إلى i فيصبح i = 3.

مرة أخرى يتم التحقق من الشرط : 3 => 3 وينفذ الأمر : Reward = 4 * 2 = 8 ويصبح i = 4.

مرة أخرى يتم التحقق من الشرط : 3 => 4 وهنا أصبح الشرط غير محقق لذا يتم الخروج من الحلقة وتنفيذ الأوامر التي تليها.

في النهاية تنفذ التعليمة الأخيرة: ;Score = Score + Reward والتي تعني أن القيمة الجديدة للــ Score ستساوي القيمة الحالية زائد قيمة المكافأة التي حصلنا عليها.

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

Functions | الوظائف :

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

لفهم عمل الوظائف بشكل أكبر سنحول كود حساب المكافأة السابق إلى وظيفة، في البداية يجب أن نسميها، يمكننا اختيار الاسم الذي نريد ولكن بما أن الكود لحساب النتيجة النهائية للــ Score لذا سنسميها Score_Calc، أما بالنسبة لطريقة تعريف الدالة فهي تختلف من لغة إلى أخرى ومن نوع إلى آخر، مثلاً في #C نستطيع أن نعرف وظيفتنا (الطريقة) بالشكل التالي:

public  void   Score_Calc()
{
       int Reward = 1;
       int i; 
       for ( i = 1 ; i<= Level ; i++)
       { 
            Reward = Reward * Chances; 
       } 
       Score = Score + Reward;
 } 

وبدلاً من إعادة كتابة نفس الكود في كل مرة نحتاج فيها لحساب الــ Score مع المكافأة، باستخدام هذه الوظيفة أو الطريقة سنستدعي فقط اسم الدالة وسينفذ الكود تلقائياً:

  Score_Calc();

بفهم هذا المثال ندرك جوهر البرمجة بالكامل، فلم يعد من المجدي كتابة - على سبيل المثال - آلاف السطور والعبارات من أجل إنشاء برنامج واحد، لذا بدلاً من ذلك يمكننا استخدام الوظائف التي تسهل عمل المبرمج وتختصر الأكواد بحيث تكون كل وظيفة مسؤولة عن ميزة محددة.

وفي البرمجة الحديثة من غير المألوف رؤية وظائف تزيد عن مئة سطر من التعليمات البرمجية، لأنه في هذه الحالة من المحتمل أن يكون هناك جزء من كود الوظيفة يمكن أخذه وجعله وظيفة منفصلة بحد ذاتها.

وتحويل البرامج إلى وظائف يجعل من الممكن توظيف عدة مبرمجين للعمل على برنامج واحد وبالتالي تحقيق كفاءة أكبر.

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

وتوجد حالياً مكتبات لكل شيء تقريباً، بما في ذلك علوم البرمجة والشبكات والرسوميات والصوت.

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