‏إظهار الرسائل ذات التسميات نقد لغات برمجة. إظهار كافة الرسائل
‏إظهار الرسائل ذات التسميات نقد لغات برمجة. إظهار كافة الرسائل

الأحد، 10 أغسطس 2014

مرحباً Swift، ما الذي أخَّرك حتي الآن ؟!

 
في مؤتمر WWDC 2014 الصاخب الذي عقدته Apple في الأيام الماضية كان هناك العديد من المفاجآت، منهن أن نظام mac os x صار قريب الشكل من نظام iOS (و هو الأمر الذي لا أخفي كرهي الشديد له، و ربما أخصص مقالاً قادماً لانتقاد هذا الأمر و أوضح فيه مدي استيائي منه). و لكن كان هناك الكثير من الأمور التي أسعدتني، و علي رأسها كان خبر إطلاق Apple للغة برمجة جديدة تسمي swift ستعمل كبديل للغة Objective-C علي المدي البعيد. و في هذا المقال أنوي أن أكتب بعض الفقرات التي أوضح فيها وجهة نظري لتلك اللغة الجديدة.

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

الأحد، 10 فبراير 2013

استبدال الإجراءات متعددة الخرج بالإجراءات الداخلية

هناك لغات برمجةٍ تسمح بتفريع الإجراءات functions nesting، أي أنها تسمح بتعريف إجراءٍ أو أكثر داخل إجراءٍ آخر، و من تلك اللغات لغة الـpython علي سبيل المثال. و في أمثال تِلكم اللغات نري أننا نحصل علي فائدةٍ جميلةٍ من تفريع الإجراءات، حيث أن الإجراءات الداخلية يمكن أن تكون قادرةً علي التعامل مع المتغيرات و الثوابت و ما يشبههن اللاتي تم تعريفهن في الإجراءات الخارجية قبل تعريف الإجراء الداخلي، و كذلك التغيير في قِيم تلكم العناصر بحرية.
كما في المثال التالي المكتوب بالـpython:
def  func1():
    x = [10]
    y = [20]
   
    def  func2():
         x[0] = x[0]+ 1
         y[0] = y[0] + 1
   
    func2()
   
    print x[0],"    ", y[0]
   
func1()

الذي يعطي عند تنفيذه الخرج التالي:
11         21

و لو حاولنا إعادة صياغة البرنامج السابق بلغة لا تدعم تفريع الإجراءات مثل الـjava لوجدنا أننا سنضطر لكتابة كودٍ يشبه ما يلي:

public class Test {
    public static void main(String[] args) {
        Test t = new Test();
        t.func1();
    }
   
    void func1() {
        int x = 10, y = 20;
        result res = func2(new result(x, y));
        System.out.println("" + res.x + "    " + res.y);
    }

    result  func2(result res){
        res.x = res.x +1;
        res.y = res.y +1;
        return res;
    }

    class result {
        int x, y;
        public result(int x, int y){
            this.x = x;
            this.y = y;
        }
    }
}
و نري فيه أننا اضطررنا إلي عمل صنفٍ جديدٍ result يحوي داخله البيانات المتعددة التي نرغب في إعادتها لمحاكاة عمل الإجراءات الداخلية. و الأمر في المثال السابق يتعلق بمحاكاة عمل إجراءٍ داخليٍ واحد، فكيف يكون الحال مع محاكاة عمل أكثر من إجراءٍ تتعامل مع أكثر من من حاويةٍ داخلية ؟!
بالطبع ستكون هذه من الأمور المرهقة للمبرمج، و كلما ازدادت المشاريع البرمجية ضخامةً كلما قابل المبرمج مواقفاً تشبه السابقة و لكنها أكثر تعقيداً.
لكن هذه المشكلة يمكن حلها بمنتهي البساطة إذا كانت الإجراءات قادرةً علي إعادة أكثر من خرج، كما هي الحالة مع لغة إبداع، و بالنظر إلي بناء المثال السابق بإبداع:


إجراء1()


إجراء  إجراء1 :
    رقم س = 10
    رقم ص = 20
   
    س ، ص = إجراء2(س    ص)
   
    أكتب.نص.سطر(إلي.نص(س) +"       " + إلي.نص(ص))
   
إجراء  (رقم س2  رقم ص2)  إجراء2(رقم س1  رقم ص1):
    س2 = س1 +1
    ص2 = ص1 +1

   
   
و له تقريباً نفس عدد أوامر البرنامج المكتوب بالـpython، بل و يمكن اختصار البرنامج السابق أكثر من ذلك بجعل كود الإجراء إجراء2 كما يلي:

إجراء  (رقم س2=س1+1 رقم ص2=ص1+1)  إجراء2(رقم س1  رقم ص1):
    لاشيء

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

كما أنه يمكن الاستغناء عن الإجراءات الداخلية عن طريق التمرير بالمرجع passing by reference، و هو الأمر الموجود في لغاتٍ كثيرةٍ منها الـC  و الـ++C و الـ object pascal و الـD و غيرهن من اللغات الأخري. و يمكننا كتابة المثال السابق بلغة object pascal كما يلي*:

function func2(var x, y :integer);
begin
    x = x+1
    y = y+1
end;

function func1();
begin
    x :integer = 10;
    y :integer = 20;
   
    func2(x,y);
   
    writeln(x +"    " +y);
end;

begin
    func1();
End.

و بالطبع يمكنكم ملاحظة أنه تم الاستغناء عن الإجراءات الداخلية هنا أيضاً بكفاءة، لكن أيضاً يمكنكم ملاحظة أن تعقيد قواعد الـobject pascal جعل الأمر أقل سهولةً من حالتَيْ الـpython و إبداع.

كما أن هناك نقطةً أخري تتعلق بإمكانية حدوث ارتباكاتٍ و مشاكلٍ منطقيةٍ في اللغات التي تدعم الإجراءات الداخلية، حينما تكون تلك اللغات من نوع اللغات استنتاجية الأنواع
Type inference، فمثلاً لو نظرنا إلي البرنامج الأول المكتوب بلغة الـpython لوجدنا أنه يستخدم الـlists و ليس المتغيرات الرقمية البسيطة، فلماذا لم أكتبه كما يلي:
def  func1():
    x = 10
    y = 20
   
    def  func2():
         x = x + 1
         y = y + 1
   
    func2()
   
    print x,"    ", y
   
func1()

علي الرغم من أن هذا هو الأمر الأقرب للمنطق ؟!
الجواب أنني حينما فعلتُ ذلك أَخرجَ لي مُفسِّر الـpython الخطأ التالي:
x = x + 1                                                                                                            
UnboundLocalError: local variable 'x' referenced before assignment
و السبب في هذا أنه اعتبر أن المتغيرين x و y داخل الإجراء func2 يختلفان عن المتغيرين x و y اللذين في func1 ! و بالتالي أصبح من الخطأ كتابة الأمرين:
x = x + 1
y = y + 1
لأننا بهذا نكون قد استخدمنا المتغيرين x و y قبل إعطائهما أي قيمة، رغم أن المبرمج يقصد أن يستخدم x و y الخاصين بالإجراء func1 و اللذان تم إعطاؤهما قيماً ابتدائيةً هن 10 و 20 علي الترتيب !

و الغريب أنك لو عرَّفتَ list داخل func1 فيمكنك استخدام عناصرها الداخلية بشكلٍ عاديٍ في func2، و هو ما لجأتُ إليه فعلاً في المثال الأول. و لكنك لو أسندتَ قيمةً لاسم تلك الـlist في الإجراء الداخلي
func2 فإنه سيعتبر أنك تقوم بتعريف list جديدة داخل func2 تُغطِّي تلك التي تحمل نفس الاسم في func1 !
أي أنهً عند تنفيذ المثال التالي:

def  func1():
    x = [10]
    y = [20]
   
    def  func2():
         x = [11]
         y = [21]
   
    func2()
   
    print x[0],"  ",  y[0]
   
func1()
تكون النتيجة:
10    20

لأن القِيم [11] و [21] أُسنِدت إلي x و y  الخاصَّيْن بـfunc2، بينما بقي x و y الخاصَّيْن بـfunc1 كما هما، و هذا يعني معضلةً عند محاولة المبرمج التعديل في قيمة x أو y  في func1 من داخل func2؛ حيث أنني حينما حاولتُ إيجاد طريقةٍ لفعل ذلك تختلف عن استخدام خاصية الخرج المتعدد: لم أجد، و هو ما يؤيد عدم الحاجة الضرورية لتفريع الإجراءات، و أن كل الفوائد التي يمكن جنيها من ورائه يمكن الحصول عليها بشكلٍ أبسط و أسهل عن طريق الإجراءات متعددة الخرج. 
كما أن هذا الأمر يؤكد أيضاً ما ذهبتُ إليه من أفضلية فرض التعريف اليدوي للأنواع علي المبرمج و عدم جعل اللغة من النوع الذي يستنتج الأنواع بدون تدخل المبرمج**.


----------------------------------
* كل البرامج المكتوبة في هذا المقال تم تنفيذها عملياً و التأكد من خلوها من الأخطاء، ما عدا البرنامج المكتوب بالـobject pascal.
** تجدون كلامي عن هذه الجزئية في فصل (فائدة تعريف الحاويات يدوياً) الموجود في باب (أين الإبداع فيها؟) في نهاية كتاب (رسالة البرمجة بإبداع).

الأحد، 5 أغسطس 2012

خاطرةٌ عن الـ#C

خاطرةٌ عن الـ#C

لغة الـ#C لغةٌ رائعةٌ و فاتنة بالفعل، و قد بدأت مشواري البرمجي الحقيقي معها و مع بيئة الفيجوال ستوديو visual studio، لكن أكبر المشاكل التي تواجه الـ#C أن الجميع يعتبرها واجهةً فقط لتقنية الـ.Net (و قد كنتُ منهم لفترةٍ طويلة)، لذلك فإن كل من يبرمج بها يستخدمها و هو يؤمن أنه ما دام يستخدمها فلن يستطيع البرمجة إلا للويندوز فقط، بل و سيظل مرتبطاً أبد الدهر ببيئة الفيجوال ستوديو و مكتبة الـ.NET.


و من أسباب ذلك أنه علي الرغم من قوة الـ#C إلا أن نقلها إلي منصات متعددة من الصعب أن يكون كنقل الـjava مثلاً: فالجافا مصممة من الأساس لكي تتنقل برامجها بحرية عبر المنصات المختلفة، و هذا مراعي في مكتبتها القياسية الـJDK، بينما مكتبة الـ.Net بها أجزاء من الصعب جداً نقلها أو مُحاكاتها بالكامل (مثل جزء الواجهة الرسومية GUI الضخم) و بالتالي لا يكون أمام المبرمج الذي اعتمد علي أكواد مكتبة الـ.Net غير المتنقلة إلا أن يبقي علي منصة الويندوز فقط، و للأسف فمعظم مبرمجي الـ#C قاموا بالفعل بعمل الكثير من البرامج الضخمة منذ فترة بطريقةٍ شديدة الارتباط بنظام التشغيل ويندوز و صار من المستحيل عملياً تحويل هذه البرمجيات للعمل علي منصاتٍ أخري.

و مما يزيد الطين بلةً أن هناك براءات اختراع مملوكة لمايكروسوفت يتم استخدامها (بالطبع) داخل مشروع مونو mono (الذي يعتبر البديل مفتوح المصدر لمنتجات مايكروسوفت التي تربط الـ#C بها، و يعطيها القوة التي تضاهي قوة الجافا)، و بالتالي يضع هذا المبرمجين تحت طائلة مايكروسوفت التي لا تري إلا مصالحها (بطبيعة الحال).

السبت، 4 أغسطس 2012

كنتُ أظن حتي رأيت

كنتُ أظن أن الـ++C هي أصعب لغة برمجة حتي رأيتُ الـAda.
كنتُ أظن الـ#C هي أضخم لغة برمجة حتي رأيتُ الـVB.NET.
كنتُ أظن أن الـjava هي أكثر اللغات تزمتاً من حيث هيكل البرنامج حتي رأيتُ الـobject pascal.

اختبار المترجمات و المفسرات جـ1

اختبار المترجمات و المفسرات جـ1

من أصعب النقاط في برمجة المترجمات compilers و المفسرات interpreters أنها (علي خلاف معظم المجالات البرمجية الأخري) تنتمي لفئةٍ صغيرةٍ جداً من التطبيقات التي لا يُسمح أن يكون فيها أقل القليل من الأغلاط bugs أو المخالفة للمواصفات القياسية الخاصة بها، فالبرنامج النهائي يجب أن يكون في أعلي درجات الموثوقية و الاعتمادية و أن يفعل "كل" ما صُمم لفعله بالشكل "المُتوقع"، و إلا فسيُعد غير صالحٍ للاستعمال الطبعي !

لتقريب هذه الصورة إلي الذهن: يمكنك أن تتخيل أن تكتب برنامجاً بلغة الـjava ثم تقوم بترجمته، و عند تشغيله تفاجأ بأنه لا يعمل كما يُفترَض، فأين الغلطة إذاَ: هل هي في برنامجك المكتوب أم في مترجم الجافا ؟؛ فهذا الموقف سيصبح كارثةً متكررةً بشكلٍ لا يُطاق لو سُمح بأن يكون المترجم أو المفسر قابلاً لوجود الأغلاط المنطقية فيه بنفس كثافة البرمجيات الأخري.

إلا أن هذا لا يدفعنا إلي الظن بأن هذه البرامج "دائماً" ما تكون مثالية من هذه الناحية، بل هو ينبهنا فقط إلي أن مرحلتا الاختبار testing و التنقيح debugging لهذا النوع من البرامج لا تشبهان ذات المرحلتين في حالة البرمجيات الأخري التي تقبل التساهل فيها علي نحوٍ أكبر.
فيجب هنا أن نقوم باختباراتٍ أكبر كثافةً عددية، و أشد تغلغلاً في احتمالات الاستعمال usage cases المختلفة، بل يجب أن يخضع البرنامج للاستعمال القاسي أكثر من الحالة الطبعية، بما في ذلك أشد حالات الاستعمال شذوذاً و غرابةً و قلة حدوث؛ و ذلك حتي يتم التنبه إلي أي غلطةٍ منطقيةٍ قد تكون في مكانٍ صعب الوصول إليه في مجال الاحتمالات الإستخدامية المختلفة.

--------------------------
للمزيد من المعلومات:
http://en.wikipedia.org/wiki/Compiler_correctness

الأحد، 3 يونيو 2012

أكثر من لغة، و أكثر من بيئةٍ متكاملة.

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

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


و تنقسم اللغات من حيث قوة تعلمي لها إلي عدة فئاتٍ هي:
  • اللغات التي أتقنتها بشكلٍ كبيرٍ جداً، مثل الـ++C و الـjava و الـ#C و VB.NET و إن كنت طبعاً لم أتقن جميع مكوناتها و قواعدها. مع إتقان جزءٍ جيدٍ من مكتباتها القياسية، و ربما مكتباتٍ أخري ذات أغراضٍ خاصة (مثل مكتبة الـOpenCV في حالة لغة الـ++C و مكتبة الـXNA مع لغة الـ#C).
  • اللغات التي أتقنت قواعدها و لكني لم أتعلم مكتبتها القياسية بشكلٍ مماثلٍ نظراً لضيق الوقت و تأجيلي لهذه الخطوة إلي مرحلة تعلم المناهج المختلفة لتصميم المكتبات البرمجية و العلاقة بينها و بين تصميم اللغات ذاتها. و هذا حدث مع لغاتٍ مثل الـpython و الـobject pascal و matlab.
  • اللغات التي تعلمت كثيراً من نحوها syntax و لكن ليس علي نفس مستوي لغات النوع الأول، و كذلك فلم أتعلم مكتبتها القياسية. و منها ruby و fortran90  و shell script (إن اعتبرنا الأخيرة لغة برمجة كاملة).
  • اللغات التي أعلم بعض الأشياء عنها و بعض قراراتها التصميمية، و لكني لم أتعمق فيها مطلقاً، مثل الـeiffel و الـGo و الـobjective C و ربما غيرهن. 
و كذلك كنت لكل لغةٍ من تلك اللغات أُنَصِّب بيئة برمجةٍ متكاملة لها علي حاسوبي لتجربتها قدر الاستطاعة؛ حتي يتسني الاحتكاك العملي لي بها فأدرك نقاط القوة و الضعف فيها عن تجربة واقعية. و كذلك لمعرفة الفروقات بين بيئات البرمجة المتكاملة و التي يعد بناؤها جزءاً هاماً للغاية من هندسة البرمجيات المُساعَدَة حاسوبياً CASE - computer aided software engineering، و لمعرفة تأثير القرارات التصميمية للغة البرمجة علي كيفية عمل و بناء بيئة البرمجة المتكاملة الخاصة بها.
و من ضمن هذه البيئات ما يلي:
  • netbeans
  • monodevelop
  • eric
  • lazarus
  • octave
  • code blocks
  • Gambas
و أعترف أنني لم تتسن لي الفرصة لتجربة أيٍ منها تجربةً حقيقيةً قويةً، إلا بيئة الـNetbeans التي استقر قراري علي استخدامها أثناء البرمجة بالـjava.
     و الجميل أنني بحمد الله تعالي تعودت منذ صغري علي التلخيص الجيد لكل ما أتعلمه، بل و كنت أتسابق في تلخيص الكتب العلمية مع صديقي: ياسين أحمد سعيد، و أدي هذا إلي أنني لم أتعلم شيئاً في حياتي له قيمةٌ إلا و دونت ما تعلمته فيه. و لم يكن تعلمي لهذه اللغات شاذاً عن هذه القاعدة، فاستطعت تكوين تلخيصاتٍ جميلةٍ للغات النوع: الأول و الثاني و الثالث، و هي التي تتكون منها موسوعة الألسن التي تحدثت عنها مسبقاً.


    الآن: ما الغرض من حديثي عن هذه الأمور الشخصية ؟
    بمنتهي البساطة أنا أريد أن أوضح عملياً بعض النقاط التي تخفي علي الكثيرين بكل أسف:
    • الوقوف علي مسافةٍ واحدةٍ من كل الأذواق و المشارب و التقنيات المختلفة التي توجد داخل نطاق تخصصنا، و من ثم دراستها جميعها (أو ما تيسر منها إن كان الكل أو الأغلبية أكبر من اللازم)، و بعد الدراسة المتفهمة الجيدة يمكننا أن ننحاز إلي تقنيةٍ ما علي أنها التي نعتقد فيها القرب أكثر ما يُمكن من الصواب.
      و الحرص علي عدم التبعية و البعد التقليد الأعمي؛ فهناك أناسٌ تعودوا أن يسلموا قيادتهم إلي أحد الهيئات أو المؤسسات أو الشركات علي اعتبار أنها الأفضل تقنياً "دائما" و مهما كان قرارها في فرعٍ من الفروع !.
      فالتقليد و إن كان يُتقبل من بعض الناس فإنه في الأصل مذمومٌ للمتخصصين كل الذم، و ما من متخصصٍ تعصب لمُنتجٍ (بفتح التاء و كسرها) دون الاستناد إلي دليلٍ و برهانٍ لانحيازه إلا كان هذا قدحاً في عقلانيته و قدرته علي اتباع المنهج العلمي من الأساس.
    • الشجاعة في النقد عند وجود مناط الانتقاد، فعلي الرغم من أن هناك من لن يتقبل نقدك للتقنية التي يحبها مهما كانت منطقية النقد أو دوافعه، إلا أنه لا يُمكنك أن تسمح لمثل هذا أن يكبلك و أن يمنعك من استبعاد ما يجب استبعاده أو قبول ما يجب قبوله؛ فعامةًَ أي رأيٍ تقتنع به سيكون هناك من يُعارضك فيه أشد المعارضة، و ربما يري أنك وقحٌ و جاهل !
    • زيادة القاعدة المعرفية قدر الإمكان؛ فمثل هذا الازدياد قادرٌ علي توسيع آفاق تفكير صاحبه جداً، و يجعله قادراً علي الانتباه (نظراً للنظرة الشاملة التي يمتلكها) إلي ما قد يخفي علي الكثيرين و إن كانوا أكثر منه فضلاً و ذكاءاً.
    • التجريب العلمي و المعايشة أمران مهمان للغاية؛ فبإمكانهما أن يهدما كل ما بناه الواحد منا من أفكارٍ نظريةٍ و تحويلها في نظره إلي غبارٍ تذروه الرياح.
      و كلما كان مجال التجريب قريباً من الأصول التي نبني عليها آراءنا و فرعياتنا كلما كانت فائدة التجريب أوضح و أقوي (و ربما أكثر صدمة).

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



    الأربعاء، 11 يناير 2012

    نقد الدامجات unions في لغتي الـC و الـ++C

    نبذةٌ بسيطة:
    الـunions فى الـC و الـ++C هى مكوناتٌ الفكرة الرئيسة من ورائها هي إتاحة الفرصة لاستخدام نفس الحيز من الذاكرة بأكثر من متغيرٍ لها أكثر من نوعٍ مختلف، يعنى أن الدامج عبارةٌ عن حاويةٍ تُشبه الصنف class من حيث أنه يتم داخله تعريف متغيراتٍ مُكونةٍ له، و لكنه يختلف عنه فى أن الصنف يعتبر كل متغيرٍ مُعَرَّفٍ منفصلاً عن المتغيرات الأخرى من حيث حيز الذاكرة المحجوز له و لها، بينما فى الدامج يتم إعطاء كل تلك المتغيرات مساحةً مشتركةً فى الذاكرة تبدأ من نفس النقطة و تنتهى حسب مساحة ذلك المتغير (و التى تتأثر بنوعه).
    يعنى لو أننا كتبنا ما يلى:
    فإن معنى هذا أننا نُعَرِّفُ متغيراً يسمى var1 من النوع DATATYPE يمكننا التعامل معه على أساس أنه من النوعchar أو النوع int أو النوع long أو النوع float أو النوع double، فى حين أن القيمة التى نتعامل بها كل مرةٍ هى نفس القيمة و لكن مع اختلاف المساحة التى نتعامل بها منها.
    و لمزيدٍ من التوضيح يمكنكم مراجعة هذا الرابط في موسوعة الويكيبيديا:
    http://en.wikipedia.org/wiki/Union_%28computer_science%29

    لا ينبغي أن يُسمح بها في اللغات الجديدة للأسباب التالية:
    إن الأسباب التى يسوقها الشارحون للبرمجة بلغتى الـC و الـ++C فى كتبهم لوجود الدامجات و مدى فائدتها لا تُسمن و لا تُغْنِى من جوعٍ أمام التحقيق و التدقيق لتغير الزمن و اختلاف الظروف؛ فما وجدت منها غير التالي:
    1. أن الدامجات تُوفر فى استخدام الذاكرة حينما أريد التعامل مع قيمةٍ ما بأكثر من أسلوب؛ فبدلاً من إشهار متغيراتٍ مختلفة الأنواع بشكلٍ منفصلٍ و أقوم كل مرةٍ (حينما أحتاج إلى التعامل مع القيمة على أنها من نوعٍ معينٍ) بوضعها فى المتغير الذى ينتمى إلى ذلك النوع، و من ثم أقوم بإجراء العمليات على ذلك المتغير، بدلاً من كل هذا فإننى أقوم مباشرةً بوضع تعريفٍ لدامجٍ يدمج بين تلك الأنواع فى مكانٍ واحدٍ؛ لأتمكن من التعامل مع القيمة المُخَزَّنة فى داخله بأى شكلٍ أريده.
      و هذا السبب ضعيفٌ جداً فى هذه الأيام؛ فهذا القول كان صحيحاً حينما كانت الأجهزة التى تتم البرمجة لها لا تحتوى من الذاكرة إلا على 64 كيلو بايت: يستغل نظام التشغيل مقداراً صغيراً منها و تستغل البرامج العادية الباقى، و هذه هى مواصفات أجهزة الـPDP11 التى كانت أوائل برامج الـC مكتوبةً لها ! و لكننا الآن نعيش فى زمنٍ مختلفٍ ليس من الممكن فيه أن تُوهمنى أنك حينما تكتب برنامجاً كالسابق سوف تُوفر لى الكثير من الذاكرة المهدرة ! بل العكس أنك ستحصل على برنامجٍ غريبٍ سئ التكوين مقابل الحصول على بضعة بايتاتٍ لا تساوى أى شئٍ بالمقارنة مع أقل الإمكانيات فى سعات ذواكر الحاسوب الموجودة اليوم !
      إذاً فهذه الفائدة التى كانت موجودةً للدامجات قد انتهت إلى غير رجعة، و كان من المحتم على مصممى لغات البرمجة التنبه إلى هذا و إبعاد ذلك المكون الزائد عن اللغات الجديدة، لا ضمه إليها كما حدث مع الـ++Cالتى سارعت إلى ضمه إليها و كأنه كنزٌ ثمين ! و ذلك على الرغم من أنها قد صُمِّمَت بعد فترةٍ كبيرةٍ من ظهور الـC و حينما لم يكن القلق على إهدار ذاكرة الحاسوب كما كان أيام الأجهزة العتيقة فى الأزمان الغابرة لتصنيع الحواسيب !
    1. الدامجات أكثر كفاءةً من استدعاء الإجراءات التى تُحَوِّل بين أنواع المتغيرات. أى أنه بدلاً من استدعاء إجراءات التحويل بين أنواع المتغيرات فى كل مرةٍ نحتاج فيها إلى تحويل قيمةٍ ما من نوعٍ إلى نوعٍ آخر فإننا نستخدم المتغيرات الموجودة فى الدامج مباشرة، و نستخدم منها ذلك الذى له النوع الذى نرغب فى التعامل مع القيمة على أساسه.
      و هذا قولٌ آخرٌ ضَعُفَ بتغير الزمن، حيث أن مثل هذه التوفيرات الغريبة لا تُقدم تلك النتائج الخارقة التى تُغرى ببذل الجهد و التضحية للحصول عليها؛ فما الذى سيضر البرنامج إذا ما استدعى إجراء تحويلٍ عشر مراتٍ أو أكثر ؟! و ما التأخير الذى سيحدث عندئذٍ و كيف سيؤثر ذلك التأخير على زمن تنفيذ البرنامج بصورةٍ  و لو طفيفة ؟!

    الثلاثاء، 27 ديسمبر 2011

    نقد نموذج لغة الـPython للأصناف classes و الدوال functions.

    على الرغم من أن لغة الـPython تمثل بالنسبة لى لغةً من أفضل اللغات (بل أفضلها علي الإطلاق) من حيث شكل البرنامج المكتوب بها، إلا أنها تحتوى على قراراتٍ تصميميةٍ أجد أنه من الواجب الرد عليها؛ لأنها تمثل قراراتٍ سيئةٍ بما فيه الكفاية لمن كانت له قناعاتٌ تصميميةٌ كقناعاتى.
    و من أوضح هذه القرارات الغريبة هو نظرة اللغة إلى الأصناف classes و الدوال functions؛ حيث أن هذه النظرة الغريبة ترى فى الأصناف ما يشبه الدوال، و ترى فى الدوال ما يشبه الأصناف !، فنرى أن الأصناف فى الـPython عبارةٌ عن حاويةٍ لمجموعةٍ من الأوامر المتتابعة التى تُنفذ بشكلٍ متتالٍ واحداً تلو الآخر، و أن المكونات الداخلية للأصناف مثل الدوال و المُشَيِّدَات constructors و خلافها ما هى إلا عباراتٌ تنفيذيةٌ بدورها، و يعنى هذا أنه يمكننى أن أقوم بكتابة عبارات اسناد قيمٍ و استدعاءاتٍ لإجراءاتٍ ما داخل صلب الصنف و ليس داخل مشيداته أو دواله، و مثالٌ على هذا (كودٌ للتوضيح فقط):
    حيث يتم فى البداية تعريف دالة تسمى func1، ثم تم استخدامها لإسناد قيمةٍ إلى متغيرٍ يسمى A، ثم تلى ذلك تعريف دالةٍ أخرى تسمى func2.
    و تكتمل الصورة حينما نعلم أنه يمكننا فى الـPython تعريف دالةٍ داخل دالةٍ أخرى، و استخدامها عن طريق كتابة اسم الدالة الحاوية لها و إتباعها بقوسى دالةٍ نكتب فيهما المعاملات الممررة للدالة الداخلية. و تُعْرف الدوال الحاوية بالاسم closures.
    و مثالٌ على هذا:
    و بالنظر إلى صفات الأصناف و الدوال فى الـPython سنرى أن لكليهما الصفات التالية:
    1. اسم الدالة  و اسم أى كائنٍ من الصنف هما مؤشران يشيران للدالة و الكائن، أى أنه يمكن تغيير الدالة أو الكائن الذى يشير إليه الاسم. مثل البرنامج التالي:
    حيث أنه فى الأمر قبل الأخير جعلنا الاسم (log) يشير إلى كود الدالة (exp)، بينما جعلنا الاسم (exp) يشير إلى كود الدالة (log). و النتيجة التالية لاستدعاء الاسمين قبل التبديل و بعده تدل على أثر التبديل و نجاحه:
    1. كلاهما يمثل كتلةً من الأوامر التى تُنَفَّذ بشكلٍ تتابعى.
    2. كلاهما له القدرة على احتواء تعريفاتٍ لأصنافٍ داخله، أى أنه يمكن للدالة أن تحتوى على تعريف صنفٍ من الأصناف داخلها لتعود و تستخدمه بصورةٍ طَبْعيةٍ كما يحدث فى حالة الأصناف المتفرعة فى باقى لغات البرمجة.
    1. كلاهما له القدرة على احتواء دوالٍ داخليةٍ يتم استدعاؤها عند الحاجة إليها عن طريق اسم المكون الحاوى لها. مع فارقٍ: أن الدوال تحتوى داخلها دالةً داخليةً واحدةً فقط بينما يمكن للصنف تعديد الدوال، و كذلك فإن الدوال التى فى الصنف يتم استدعاؤها باسمها بينما تُستدعى الدوال الداخلية باسم المتغير الذى استدعى دالتها الحاوية. 
      مثال1:
      مثال2:
    و من الصفات السابقة نرى أن هناك تقريبٌ لا معنى له بين صفات مكونين برمجيين يجب إبقاء كل منهما منفصلاً عن الآخر، و عدم إثارة البلبلة التى لا داعى لها بجعل كل منهما يحمل شيئاً من صفات الآخر بشكل لا يحقق أى أهدافٍ فى حقيقة الأمر.
    فالدوال هى فى الأصل كتلةٌ من الأوامر التى تُنَفَّذ بشكلٍ تتابعىٍ بحيث يتم استدعاؤها عند الحاجة إليها فيوفر وجودها تكرار الأكواد و مساحة البرنامج النصية و يزيد القدرة على اكتشاف الأخطاء و السرعة فى ذلك و غيرها من العوامل الأخرى، أما الأصناف ففى الأصل لم تنشأ إلا لتكون حاويةً تجمع بين مجموعةٍ من المتغيرات و مجموعةٍ من الدوال التى تعمل عليها، و عن طريق الاستنساخ instantiating من الأصل يتم الاستفادة من كود الصنف أقوى استفادة، عن طريق عزل المحتويات الداخلية للكائنات عن المبرمج النهائى و غيرها من الفوائد، فما معنى وجود دوالٍ تحوى دوالاً أخرى داخلها ؟! أو صنفٍ يحوى أوامر تُنفذ بشكلٍ متسلسلٍ و كأنها كتلةُ أوامرٍ فى صلب دالةٍ من الدوال !
    و ما الفائدة التى ستعود علينا من ذلك المزج و التقريب الغريبين؟، و أى ضررٍ سيعود علينا عند التفريق بينهما كما تفعل بقية اللغات؟.

    الأحد، 25 ديسمبر 2011

    كلماتٌ ليست كالكلمات


      المطور: م. محمد سامي
      متأثرة بـ: python و lisp
      نظام التشغيل :WINDOWS و GNU/linux 
      موقع اللغة:
      http://www.kalimat-lang.com 
      بريد المبرمج:
      samy2004 @ gmail.com 
      مدونة المبرمج:
       http://iamsamy.blogspot.com/ 
      مواصفات أخرى:
      يقول م. محمد سامي عن اللغة:
    كلمات لغةٌٌ برمجيةٌ عربيةٌ لتعليم الأطفال البرمجة وقد راعينا فيها سهولة التعلم وقابلية البرامج للقراءة.
    اللغة تشمل امكانات جاهزة للرسم وتحريك الصور على الشاشة، وبها أيضا امكانية التعامل مع لوحة المفاتيح والماوس. كما تأتي في بيئة تطوير متكاملة (IDE) ليسهل بها كتابة وتنفيذ البرمجيات.
    ربما تكون كلمات لغة للأطفال لكنها ليست لعبة، هذه لغة حقيقية باوصاف مألوفة للمبرمجين المحترفين:
      • Object-oriented programming
      • Dynamic typing
      • Garbage collection
      • عمل ملفات تنفيذية exe (انظر قائمة برنامج-> عمل ملف تنفيذي)
    ولعلّها تكون بإذن الله جزءاً من نهضةٍ علميّةٍ في أمتنا.

    ميزات لغة كلمات:
    بدايةً: تعد لغة كلمات أرقي لغات البرمجة العربية الحالية علي الإطلاق، فهي بحقٍ تُعد لغة برمجةٍ بكل ما تحمل هذه الكلمة من معاني، و لكلمات الميزات التالية:
    1. كاملة الهيكل، يعني أنها لا ينقصها مكونٌ من المكونات الأساسية التي يجب توفرها في أي لغة برمجة تستخدم عملياً، مثل:
      • التعامل مع المتغيرات.
      • معاملات حسابية و منطقية logic and arithmetic operators
      • الجمل الشرطية.
      • الجمل التكرارية.
      • الدوال functions.
      • أوامر إدخال و إخراج للتعامل مع الشاشة console.
      • أوامر للتعامل مع الملفات.
      • المكونات المركبة:
        1. المصفوفات arrays
        2. القواميس dicts
    2. تحتوي علي مكتبةٍ تجريبيةٍ بسيطة، و لها الإمكانيات التالية:
      • التعامل مع الملفات.
      • الإدخال و الإخراج من/علي الشاشة.
      • أوامر رسومية:
        1. أمر ارسم.خط
        2. أمر ارسم.مستطيل
        3. أمر ارسم.دائرة
        4. أمر ارسم.نقطة
      • أوامر التعامل مع الصور (الأطياف حسب تعبير اللغة):
        1. حمل.طيف
        2. ارسم.طيف / في
        3. اخف.طيف
        4. اظهر.طيف
      • أوامر التعامل مع الحوادث المدعومة في اللغة، و هي:
        1. حوادث الماوس
        2. حوادث لوحة المفاتيح
        3. حوادث الأطياف
      • إمكانيات برمجة الواجهات الرسومية.
    3. لها ميزاتٌ متقدمةٌ للغاية عن لغات البرمجة البسيطة، مثل:
      • دعم البرمجة الكائنية oop بشكلٍ جيد، ففيها:
        1. تعريف الفصائل (تكافئ الـclasses).
        2. الوراثة inheritance
      • إمكانية تجميع الأكواد المرغوب في إعادة استعمالها في وحدات.
         
      • قويةٌ في جزئية الأحداث و معالجتها events and events handling
      • تدعم تنفيذ أكثر من عمليةٍ في نفس الوقت (شيئٌ يشبه في تأثيره تعدد خيوط التنفيذ multithreading).
    و للمزيد من التفاصيل و الأمثلة يمكنكم زيارة موقع اللغة.


    عيوب لغة كلمات:
    و لكن علي الرغم من كل تلك الميزات التي لها، إلا أن كلمات لها عيوبٌ تجعلها لا ترضيني علي الإطلاق، و منها:
    1. اللغة من نوع اللغات ذات التنويع المتغير dynamically typed، و هذا النوع لايصلح لكتابة البرامج التي تحتاج إلي سرعاتٍ فائقةٍ في التنفيذ، و كذلك يساعد في الوقوع في أخطاء التكويد المنطقية لأن اللغة لا تقيد المتغير بنوع بياناتٍ معين (يرجي مراجعة هذه النقطة في نقد لغة السوبرنوفا).
    2. اللغة تحتوي علي مكونين في غاية التشابه هما:
      • الإجراء.
      • الدالة.
        و كان يجب ألا تضم اللغة مكونين متشابهين كهذين علي الإطلاق؛ حيث أن هذا لا داعي له منطقياً، بل و يسبب تشابهُّما الشديد إلي البلبلة عند المبتدئين و سنري مثالاً لهذا عند التحدث عن العيب رقم 5، و كان من الأفضل ضم هذين المكونين في مكونٍ واحدٍ أشمل و أقوي من كليهما (و كان يمكن لكلمات أن تحتوي علي الإجراءات فقط، و لكن مع الاهتمام بأن تأخذ الإجراءات كل جوانب القوة التي تُغْني عن كل مثيلاتها).
    3. اللغة تحتوي علي مكوني:
      • المصفوفات arrays
      • القواميس dicts
        و كان بالإمكان ضم هذين المكونين في مكونٍ واحد، و هذا سيسهل علي المبتدئين كثيراً لأنه يضم المكونات المتشابهة التكوين و الوظيفة في مكونٍ واحدٍ أشمل (هذه نقطة نقدٍ فرعية لكنها موجودةٌ بالفعل).
    4. الدوال و الإجراءات في كلمات ضعيفة البنية؛ فهي:
      • تعيد خرجاً واحداً فقط (في حالة الدالة، أما الإجراءات فلا يفترض أن تعيد مخرجاتٍ من الأصل).
      • لا يمكن إعطاء قيمٍٍ ابتدائيةٍ لمدخلات الدالة أو الإجراء، و هو الأمر الذي كان بإمكانه تيسير العمل بها بشدة و خاصةً في المشاريع الكبيرة.
    5. الفصائل في كلمات ثرثارة؛ فلكي تُعَّرِّف محتويات فصيلةٍ ما فيجب عليك كتابة كلامٍ كثير، و هو علي الرغم من كونه أقل مما هو عليه في حالة لغات مثل الـEiffel إلا أنه أكبر من المعتاد في اللغات الأخري (مثل لغة الـpython، و هي اللغة التي تأثرت بها كلمات بشدة).
      مثال1:
      مثال2:
    6. تحتوي كلمات علي أوامر "علامة" و "اذهب إلى"، و اللذين يكافئان "Goto" في اللغات الإنجليزية، و أنا أرفض هذين الأمرين لأنه من الممكن الاستغناء عنهما و استخدام مكوناتٍ أخري لتؤدي عملهما (الحلقات التكرارية و الجمل الشرطية)، و كذلك فهما يسببان الإرتباك في الكود عند استعمالهما بغزارة (يرجي مراجعة ترجمتي لخطاب Goto statement considered harmeful للبروفيسور ديجكسترا، و الذي أرسله للنشر فى مجلة (Communications of the ACM, Vol. 11, No. 3, March 1968, pp. 147-148).
    7. تعبير الحلقات التكرارية ضعيفٌ للغاية، حيث لا يتيح تغيير مقدار الخطوة في العملية إلا بقيمة زيادةٍ مقدارها 1 (و قد نبه م. محمد سامي إلي أنه ينوي تدارك هذه الجزئية في الإصدارات القادمة بإذن الله عز و جل).
    8. المكتبة حتي الآن مبنيةٌ داخل المفسر نفسه، و ليست قائمةً بذاتها و ليست مكتوبةً بلغة كلمات نفسها بل بلغة الـ++C مع مكتبة الـQT.
    9. لا يوجد مترجمٌ قويٌ للغة حتي الآن، و كل ما يوجد هو مفسرٌ يتيح لنا استخدام بعض مكونات مكتبة الـQT، و هذا أمرٌ مرفوضٌ لأننا نحتاج إلي كتابة المكتبة الخاصة باللغة كاملةً بها نفسها ليتسني لنا نقل هذا الجزء من العلم البرمجي إلي العربية. و لكن المشكلة أنه لا يمكن كتابة مكتبة كلمات بها نفسها كما سيلي في العيب العاشر.
    10. لا يمكن كتابة أوامرٍ بلغة التجميع assembly في برنامج كلمات، و هذا يجعلها غير قادرةٍ علي:
      • إنتاج مكتبتها باستخدامها هي نفسها.
      • إنتاج برامجٍ تعمل علي المتحكمات الميكروئية microcontrollers
      • كتابة البرمجيات الأخري التي نحتاج فيها إلي التعامل مع الذاكرة مباشرةً، مثل:
        1. أنظمة التشغيل.
        2. المترجمات compilers.
        3. المفسرات interpreters.
    11. الوحدات في كلمات تتيح لنا إنشاء إجراءاتٍ و دوالٍ حرة (أي لا يلزم أن تكون مكتوبةً في فصيلةٍ ما)، و هو ما يجعلنا نعاني من مساوئ نموذج البرمجة الإجرائية في المشاريع الكبيرة، و هذه الصفة تناقض مبدأ الأمن الذي نريده في لغة البرمجة القوية.
    12. اللغة لم تستقر في تصميمها بعد، و لم توضع لها خطةٌ توضح حجمها النهائي المتوقع حتي الآن، ونحن نري بالفعل أن اللغة يزيد حجمها يوماً بعد يوم.
    13. ليس فيها تعبيرٌ لمعالجة الاستثناءات exception handling.
    14. الوصول إلي مكونات الفصيلة غير مُوَحَّد الشكل، فنحن نصل إلي المتغير الداخلي للكائن عن طريق كتابة اسمه ثم كتابة اسم الكائن بعده، مثال:
      حيث م هو كائن object فيه ثلاث متغيراتٍ هي: اسم، سن، عنوان.
      أما الإجراءات و الدوال فيجب أن يكتب اسم الكائن أولاً، ثم نتبعه بعلامة : ثم اسم الإجراء أو الدالة. مثال:
      حيث ق هو الكائن، و اضف هو الإجراء أو الدالة.
    1. لا تحتوي علي مكونٍ هامٍ للغاية هو التعدادات enumerations 
    2. لا تحتوي علي فكرة الـتفويض delegating (الموجود في لغاتٍ مثل الـ#C).


      نهايةً: فكلمات علي الرغم من نقدي لها و العيوب التي أراها فيها (و بعضها ليس عيباً كبيراً كما رأيتم)، فيمكنني أن أقول ثانيةً أنها أفضل اللغات البرمجية العربية الحالية علي الإطلاق، و أنها نواةٌ جيدةٌ للغاية للغة برمجةٍ احترافيةٍ من الطراز الأول، و لا أملك حالياً إلا الدعاء لمصممها بكل التوفيق في مسعاه.