سلسلة من المقالات، احاول فيها تحفيز مبرمجي Visual Basic x.0 العرب الى مواكبة التيار والهجرة بلا عودة الى احد لغات اطار عمل NET Framework. عندما أذكر سمات اطار عمل NET. فلا تعتقد بأني سأتحدث عن مكتبة الفئات Class Library التي توفرها (رغم انها احد اعظم الاسباب التي تسيل لعاب المبرمجين للانتقال لها)، وذلك لاني اخاطب مبرمجي vb4arab.com وهم على قدر رفيع من الفهم واستيعاب الحقائق، فهم مبرمجين لا تخدعهم المظاهر، لانهم يعلمون علم اليقين انهم يستطيعون بناء عشرات –ان لم يكن مئات- الفئات التي تغلف Encapsulate إجراءات API، وبذلك يستطيعون تطبيق كل شيء تعجز عنه لغة VB6. لذلك، ان اردنا معرفة القصور الحقيقي لـ Visual Basic، فدعنا نركز حديثنا حول لغة البرمجة والإمكانيات الداخلية والخاصة بها. السطور التالية كلفتني أكثر من 3 ساعات لكتابتها، حيث تعمدت عدم ترجمة أي مقال اجنبي لتأتيكم كلمات من مبرمج عربي منكم وفيكم: 1) لكل شيء ملف من الأشياء التي تغيظني في VB6 هو اسلوبه الغبي في توزيع الشيفرات المصدرية على الملفات، فلكي تعرف وحدة برمجية Module ستحتاج الى ملف خاص بها (حتى لو كانت الوحدة تشمل سطر واحد فقط)، وان اردت تضمين شيفرات لمكتبة صممتها في مشروعك، وكانت إجراءات هذه المكتبة موزعة على وحدات برمجية، فلك ان تتخيل كثرة الملفات والتي ستكون في مشروعك. اما مع VB.NET فيمكنني تعريف ملف واحد فقط يشمل جميع الوحدات البرمجية: ** VB.NET ************** Module MathFunctions … … End Module Module ArabicLanguageFunctions … … End Module Module BusinessFunctions … … End Module لو كانت المسألة تقتضي على الوحدات البرمجية لهان الامر كثيرا، ولكن القضية تشمل كل شئ (نوافد النماذج Forms، فئات Classes، ادوات تحكم UserConstrols، ...الخ) ومما يزعجني اكثر ان كل ملف له امتداد خاص –رغم انها تكتب جميعها بلغة واحدة VB6، اما مع VB.NET فجميع الملفات (البرمجية) تنتهي بالامتداد vb، كما يمكن للملف ان يشمل وحدات برمجية Modules، فئات Classes، ادوات Controls وكل شئ يتبع للغة البرمجة. ليس هذا فقط، بل حتى بعض محتويات الملف تكون مخفية (كمواصفات الفئات Classes Attributes، بيانات مصمم النماذج Form Designer). فلو اردت نسخ شيفرات مصدرية من فئة الى فئة اخرى، علي نسخ الملف الكامل للفئة. اما مع VB.NET فما اروع المفاتيح Ctrl+V <- Ctrl+C <- Ctrl+A وتنتهي الحكاية. 2) الإجراءات المفوضة Delegate Procedures الاجراءات المفوضة هي إجراءات يتم استدعائها عن طريق متغيرات تكون بمثابة مؤشرات لها (ان كنت من مبرمجي C فهي تشابه مؤشرات الدوال Function Pointers الى حد كبير). من الانجازات التي كانت اختراعا عظيما لمبرمجي VB6 هو دعم الكلمة المحجوزة AddressOf والتي تعود بمؤشر الاجراء. هل تعرف كيف يمكنك الاستفادة منها؟ في الحقيقة لا يفضل مبرمجي VB6 استخدامها لسببين: الاول خوفهم من ممازحة المؤشرات (وهذا من حقهم)، والسبب الثاني امكانية استدعاء الاجراءات بشكل مباشر. ولكن الحقيقة –المرة- ان كل هذه الاسباب لا اساس لها من الصحة، حيث ان VB6 لا يمكنك من الاستفادة منها !!!!!! عجبا على هذا الغباء! لماذا يدعم كلمة المحجوزة لا يمكنك استخدامها؟ والسبب انه (قد) تلجأ الى اجراءات API والتي تستخدم الردود CallBacks، التصنيف الفرعي SubClassing، أو خطف الرسائل Message Hooking، وهي مواضيع جعلتني اترك البرمجة بلغة C لصعوبتها. وكأن VB6 يقول لك: عد الى برمجة API الاجرائية المعقدة فقد وفرت لك كلمات محجوزة لها! وماهي فائدة VB6 اذا ان كان هذا هدفه، فالتعامل مع اجراءات API باستخدام لغة C اسهل بعشرات المرات من VB6 !!! ولكن مع VB.NET فهو يقول لك: وفرت لك الكلمة المحجوزة AddressOf ليس فقط لاستدعاء الإجراءات المفوضة، بل ايضا يمكنك تطوير إجراءات مفوضة خاصة بك باستخدام لغتة برمجتك المفضلة VB.NET -كما تفعل اللغات المتقدمة الاخرى. وهذا امر بديهي، حيث عندما ادعم ميزة في لغتي علي ان اجعل المبرمج قادر لاستخدام هذه الميزة بنفس لغتي (وليس لاستخدامها مع لغة اخرى). 3) تعارضات وتوزيع اسماء المعرفات Identifiers عندما تعرف فئة باسم Point فسيكون هذا الاسم محجوز لها دائما، ولن تتمكن من استخدامه ابدا. ولكن هب –مثلا- ان الغرض من الفئة Point هو تمثيل الاحداثي x و y لنقطة على سطح ثنائي الابعاد، واردت استخدام –نفس الاسم Point- لتمثيل نقطة على سطح ثلاثي الابعاد، فقد تسمي الفئة الجديدة بالاسم Point3d او PointEx او أي شئ اخر. حسنا، ماذا لو وجدت مئات الفئات في برنامجك؟ فاعتقد ان موضوع التسمية سيكون مشكلة كبيرة، حيث تكثر اسماء الفئات بعد كتابة العبارة As New، وتصبح مسألة البحث عن الفئة كالبحث عن مسمار في محيط. اما مع VB.NET، فهو يدعم فكرة مجالات الاسماء NameSpace، حيث يمكنك من توزيع فئات على شكل شجري يسهل عليك ترتيب وتقسيم اسماء المعرفات، لتتمكن من كتابة شيئا مثل: ** VB.NET ************** Dim X As New Animals.Mouse Dim Y As New Hardware.Mouse 4) هل تود اضافة شيفرة بلهجة اخرى؟ في الحقيقة، كانت لغة C هي اللغة الوحيدة التي تمكنك من اضافة شيفرات بلغة Assembly مع برنامجك، ولكن مع اطار عمل NET. (بشكل عام)، فجميع لغات البرمجة موحدة في بنيتها التحتية، وذلك بسبب معايير Common Language Runtime – CLR. لتتمكن من دمج شيفرات مصدرية بلغات برمجة مختلفة في برنامج واحد. 5) اسناد القيم لحظة التصريح قد لا يكون هذا قصور كبير في VB6 –هذا في حال المتغيرات البسيطة: ** VB6 ************** Dim X As Integer X = 5 وقد لا يكون قصور كبير حتى لو كثرت المتغيرات: ** VB6 ************** Dim A As Integer Dim B As Integer Dim C As Integer Dim D As Integer A = 5 B = 10 C = 15 D = 20 ولكن عند الحديث عند الحديث عن المصفوفات الديناميكية: ** VB6 ************** Dim X As String () Redim X (2) X(0) = "عباس السريع" X(1) = "برعي ابو جبهة" X(2) = "زكريا زعتر" فليس فقط تتطلب منك سطور اضافية، بل حتى لو اقمت علاقة صداقة جديدة واردت اضافتها مع الشلة السابقة، عليك اعادة تعديل الشيفرة والخاصة بـ Redim : ** VB6 ************** Dim X As String () Redim X (3) X(0) = "عباس السريع" … … X(3) = "عبود اللوح" ضع في عين الاعتبار، ان الشيفرة السابقة تستهلك وقت اضافي –سواء لكتابتها او تنفيذها- ولاتنسى انها تتطلب وضعها داخل اجراء Sub او Function (فهي شيفرات برمجية). اما مع VB.NET فيمكنك بخطوة واحدة ومن أي مكان في برنامجك (حتى خارج الاجراءات) كتابة شيئا مثل: ** VB.NET ************** Dim X() As String = { "عباس السريع", "برعي ابو جبهة", "…", "…" } 6) انا اسمي "تركي العسيري" "تركي العسيري" "تركي العسيري" !!! لماذا التكرار؟ في العقود الاخيرة، اصبح التعامل مع النصوص الحرفية امر لا يكاد ان يخلو احد اجراءات برنامجك منه، فنحن في زمن التدفق او الانفجار المعلوماتي، وكل مزايا برامجك لابد ان تتعامل مع النصوص، صحيح ان VB6 كان يستعرض عضلاته في اعطائنا امكانية تعريف متغير حرفي حجمه يزيد عن 2 جيجابايت، ولكن طريقة ادارته لها فاشلة جدا، فاي عملية اسناد بين المتغيرات الحرفية تؤدي الى نسخ القيمة الحرفية وتكرارها في الذاكرة: ** VB6 ************** Dim X As String Dim Y As String X = "تركي العسيري" ' الان لدينا نسختين من القيمة ' الحرفية في الذاكرة Y = X اخي العزيز، الامر ليس مقصور على القيمة "تركي العسيري" فهي لا تكلف سوى ( (12 * 2) * 2 = 48 بايت)، ولكن عند التعامل مع النصوص الطويلة جدا (كالموجودة في الملفات النصية، الحقول Memo في قواعد البيانات، او مستندات XML) فهي بحاجة الى تفكير جدي اكثر في الموضوع. اما مع VB.NET فلديه من الذكاء الذي يستحق التقدير والاحترام، حيث ان القيم الحرفية تمثل كائنات من النوع المرجعي Reference Type، وفيه ميكانيكية فائقة الروعة بحيث لا تنسخ القيم الحرفية ان تساوت لاكثر من متغير (سواء لحظة الترجمة او التنفيذ): ** VB.NET ************** Dim X As String = "تركي العسيري" Dim Y As String = "تركي العسيري" ' القيمة مكررة مرة واحدة فقط Console.WriteLine ( X Is Y ) ' True ذكاء VB.NET اكبر مما تتصور، حيث يشمل ويتحقق من كامل القيمة –حتى وان استخدمت معامل الدمج: ** VB.NET ************** Dim X As String = "العسيري" & " " & "تركي" Dim Y As String = "تركي العسيري" ' القيمة مكررة مرة واحدة فقط Console.WriteLine ( X Is Y ) 'True 7) اضافة/حشر/حذف/تعديل القيم الحرفية قد لا يعلم الجميع، ان كل عملية تعديل على متغير حرفي تستهلك وقت وجهد اضافي: ** VB6 ************** Dim X As String X = "عباس" ' تتطلب حجز مساحة اضافية ' في الذاكرة قبل الاسناد X = X & " " & "السريع" ولا شك ان الامر يظهر عيبه وبطئه الكبير مع الحلقات التكرارية، قد يأتي احد الاشخاص ويخبرني باستخدام المتغيرات الحرفية ثابتة العدد Fixed-Leangth-Strings: ** VB6 ************** Dim X As String * 50 X = "عباس" ' هنا اسرع بكثير X = X & " " & "السريع" فكرته لابأس بها ولكن دعني اريك عيوب هذا النوع من المتغيرات: * تضيف مسافات Spaces دائما في المناطق غير المستخدمة (مما يكلفك استخدام دوال حذف المسافات كـ Trim والتي تستغرق بدورها وقت اضافي). * ليست متوافقة مع تقنية COM. * ليست متوافقة مع إجراءات API. * ليست متوافقة مع مجموعة كبيرة من دوال مكتبة VBA و VB (رغم انها تتبع وخاصة بلغة VB6!)، حيث تقوم اما بتحويلها الى المتغيرات Strings العادية او لا تقبلها. * لا يمكن لهذا النوع من المتغيرات ان يعرف على مستوى Public في الفئة او نافذة النموذج. (أي لن تستطيع ان تصله الى العالم الخارجي) * اقصى عدد من الحروف الذي يمكن ان يحملها هو 64 كيلوبايت ( اين الـ 2 جيجابايت يا VB6 ؟؟!!) 8) عرف هنا ولكن لا تعرف هناك، كما يمكنك هنا ولكن لا تستطيع هناك!! من الامور التي لا اعلم كيف كنت اصبر عليها، قوانين قابلية الرؤية Visibility لمعرفات البرنامج، حيث لا توجد صيغة موحدة المعايير ومفهومة المنطق استطيع ان ابني برامجي على اساس سليم لها، فكل معرف له حالة خاصة، واسلوب خاص، الامر الذي يجعلني افتح نسخة ثانية من VB6 على سطح مكتبي حتى اجرب قبل ان اعتمد التصميم. خذ مثلا شروط قابلية الرؤية للتركيبات: * يمكنك تعريفه كـ Private لحصره على الوحدة و Public ليشمل باقي انحاء المشروع. * لا يمكنك استخدام Public ان كان في نافذة نموذج. * يمكنك استخدام Public لتعريف تركيب في الفئة دون أي مشاكل. * ان عرفت تركيب باستخدام Public في وحدة برمجية Module، فيمكنك استخدامه دون أي مشاكل، ولكنك لن تستطيع تعريف اجراءات Subs او Function تستقبل وسيطة Parameter من نفس نوع التركيب ان كان الاجراء على مستوى Public (يمكن ذلك ان كان الاجراء على مستوى Private او Friend) افففففففففففففف! كيف يمكنني حفظ كل هذا؟ وماذا عن المصفوفات هل يمكن تعريفها Public ؟؟؟ والله لقد نسيت ولكني اعتقد ان المصفوفات الديناميكية ممكن اما الستاتيكية فلا – او العكس !! اما مع VB.NET فكل هذه السخافات ليست في مستنداته، حيث يوفر لك الكلمات المحجوزة Private، Friend، و Public والتي تتبع قانون ومعييار موحد لكافة انواع المعرفات –دون أي حالات شاذة. كانت هذه ملخص جولتي السريعة حول بعض –وليس كل- قصور لغة VB6 في ابسط اساسيات لغة البرمجة، قريبا سنتعرض الى تفاصيل اكثر حول تعريف الفئات Classes وسأريكم فضايح من تحملون رايته Visual Basic x.0 !! -- تركي