الأربعاء، 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. الدامجات أكثر كفاءةً من استدعاء الإجراءات التى تُحَوِّل بين أنواع المتغيرات. أى أنه بدلاً من استدعاء إجراءات التحويل بين أنواع المتغيرات فى كل مرةٍ نحتاج فيها إلى تحويل قيمةٍ ما من نوعٍ إلى نوعٍ آخر فإننا نستخدم المتغيرات الموجودة فى الدامج مباشرة، و نستخدم منها ذلك الذى له النوع الذى نرغب فى التعامل مع القيمة على أساسه.
    و هذا قولٌ آخرٌ ضَعُفَ بتغير الزمن، حيث أن مثل هذه التوفيرات الغريبة لا تُقدم تلك النتائج الخارقة التى تُغرى ببذل الجهد و التضحية للحصول عليها؛ فما الذى سيضر البرنامج إذا ما استدعى إجراء تحويلٍ عشر مراتٍ أو أكثر ؟! و ما التأخير الذى سيحدث عندئذٍ و كيف سيؤثر ذلك التأخير على زمن تنفيذ البرنامج بصورةٍ  و لو طفيفة ؟!

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

  1. السلام عليكم أخي وائل.
    بعد قراءة موضوعك، بحثت عن الدامجات في لغة أوبجكت باسكال، ووجدت أن فري باسكال قد دعمت هذه الميزة، لكن لا أدري هل تدعمها دلفي أيضاً أم لا.
    ووجدت أني احتاج لها في النقطة رقم (2) وهي عند تحويل البيانات الذي احتاجه كثيراً في اﻹتصالات، عند إستلام packet عبر الـ socket، أحياناً أقوم بتحويل أو قلب الأرقام.
    وهذا مثال قمت بكتابته بإستخدام الدامجات في فري باسكال:

    type
    MyUnion = record
    case Byte of
    0: (Left, Right: Byte);
    1: (Value: Word);
    2: (SignedValue: SmallInt);
    end;
    var
    x: MyUnion;
    begin
    x.Left:= 0;
    x.Right:= 1;
    Writeln(x.Value); // 256
    x.SignedValue:= -1;
    Writeln(x.Value); // 65535
    Writeln(x.Left); // 255
    Writeln(x.Right); // 255
    Readln;
    end.

    ردحذف
  2. مرحباً أخي أبوإياس، دمت مفيداً و مستفيداً ^_^
    بالنسبة لمثل هذه التعاملات فلها أكثر من حل:
    1- استعمال لغة التجميع assembly في أكواد اللغة عالية المستوي.
    2- وجود دوال في المكتبة القياسية للغة البرمجة تتيح مثل هذه التعاملات.
    و أنا بطبعي أميل إلي الحل الأول؛ لأن إتاحة الفرصة للكتابة بلغة التجميع سيعطينا إمكاناتٍ تفيد في مواقف أخري غير هذه، لكن بالطبع مع إتقان كيفية السماح بوجود هذه الأكواد وسط البرامج المكتوبة باللغة عالية المستوي.
    و ما دام هناك حلٌ بديلٌ فلا أري حتي الآن داعياً لوجود الدامجات. و الأفضل الاقتصار علي المكونات التي لا بديل لها.

    ردحذف
  3. الحقيقة أن هناك مجموعةً كاملةً من المكونات المترابطة تغنينا عن الدامجات و غيرها من المكونات التي لا أري ما يدعو لوجودها في اللغات العالية المستوي عامة الأغراض، لكن المشكلة أنني لا أستطيع تقديم كافة البدائل الآن؛ لأنني مشغولٌ جداً في مشروعٍ ضخم، و كذلك لأن الرد الوحيد هو الرد العملي لا النظري، و هذا له وقته و لا يمكنني تقديمه الآن ^_^

    أرجو ألا تحرمني من زياراتٍ أخري :)

    ردحذف