الأحد، 23 ديسمبر 2012

حين تتحقق خطط المدى البعيد

حين كنت أعمل في صنع لغة كلمات سنة 2010 كانت هناك بعض القرارات التي اتخذتها في تصميم وتنفيذ اللغة. بعض هذه القرارات قد بدأت تظهر آثاره الآن!

حين يسمع كثير من المبرمجين عن مصطلح "software design" فإن ما يأتي على بالهم هو "UML Class diagram"، ولكن تصميم البرامج له نواح أخرى كثيرة، وربما يفيد عرض بعض قراراتي في "كلمات" في توضيح بعض هذه النواحي.


القرار الأول: عن تسريع لغة بطيئة

أثناء تنفيذ مفسر كلمات لم أهتم كثيراً بسرعة الكود بقدر اهتمامي بسرعة تطوير اللغة: كنت أخزن المتغيرات في عناصر QMap الموجودة في مكتبة Qt، كنت أستخدم عناصر QStack في أي مكان أحتاج فيه لمكدس (stack). كانت هناك أخطاء بديهية (من ناحية السرعة) في كل مكان في الكود. وتركتها.

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

السبب الثاني هو أنني كنت أتوقع أنه عند الاحتياج لتسريع اللغة فإن هذا الأمر سوف يكون ممكناً. هناك نوعان من مشاكل السرعة في لغة البرمجة: مشاكل خاصة بمترجم أو مفسر اللغة (implementation specific)، ومشاكل خاصة باللغة نفسها لا يكاد يمكن لأي مفسر التغلب عليها (language semantic specific).

[نقطة جانبية: هناك أحياناً لغات يوجد بها "مبطئات" في تصميمها نفسه لكن يأتي مبرمجون عباقرة يصنعون implementations تتغلب على هذا البطء. مثلاً لغة جافاسكربت لها أسباب كثيرة تبطئها، لكن الجهد الذي قامت به جوجل في مفسر V8، أو موزيلا أو أبل في مفسراتهم، جعلت تنفيذ جافاسكربت أسرع بكثير مما كان متوقعاً. وحتى في هذه الظروف هناك أشياء لا يمكن لأحد أن يفعل لها شيئاً؛ فمثلاً من أحد أسباب إطلاق جوجل للغة Dart أنهم يريدون لغة تسلّم نفسها للتسريع أكثر من جافاسكربت].

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

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

القرار الثاني: عن حركة المؤشر المنطقية

كانت هناك خاصية مزعجة في محرر كلمات: حركة المؤشر منطقية وهذا يؤدي لالتباس عند الأطفال الذين يتعلمون البرمجة بها. قبل أن نكمل سأتحدث عن معنى "حركة المؤشر منطقية".

تخيل أننا نحرر هذا النص:

كلمة أم بالإنجليزية معناها ·Mother

تخيل أيضاً أن هذه النقطة السوداء هي مؤشر التحرير cursor. ماذا يحدث لو ضغط المستخدم زر الحركة لليسار؟ سوف تجد أن مكان المؤشر قد صار هكذا:
كلمة أم بالإنجليزية معناها Mother·

لماذا حدث ذلك؟ لماذا قفز المؤشر بدلاً من أن يتحرك لليسار كما أراد المستخدم؟ لأن المحرر قد فسر الأمر بصورة معينة: إنه يعتبر أن المستخدم لم يرد التحرك حقاً لليسار، بل أراد في الواقع التحرك للحرف التالي في النص الذي يُحرر، وكان هذا الحرف التالي - منطقياً - هو أول حرف في الكلمة التالية؛ أي حرف "M".

لماذا يسبب هذا الأمر مشكلة في كلمات؟ لأن الأرقام تكتب في أجهزة الكمبيوتر من اليسار لليمين مثل الكلمات الإنجليزية! فلو ضغط الطفل مثلاً هذه الأزرار في محرر كلمات ا ط ب ع 1 0 0 فسيكتب المحرر:

اطبع 100

..وهذا متوقع، لكن المشكلة في تحريك المؤشر. مرة أخرى، كما رأينا لو كان المؤشر هكذا:
اطبع ·100
وضغط المستخدم زر "يسار" فسيقفز المؤشر هكذا:
اطبع 100·
كما أن المؤشر لن يكتفي فقط بالقفز؛ سوف تكون حركته عكسية داخل الرقم: اليسار يمين واليمين يسار، وهذا يجعل تحرير الأرقام بعد كتابتها أصعب على المبرمجين الأطفال (والكبار في الواقع).

الذي نريده في كلمات هو حركة مؤشر مرئية وليست منطقية. ولكن مكتبة Qt لم تكن تدعم ذلك. ماذا كان قراري إذاً؟ كان، بكل بساطة، انتظار نسخة مستقبلية من مكتبة Qt تكون داعمة للخاصية المطلوبة.

وقد تحقق الموضوع في نسخة Qt 4.8 (واكتشفته متأخراً للأسف)، والآن يمكن أن تصبح حركة المؤشر مرئية في الإصدارة القادمة من كلمات (وربما يمكن إضافة اختيار بحيث تكون منطقية لمن يريد ذلك).

Supporting callbacks in FFI

ليس حديثي هنا عن قرار تصميميّ، ولكنه حديث يندرج تحت بند "التخطيط للمدى البعيد" على العموم. كنت قد أعلنت منذ أكثر من عام عن إضافة إمكانية FFI للغة كلمات. اسم الإمكانية هو اختصار لـforeign function interface، أو "واجهة للدوال الأجنبية". ببساطة هي إمكانية تسمح للغة مثل كلمات باستدعاء إجراءات من لغة برمجة أخرى هي في هذه الحالة لغة سي.

لكن كان هناك مكوّن هام ينقص تلك الإمكانية: إمكانية callback، أي أن يكون الاستدعاء بعكس الاتجاه المعتاد — دالة سي تستدعي دالة من كلمات. ما أهمية هذا؟ فكر في كيفية عمل مكتبة مثل OpenGL: نحن نريد في كلمات أن نكتب شيئاً مثل هذا:

حدد.دالة.الرسم(الإجراء رسم)

بحيث يمكن لمكتبة OpenGL أن تستدعي ذلك الإجراء المكتوب بكلمات حين تريد رسم شيء على الشاشة. المكتبة مكتوبة بالسي لكنها تريد "خدمة" من كلمات.

أعمل الآن في إضافة تلك الإمكانية أخيراً. لم تكتمل في صورتها النهائية بعد لكن...قد بدأت تعطي نتائجاً كما ترى في الصورة.

وإني متشوق حقاً للإصدارة القادمة من كلمات :)


ليست هناك تعليقات: