الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

ال Dynamic Typing و ال Static Typing في سطور!

بدأه Khaled.Alshaya في 24 أبريل 2010 · 3 رد · 6,165 مشاهدة · في المقالات العلمية و التقنية
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

بسم الله الرحمن الرحيم,

في الجزء الأول من هذا الموضوع, بدأنا حديثاً موجزاً عن الـ Type Safety و الـ Strong Typing في مقابل الـ Weak Typing.و حديثنا في هذا الموضوع عن الـ Static Typing في مقابل الـ Dynamic Typing. الغريب أنك إن لم تكن قرأت من قبل حول هذا الموضوع في مصادر "حقيقية" فسيصبك الإحباط, لتناقض المعلومات حوله. إذاً ماذا نعني عندما نقول أن هذه اللغة Statically Typed؟ و ماذا نعني عندما نقول أن هذه اللغة Dynamically Typed؟ لربما كانت الإجابة على "طرف لسانك" لو أنك قرأت عن الموضوع من قبل, و لكن: هل الإجابة هي أن كل لغة مترجمة هي لغة Statically Typed و كل لغة مفسرة هي Dynamically Typed؟! ماذا عن اللغات المترجمة وقت الشغيل Jitted!!!

الـ Dynamic Typing عندما نتكلم عن أقصى معنى لها, تعني أن أي متغير في البرنامج النهائي أو بمعنى أصح at run-time يحمل جميع المعلومات الأخرى غير القيمة التي يحملها أساساً, مثل اسمه "التمثيل النصي لاسمه", نوعه, حجمه, الأنواع التي يرثها كما في OOP, و هكذا و عندما تكون اللغة Dynamically حتى النخاع فإن جميع المعلومات التي يمكن أن تستقيها من الكود يمكن أن تحصل عليها أو تعدلها بطريقة أو بأخرى عند تشغيل البرنامج at run-time. فالمتغير ليس فحسب, مكاناً توضع فيه قيمة و حسب و إنما data structure متكاملة تحمل جميع المعلومات التي تحددها اللغة إضافة إلى القيمة التي يفترض أن يحملها. هذا الأمر يوفر ميزات كثيرة و عيوب كثيرة أيضاً, فالعيب واضح, فلن يعود بإمكاننا استخدام الذاكرة بشكل كفؤ لأن المتغير يملأ حيزاً كبيرة, و ربما يكون حجم تلك المعلومات الإضافية أضعافاً مضاعفة من الحجم اللازم لحمل قيمة عدد صحيح int مثلاً. هذا الأمر يظهر عندما يكون البرنامج يعالج كمية كبيرة نسبياً من البيانات. و لكن الميزات كثيرة! فمثلاً تصور أننا نستخدم لغة تشبه ++C في الـ Syntax و لكنها Dynamic و أردنا كتابة دالة تقوم باستدعاء دالة تسمى print لكائن ما:

void call_print(object)
{ object.print(); }

هل ترى! الـ Generic Programming في أوج عظمتها :)

سيتم البحث عن دالة اسمها print في معلومات الكائن المسمى object, ثم سيتم إحضار عنوانها و يتم ندائها, و في الغالب العمليات أكثر تعقيداً و اللغة تصبح مرنة إلى أبعد الحدود. لكن هناك سؤال, هل تستطيع دفع تكلفة ظهور الأخطاء وقت تشغيل البرنامج؟ في المقابل ستحصل على مرونة إلى حد أن هناك مبرمجون, يفضلون الـ Prototype Inheritance على الـ Classic Inheritance! الأولى لـ SmallTalk و هي لغة Dynamic و الثانية لـ Simula و هي المعتادة في اللغات الـ C-Like. الـ prototype inheritance هي مثال حقيقي على الـ Dynamic Typing, فأنت تأخذ كائن و لنقل أنه person, و تضيف عليه متغيراً اسمه student_number و تضيف دالتان get و set و أصبح لديك كائن جديد, و لا تنسى كل هذا تم عند تشغيل البرنامج!

الـ Static Typing, على النقيض تعني أن المتغير يحمل معلومات أقل عن نفسه وقت التشغيل. قد يكون هذا التعريف غامضاً قليلاً, و لكن في أول الطيف هناك C و ++C حيث لا يحمل أي متغير عن نفسه أي شيء في الذاكرة على الإطلاق. و لا يوجد في اللغتان أصلاً طريقة لمعرفة وجود متغير معين من عدمه في الناتج النهائي عند الحديث عن الـ Optimized Code للمترجمات الشهيرة. هذا هو السبب الحقيقي لكون C و ++C لغات Efficient أكثر من اللغات الحية الأخرى لمهمات كصناعة المترجمات و الـ RDBMS حيث كميات البيانات خيالية. لربما كان من الغريب لمعظم دارسي C معرفة أن المصفوفات لاتحمل حتى حجمها معها في الذاكرة! هذا مصطلح أطلق عليه الأستاذ Stroustrup مايسمى بالـ Zero Overhead Principle :) في مترجمات اللغات الأكثر حداثة, كـ Java و #C و غيرهم يتم إضافة معلومات إلى الأنواع و لكنها بسيطة مقارنة بالمعلومات التي يتم إضافتها للمتغيرات في لغة Dynamic حتى النخاع كـ Python. ميزات الـ Static Typing واضحة, و عيوبه واضحة, و لكن بشكل عام الـ Static Typing تظهر محاسنها كلما كان حجم المشروع أكبر. فالمترجم بجانب المبرمج لاكتشاف أخطاء ربما تكون تافهة و لكنها غير ظاهرة كجمع نص مع عدد في حالة كون اللغة strongly typed مما يؤدي إلى خطأ وقت التشغيل بدلاً من إعلامنا بذلك مبكراً. الجميل في الأمر, أن هناك اتجاهاً نحو ما يسمى بالـ Reflection في اللغات الـ Statically Typed, و هذا بكل بساطة يعني أننا نستطيع الاستعلام عن بعض المعلومات المتوفرة عن المتغير و لكن لا يسمح لنا بتعديلها كما في اللغات الـ Dynamic الخالصة.

ربما كنت قد أصبت بالإحباط عند وصولك إلى هذا السطر لأنني قلت: "فمثلاً تصور أننا نستخدم لغة تشبه ++C و لكنها Dynamic"

فأنا قد أكدت في الموضوع السابق أن هذا الأمر لا علاقة له بلغة البرمجة نفسه و إنما بالـ Implementation المستخدم!

في الحقيقة أن الجملة السابقة صحيحة و لكنها تحتاج إلى توضيح...

عندما نستخدم مفسراً, فإن اللغة تصبح Dynamic لأن المفسر بطبعه يحمل جميع المعلومات عن الكود وقت التشغيل. بينما لو استخدمنا مترجماً, سيكون لدينا حالتان: الأولى هي أن يقوم المترجم باستخدام المعلومات التي استخلصها في الكود لترجمة البرنامج إلى منصة معينة دون إلحاق معلومات المتغير, و الحالة الثانية هي أن يقوم بإلحاقها! و في هذه الحالة تصبح اللغة Dynamic حتى باستخدام مترجم! لربما كان أوضح مثال هو عند بناء برنامج بلغة C مع تفعيل خواص الـ Debugging, في حينها ستصبح جميع المعلومات متوفرة في الناتج النهائي, و عند تفعيل خواص الـ Optimization فإن جميع المعلومات كأنها لم تكن أصلاً! هذا المثال ليس مثالاً محبذاً لدى الكثيرين عند الحديث عن الـ Dynamic Typing لأن اللغة في الحقيقة لاتوفر طرقاً للاستعلام عن تلك المعلومات من داخل اللغة نفسها وليس عن طريق برنامج خارجي على سبيل المثال. هذا يقودنا إلى الفقرة القادمة...

دائماً عند وضع تعريف لشيء ما, فلابد أن تجد له ثغرات, و خصوصاً عند الحديث عن موضوع شائك كهذا! لابد أن تعي أن اللغات عندما تبنى فإن صاحبها على الأغلب يضع في الحسبان كونها ستصبح لغة مفسرة أو مترجمة, و بالتالي فإن هناك لغات ملائمة أكثر بطبعها للـ Dynamic Typing و هناك لغات ملائمة أكثر للـ Static Typing. ما نريد أن نصل إليه هو أن هناك لغات توفر مرونة في أنواعها, يصبح إنتاج مترجم لها معدوم الفائدة, لأن المترجم عليه أن يضع معلومات ضرورية لتلك المتغيرات للتأكد من صحة العمليات. فمثلاً, هناك تجارب لإنتاج مترجمات لـ Python, و لكن طبيعة اللغة نفسها و مرونتها لا تسمحان للمترجم بافتراض شيء حول المتغيرات, و يصبح من شبه المحتم أن يلحق معلومات المتغير وقت التشغيل. بينما في لغات أخرى, فإن هذا الأمر ليس صحيحاً بالضرورة, فمثلاً هناك مفسرات للغة C و لغة ++C, و هناك مترجمات, و نفس الأمر ينطبق على Haskell و Ocaml على سبيل المثال لا الحصر. إذاً, الأمر يتعلق بالافتراضات التي وضعها صاحب اللغة. و لكن أتمنى عند وصولنا لهذه النقطة, أن نكون قد وصنا إلى اتفاق أن استخدام مترجم لايعني أن اللغة Statically Typed. و لكن عند استخدام مفسر فإن الأمر شبه محسوم, و لكن تظهر لنا حالة شاذة و هي كون المفسر المستخدم يقوم بإنتاج كود Jitter يتم تنفيذه بعد ذلك. في هذه الحالة المعلومات قد تكون موجودة قبل الترجمة الفورية و ربما يقوم بالتخلص منها في الكود النهائي. يمكن أن تضع "سيناريوهات" عن لغات تقع في الوسط! لا نريد أن نعقد الموضوع أكثر من ذلك فأنا قد تهت! هناك لغات اختارت أن يكون هذا الأمر صريحاً في اللغة نفسها, بمعنى أن اللغة تفرض وجود الأمرين معاً في نفس الوقت, و لكن هذا توجه حديث نسبياً, و هو أحد شواذ التعريف الذي وضعناه. فمثلاً, في لغة #C النسخة الرابعة, استحدث صانعوها ما يسمى بالـ Dynamic Type رغم أن لغة #C لغة Statically Typed عند النظر إلى مترجماتها الشهيرة. فلو نظرت إلى المثال التالي:

dynamic dynamic_int = 10;
int static_int = 10;

فمن المؤكد أن dynamic_int يحمل معلومات أكثر عن نفسه, و فائدة هذه الميزة لا تظهر إلا لو تخيلنا مثالاً أكثر تعقيداً كأن تقوم بتحميل مكتبة وقت التشغيل و من ثم تنادي دالة من أحد كائناتها دون حتى أن تعرف ماهو الكائن, و لا تخبر المترجم بماهية الكائن, و هل لديه تلك الدالة أصلاً؟ كل ذلك يتم وقت تشغيل البرنامج. بالطبع يمكنك القيام بذلك بدونها, و لكن المشكلة في الـ Static Typing أن المترجم لابد أن يعلم نوع الشيء الذي تريد استخدامه, و هذا الأمر قد يكون صعباً جداً في حالة كون الكود الذي تريد استخدامه بل ببساطة مكتوب بلغة أخرى كـ ++C مثلاً, و ربما تتضارب بعض الأنواع فيها مع #C. ببساطة هناك شخص قام بكتابة glue دون أن تراه كطبقة بين العالم الخارجي و بين متغيرك الـ Dynamic و سيحاول أن يبحث في المعلومات التي حصل من ذلك الكائن في العالم الخارجي لتطبيق ما أردته دون تعقيد أو حتى تفكير بماهية ذلك الكائن و هل من الممكن تمثيله بسهولة في اللغة أم لا. ضربت مثالاً آخر منذ مدة ليست بالقصيرة حول الـ Static Scope و الـ Dynamic Scope و كيف أن الـ Dynamic Scope يحتاج إلى Dynamic Types حتى يعمل. المثال تجده على الرابط التالي حتى نختصر الموضوع:

What is lexical scope?

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

تحياتي,

تم تعديل هذه المشاركة بواسطة Khaled.Alshaya في 25 أبريل 2010 في 12:31

15
#2

موضوع جميل وثرى بالمعلومات

بارك الله فقك وجزاك الله كل خير

لدى اكثر من اضافة احببت ان اشارك بها فى الموضوع للمساعدة فى التوضيح

---------------------------------------------------------------------------------------------

اولا : تعريف لغات البرمجة وطرق بنائها المختلفة

---------------------------------------------------------------------------------------------

لغة البرمجة اداة للتخاطب مع الحاسب واعطاءه التعليمات للتحكم به

لعمل هذه الاداة هناك اكثر من طريقة

1 - التطبيق عن طريق العتاد Hardware مثل لغة الالة Machine Language

2 - عمل مجمع مثل لغة الاسمبلى حيث هناك تعليمات يتم كتابتها ومن ثم اعادة صياغتها الى لغة الالة بشكل مباشر

3 - عمل مترجم او مفسر او كليهما معا وهذا فى حالة اللغات عالية المستوى

حيث طرق بناء لغات البرمجة عالية المستوى التى تعتمد على معالجة النصوص (الكود) ثلاثة طرق وهى

* بناء مترجم Compiler يقوم بالتحويل الى لغة الالة Machine Language او لغة اخرى مثل لغة C

* بناء مفسر يقوم بتنفيذ الكود مباشرة لاظهار النتيجة

* بناء مترجم Compiler يقوم بتحويل الى لغة وهمية او لغة وسيطة لانتعامل معها مباشرة ثم يتم بناء مفسر او الة صورية لتنفيذة تعليمات هذه اللغة الوهمية او الوسيطة وذلك يسمى Hybrid Implementation

اى التطبيق الخليط حيث تم عمل مترجم + مفسر فى نفس الوقت من اجل عمل لغة البرمجة

4 - عمل لغات برمجة بدون كود حيث تتم البرمجة من خلال التفاعل مع واجهة رسومية GUI بدلا من كتابة كود (نص Text) يتم معالجته.

ولعمل ذلك هناك ثلاثة طرق متعارف عليها

* طريقة Flow-chart

* طريقة Drag-And-Drop مثل تقنية Limnor

* طريقة Coding-Simulation مثل تقنية البرمجة بدون كود PWCT

-----------------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------

ثانيا : المرونة فى اللغات الديناميكية التى تتبع الـ Dynamic Typing يمكن زيادتها

-------------------------------------------------------------------------------------------------------------------

نعم يمكن زيادة هذه المرونة وبشكل كبير على ماهى عليه الان و يمكن ان نضع فى الاعتبار مثلا لغة بايثون Python و روبى Ruby

حيث انهما من اللغات الشهيرة التى تستعمل الـ Dynamic Typing ولكن مازال هناك ميراث من اللغات القديمة فعلى سبيل المثال

فى لحظة ما من الزمن وقت التشغيل عندما يكون لدينا مصفوفة Array فان هذه المصفوفة تحتوى فى هذه اللحظة الزمنية على عدد معين من العناصر وليكن مثلا 10

هنا فى هذه اللحظة لايمكن ان نشير الى العنصر 15 وتتعامل معه لانه غير موجود وحتى يكتب لهذا العنصر الوجود لابد ان يكون هناك العناصر 11 و 12 و 13 و 14 اولا

حيث كل شىء محدد وثابت على مستوى اللحظة الزمنية لاننا نتبع اسلوب رياضى ومتسلسل فى التفكير ونعمل على اجهزة ذات امكانيات محددة (سرعة معالج محددة - ذاكرة محددة - الخ)

من جانبى ارى ان اتباع ذلك الاسلوب يقلل من الديناميكية ويجعلنا نتبط بالالة وبالرياضيات ولانترك الخيال ينطلق فى التعبير

فى رايى المتواضع يجب ان لايكون هناك الكثير من القيود حتى يتاح لنا بان نفكر ونعبر عن افكارنا بطرق جديدة اكثر مرونة

هذا جانب من جوانب (البرمجة بوصف الخيال) Programming With Fiction Description وسوف اوضح ذلك على نفس المثال

فى البرمجة بوصف الخيال يمكن لنا ان نتعامل مع اى عنصر فى المصفوفة فى اى وقت وبدون ان يرتبط وجوده بعناصر اخرى

يعنى فى حالة المصفوفة التى كانت تشتمل على 10 عناصر مستعملين فى لحظة ما يمكن لنا بعد هذه اللحظة

ان نتعامل مع العنصر 15 فى حين ان العنصر 11 و 12 و 13 و 14 غير مستعملين اساسا

ولاحظ انى ذكرت كلمة (غير مستعملين) ولم اقل (غير موجودين) لانه فى البرمجة بوصف الخيال كل شىء موجود سواء استعملته ام لم تستعمله

يعنى ان العنصر رقم 15 هو موجود ولكنه فى عالم المجهول بالنسبة لنا حتى نحتاج اليه ونستعمله

واذا طلبنا قيمة هذا العنصر قبل ان نستعمله فاننا نحصل على NULL ولا نحصل على ERROR

وكمثال عملى انظر للكود التالى الذى يستعمل المصفوفة Myarray وهى مصفوفة ذات اكثر من بعد - بشكل مباشر

Application title = "Array2"
I want window and the window title is Array2.
Window width = 350. window height = 300.

i want button and button caption = close. and button name = btn1.
button top = 230. and button width = 330.
btn1 mouseclick. instructions are you close window ok

i want listbox and the listbox left = 10. and listbox name = list1.
listbox width = 100.

i want listbox and the listbox left = 120. and listbox name = list2.
listbox width = 100.

i want listbox and the listbox left = 240. and listbox name = list3.
listbox width = 100.

[x]. = (1). and Do while [x] <= (10).
			[myarray]\[x]\(1). = [x].
			[myarray]\[x]\(2). = [x] x [x].
			[myarray]\[x]\(3). = [x] x [x] x [x].
			[x]. = [x] + (1).
		End while

[x]. = (1). and Do while [x] <= (10).
			list1. listbox selected 
			listbox must add from [myarray]\[x]\(1).
			list2. listbox selected 
			listbox must add from [myarray]\[x]\(2).
			list3. listbox selected 
			listbox must add from [myarray]\[x]\(3).
			[x]. = [x] + (1).
		End while

ويمكن تطبيق المثال على MS-Windows او Linux

ونتيجة التشغيل كالتالى

post-167987-1272142652193_thumb.jpg

والكثير من المرونة يمكن ان يتم على اللغات الديناميكية لتسهيلها وجعلها اقرب الى الخيال.

والله الموفق

2 −2
#3

أهلاً أخ PWCT Maker,

الإضافة التي تكلمت عنها هي إضافة رائعة جداً في الحقيقة, و لا يسعني إلا أن أهنئك إن كنت أضفت كل تلك الميزات دون اطلاع سابق على لغات أخرى, أي أنك رأيت الحاجة لمثل هذه الميزات. لانريد أن نوسع الموضوع ليشمل مواضيع أخرى, و لكن نريد المواضيع أن تكون متخصصة أكثر لكي تصبح أكثر فائدة, لذلك لاداعي أخي العزيز للكلام عن الـ Implementations بشكل عام, لأن هذا بحر لا ينتهي. بالنسبة للميزة التي تكلمت عنها حضرتك - و التي تعجبني شخصياً - تسمى في عالم لغات البرمجة: Lazy Evaluation. هذه الميزة موجودة في صلب Haskell و يمكن تطبيقها في لغات أخرى, و لكن للأسف تصبح أكثر بشاعة إذا لم يتوفر دعم في اللغة نفسها. هذه الميزة ليس لها علاقة بالـ dynamic types في الحقيقة, و هي تأتي على أشكال عدة إضافة للذي ذكرته أخي العزيز. نحتاج إلى مقال عنها... قريباً بإذن الله :)

#4

حضرتك صاحب الموضوع ومن حقك ان تحكمه فى الاتجاه الذى تراه صحيحا وانا معك باستمرار ان شاء الله من اجل التعاون المثمر وربنا يوفقنا جميعا يارب

اقتباس

هذه الميزة ليس لها علاقة بالـ dynamic types في الحقيقة,

للتوضيح (ان العلاقة تكمن فى ان اللغة تعرفت على نوع myarray على انها مصفوفة ذات اكثر من بعد بدون التصريح بذلك وهذه ديناميكية تخطت مستوى المتغيرات وارتقت الى مستوى المصفوفات)

اقتباس

سمى في عالم لغات البرمجة: Lazy Evaluation. هذه الميزة موجودة في صلب Haskell

معلومة جديدة بالنسبة لى - جزاك الله خيرا على هذا التوضيح.

اقتباس

هي تأتي على أشكال عدة إضافة للذي ذكرته أخي العزيز. نحتاج إلى مقال عنها... قريباً بإذن الله

ربنا يعينك ويكرمك على متابعة هذه السلسلة الرائعة وانا متابع معك باستمرار باذن الله رب العالمين

والله الموفق

مواضيع مشابهة