قائمة طعام
مجانا
تسجيل
بيت  /  بواسطة/ Php الكتابة الثابتة. الكتابة الديناميكية

الكتابة الثابتة php. الكتابة الديناميكية

من أجل شرح تقنيتين مختلفتين تمامًا بأكبر قدر ممكن ، فلنبدأ من البداية. أول شيء يواجهه المبرمج عند كتابة التعليمات البرمجية هو التصريح عن المتغيرات. قد تلاحظ أنه ، على سبيل المثال ، في لغة البرمجة C ++ ، يجب عليك تحديد نوع المتغير. بمعنى ، إذا قمت بتعريف متغير x ، فيجب عليك إضافة int - لتخزين بيانات عدد صحيح ، و float - لتخزين بيانات الفاصلة العائمة ، و char - لبيانات الأحرف ، والأنواع الأخرى المتاحة. لذلك ، تستخدم لغة C ++ الكتابة الثابتة ، تمامًا مثل سابقتها ، C.

كيف تعمل الكتابة الثابتة؟

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

لنفكر في مثال صغير. عند تهيئة المتغير x (int x ؛) ، نحدد المعرف int - هذا اختصار يخزن له فقط الأعداد الصحيحة في النطاق من - 2 147483 648 إلى 2 147483 647. وهكذا ، يفهم المترجم أنه يمكنه تنفيذ القيم الرياضية لهذا المتغير - المجموع والفرق والضرب والقسمة. ولكن ، على سبيل المثال ، لا يمكن تطبيق وظيفة strcat () ، التي تربط قيمتي حرف ، على x. بعد كل شيء ، إذا قمت بإزالة القيود وحاولت توصيل قيمتين int باستخدام طريقة رمزية ، فسيحدث خطأ.

لماذا نحتاج لغات ذات كتابة ديناميكية؟

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

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

ما هو أفضل نوع من الكتابة؟

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

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

الفصل إلى كتابة "قوية" و "ضعيفة"

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

ميزة ديناميكية

يجب أن تكون قد لاحظت أنه في مرحلة كتابة الكود ، يقوم المترجم بتحليل التركيبات المكتوبة ويحدث خطأ إذا كانت أنواع البيانات غير متطابقة. لكن ليس JavaScript. يكمن تفردها في حقيقة أنها ستجري العملية في أي حال. هذا مثال سهل - نريد إضافة حرف ورقم ، وهذا غير منطقي: "x" + 1.

في اللغات الثابتة ، اعتمادًا على اللغة نفسها ، يمكن أن يكون لهذه العملية عواقب مختلفة. لكن في معظم الحالات ، لن يُسمح لها بالتجميع ، لأن المترجم سيعطي خطأ فورًا بعد كتابة مثل هذا البناء. سوف يعتبرها ببساطة غير صحيحة وسيكون على حق تمامًا.

في اللغات الديناميكية ، يمكن إجراء هذه العملية ، ولكن في معظم الحالات سيحدث خطأ بالفعل في مرحلة تنفيذ التعليمات البرمجية ، حيث لا يقوم المترجم بتحليل أنواع البيانات في الوقت الفعلي ولا يمكنه اتخاذ قرار بشأن الأخطاء في هذا المجال. تعد JavaScript فريدة من نوعها من حيث أنها ستؤدي مثل هذه العملية وينتهي بها الأمر بمجموعة من الأحرف غير القابلة للقراءة. على عكس اللغات الأخرى التي ستنهي البرنامج.

هل الأبنية المجاورة ممكنة؟

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

ولكن ، مع ذلك ، في بعض اللغات ، يمكنك تغيير الكتابة بمساعدة إطارات عمل إضافية.

  • في لغة برمجة دلفي ، النظام الفرعي المتغير.
  • في لغة البرمجة AliceML - حزم إضافية.
  • في لغة برمجة هاسكل ، مكتبة البيانات الديناميكية.

متى تكون الكتابة القوية أفضل حقًا من الكتابة الديناميكية؟

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

فوائد الكتابة الديناميكية

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

تعرف على المزيد حول لغات البرمجة باستخدام الكتابة الثابتة

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

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

  • Haskell هي أيضًا واحدة من اللغات الشائعة التي يمكن دمج كودها مع اللغات الأخرى والتفاعل معها. ولكن على الرغم من هذه المرونة ، إلا أنها تتميز بكتابة قوية. مجهزة بمجموعة كبيرة مدمجة من الأنواع والقدرة على إنشاء مجموعة خاصة بك.

تعرف على المزيد حول لغات البرمجة باستخدام الكتابة الديناميكية

  • Python هي لغة برمجة تم إنشاؤها في المقام الأول لتسهيل عمل المبرمج. يحتوي على عدد من التحسينات الوظيفية ، والتي بفضلها تزيد من قابلية قراءة الكود وكتابته. من نواح كثيرة ، تم تحقيق ذلك بفضل الكتابة الديناميكية.

  • PHP هي لغة برمجة. تستخدم على نطاق واسع في تطوير الويب ، مما يوفر التفاعل مع قواعد البيانات لإنشاء صفحات ويب ديناميكية تفاعلية. بفضل الكتابة الديناميكية ، يتم تسهيل العمل مع قواعد البيانات بشكل كبير.

  • JavaScript هي لغة البرمجة المذكورة أعلاه ، والتي وجدت تطبيقًا في تقنيات الويب لإنشاء نصوص ويب تعمل على جانب العميل. تُستخدم الكتابة الديناميكية لتسهيل كتابة التعليمات البرمجية ، لأنها عادةً ما يتم تقسيمها إلى كتل صغيرة.

النوع الديناميكي من الكتابة - العيوب

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

لخص

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

إن بساطة الكتابة في نهج OO هي نتيجة لبساطة نموذج حساب الكائن. بحذف التفاصيل ، يمكننا القول أنه أثناء تنفيذ نظام OO ، يحدث نوع واحد فقط من الأحداث - استدعاء ميزة:


تدل على العملية Fفوق الكائن المرفق xمع حجة عابرة حج(ربما حجج متعددة أو لا شيء على الإطلاق). يتحدث مبرمجو Smalltalk في هذه الحالة عن "تمرير كائن xرسائل Fمع حجة حج"، لكن هذا مجرد اختلاف في المصطلحات ، وبالتالي فهو ليس مهمًا.

أن كل شيء يعتمد على هذا البناء الأساسي يفسر جزءًا من الإحساس بالجمال في أفكار OO.

من البناء الأساسي ، اتبع تلك المواقف غير الطبيعية التي قد تنشأ في عملية التنفيذ:

التعريف: نوع الانتهاك

يحدث انتهاك نوع وقت التشغيل ، أو مجرد انتهاك لنوع قصير ، في وقت المكالمة. x.f (arg)، أين xتعلق على كائن OBJأي كان:

[x].لا يوجد مكون مطابق Fوقابلة للتطبيق على OBJ,

[x].هناك مثل هذا العنصر ، ومع ذلك ، فإن الحجة حجغير مقبول بالنسبة له.

تكمن مشكلة الكتابة في تجنب مثل هذه المواقف:

مشكلة الكتابة لأنظمة OO

متى نجد أن انتهاك النوع يمكن أن يحدث في تنفيذ نظام OO؟

الكلمة الأساسية هي متى. عاجلاً أم آجلاً ستدرك أن هناك انتهاكًا للنوع. على سبيل المثال ، لن تعمل محاولة تنفيذ مكون "Torpedo Launch" على كائن "موظف" وسيفشل التنفيذ. ومع ذلك ، قد تفضل العثور على الأخطاء في أقرب وقت ممكن وليس لاحقًا.

الكتابة الثابتة والديناميكية

على الرغم من إمكانية وجود خيارات وسيطة ، يتم تقديم نهجين رئيسيين هنا:

[x]. الكتابة الديناميكية: انتظر حتى تكتمل كل مكالمة ثم اتخذ قرارًا.

[x]. الكتابة الثابتة: بالنظر إلى مجموعة من القواعد ، حدد من النص المصدر ما إذا كانت انتهاكات النوع ممكنة أثناء التنفيذ. يتم تنفيذ النظام إذا كانت القواعد تضمن عدم وجود أخطاء.

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

تتضمن الكتابة الثابتة فحصًا تلقائيًا ، والذي عادة ما يكون من مسؤولية المترجم. نتيجة لذلك ، لدينا تعريف بسيط:

التعريف: لغة مكتوبة بشكل ثابت

يتم كتابة لغة OO بشكل ثابت إذا كانت تأتي مع مجموعة من القواعد المتسقة ، والتي تم التحقق منها من قبل المترجم ، والتي تضمن أن تنفيذ النظام لا يؤدي إلى انتهاكات الكتابة.

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

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

قواعد الكتابة

تدوين OO الخاص بنا مكتوب بشكل ثابت. تم تقديم قواعد الكتابة الخاصة بها في المحاضرات السابقة وتختصر في ثلاثة متطلبات بسيطة.

[x].عند الإعلان عن كل كيان أو وظيفة ، يجب تحديد نوعها ، على سبيل المثال ، acc: حساب. يحتوي كل روتين فرعي على 0 أو أكثر من الوسيطات الرسمية ، ويجب تقديم نوع منها ، على سبيل المثال: ضع (x: G ؛ i: صحيح).

[x].في أي مهمة س: = صوعلى أي مكالمة روتين فرعي فيها ذهي الحجة الفعلية للحجة الرسمية x، نوع المصدر ذيجب أن يكون متوافقًا مع النوع الهدف x. يعتمد تعريف التوافق على الوراثة: بمتوافق مع أ، إذا كان سليلها ، - مع استكماله بقواعد المعلمات العامة (انظر المحاضرة 14).

[x].يتصل x.f (arg)يتطلب أن Fكان أحد مكونات الفئة الأساسية للنوع الهدف x، و Fيجب تصديرها إلى الفئة التي تظهر فيها المكالمة (انظر 14.3).

الواقعية

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

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

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

يمكننا أن نقول تلك اللغات من النوع الأول ملائم، لكن عديم الفائدة، قد يكون الأخير مفيدًا ولكنه غير مناسب.

في الممارسة العملية ، ما نحتاجه هو نظام كتابة يكون مفيدًا ومفيدًا في نفس الوقت: قوي بما يكفي لتلبية احتياجات الحسابات ومريح بما يكفي لعدم إجبارنا على الذهاب إلى التعقيد لتلبية قواعد الكتابة.

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

في هذه المحاضرة ، سوف نتأكد من أن الملاحظة التي نقترحها واقعية.

تشاؤم

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

فكر في لغة عادية غير موضوعية تشبه باسكال وأنواع مختلفة حقيقيو عدد صحيح. عند وصفه ن: عدد صحيح ؛ r: حقيقيالمشغل أو العامل ن: = صسيتم رفضه لانتهاكه القواعد. وبالتالي ، فإن المترجم سيرفض جميع العبارات التالية:


إذا سمحنا لهم بالتشغيل ، فسنرى أن [A] ستعمل دائمًا ، لأن أي نظام رقمي له تمثيل دقيق للعدد الحقيقي 0.0 ، والذي يترجم بشكل لا لبس فيه إلى 0 أعداد صحيحة. [ب] سيعمل أيضًا بشكل شبه مؤكد. نتيجة الإجراء [C] ليست واضحة (هل نريد الحصول على النتيجة بالتقريب أو التخلص من الجزء الكسري؟). سيقوم [D] بالمهمة ، وكذلك عامل التشغيل:


ifn ^ 2< 0 then n:= 3.67 end [E]

الذي يتضمن مهمة لا يمكن الوصول إليها ( ن ^ 2هو مربع الرقم ن). بعد الاستبدال ن ^ 2على نفقط سلسلة من الأشواط ستعطي النتيجة الصحيحة. تكليف نالقيمة الحقيقية الكبيرة التي لا يمكن تمثيلها كعدد صحيح ستؤدي إلى فشل.

في اللغات المكتوبة ، يتم التعامل مع كل هذه الأمثلة (التي تعمل ، لا تعمل ، تعمل أحيانًا) بلا رحمة على أنها انتهاكات لقواعد وصف الأنواع ويتم رفضها من قبل أي مترجم.

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

الكتابة الثابتة: كيف ولماذا

في حين أن فوائد الكتابة الثابتة واضحة ، فمن الجيد التحدث عنها مرة أخرى.

مزايا

قمنا بإدراج أسباب استخدام الكتابة الثابتة في تقنية الكائن في بداية المحاضرة. إنها الموثوقية وسهولة الفهم والكفاءة.

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

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

أرز. 17.1.تكاليف إصلاح الأخطاء المقارنة (منشورة بإذن)

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

أخيراً، كفاءةيمكن أن تحدد نجاح أو فشل تقنية الكائن في الممارسة. في حالة عدم وجود طباعة ثابتة عند التنفيذ x.f (arg)يمكن أن يستغرق أي قدر من الوقت. والسبب في ذلك هو أنه في وقت التشغيل ، لم يتم العثور Fفي فئة الهدف الأساسي xوسيستمر البحث في نسله وهذا طريق أكيد لعدم الكفاءة. يمكنك تخفيف المشكلة عن طريق تحسين البحث عن مكون في التسلسل الهرمي. مؤلفو لغة الذات عمل عظيم، في محاولة لإنشاء رمز أفضل للغة مكتوبة ديناميكيًا. ولكن كانت الكتابة الثابتة هي التي سمحت لمنتج OO بالاقتراب أو المساواة في الكفاءة مع البرامج التقليدية.

مفتاح الكتابة الثابتة هو الفكرة التي سبق ذكرها وهي أن المترجم الذي يولد الكود للبناء x.f (arg)يعرف النوع x. بسبب تعدد الأشكال ، لا يمكن تحديد الإصدار المناسب من المكون بشكل فريد F. لكن الإعلان يضيق نطاق مجموعة الأنواع المحتملة ، مما يسمح للمترجم بإنشاء جدول يوفر الوصول إلى الصحيح Fبأقل تكلفة ، مع ثابت يحدهصعوبة الوصول. تم إجراء تحسينات إضافية ربط ثابتو بدائل (مضمنة)- يتم تسهيلها أيضًا من خلال الكتابة الثابتة ، مما يلغي تمامًا النفقات العامة عند الاقتضاء.

الحجج للكتابة الديناميكية

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

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

الكتابة: مكونات النجاح

ما هي آليات الكتابة الثابتة الواقعية؟ تم تقديمهم جميعًا في المحاضرات السابقة ، وبالتالي يبقى لنا فقط تذكرها بإيجاز. يُظهر تعدادهم المشترك تماسك وقوة جمعيتهم.

يعتمد نظام الكتابة لدينا بالكامل على المفهوم فصل. الفئات هي حتى أنواع أساسية مثل عدد صحيح، وبالتالي ، لا نحتاج إلى قواعد خاصة لوصف الأنواع المحددة مسبقًا. (هذا هو المكان الذي يختلف فيه تدويننا عن اللغات "الهجينة" مثل Object Pascal و Java و C ++ ، حيث يتم دمج نظام كتابة اللغات القديمة مع تقنية الكائن المستندة إلى الفئة.)

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

تنتمي الكلمة الحاسمة في إنشاء نظام كتابة مرن ميراثوالمفهوم ذي الصلة التوافق. هذا يتغلب على القيود الرئيسية للغات المكتوبة الكلاسيكية ، على سبيل المثال ، باسكال وآدا ، حيث عامل التشغيل س: = صيتطلب ذلك النوع xو ذهو نفسه. هذه القاعدة صارمة للغاية: فهي تحظر استخدام الكيانات التي يمكن أن تشير إلى كائنات من الأنواع ذات الصلة ( حساب التوفيرو حساب جار). في الوراثة ، لا نطلب سوى توافق النوع ذمع النوع x، على سبيل المثال، xلديه نوع حساب، ص- حساب التوفير، والفئة الثانية هي خليفة الأول.

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

أرز. 17.2.تعدد الميراث

براعهضروري ، على سبيل المثال ، لوصف هياكل بيانات الحاوية المرنة والآمنة (على سبيل المثال فئة LIST [G] ...). بدون هذه الآلية ، قد تتطلب الكتابة الثابتة التصريح عن فئات مختلفة للقوائم ذات أنواع العناصر المختلفة.

في بعض الحالات ، التنوع مطلوب يقيد، والذي يسمح لك باستخدام العمليات التي تنطبق فقط على الكيانات من النوع العام. إذا كانت الفئة العامة SORTABLE_LISTيدعم الفرز ، فهو يتطلب كيانات من النوع جي، أين جي- معلمة عامة ، وجود عملية مقارنة. يتم تحقيق ذلك من خلال الارتباط بـ جيالفئة التي تحدد القيد العام - قابل للمقارنة:


فئة SORTABLE_LIST ...

أي معلمة عامة فعلية SORTABLE_LISTيجب أن يكون طفلًا في الفصل قابل للمقارنة، الذي يحتوي على المكون المطلوب.

آلية أساسية أخرى هي محاولة الإسناد- ينظم الوصول إلى تلك الكائنات ، التي لا يتحكم البرنامج في نوعها. لو ذهو كائن قاعدة بيانات أو كائن تم الحصول عليه من خلال الشبكة ، ثم البيان س؟ = صتعيين xمعنى ذ، لو ذهو من نوع متوافق ، أو إذا لم يكن كذلك ، فسيعطي xمعنى فارغ.

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

الإعلانات المثبتةمن أجل تجنب تكرار الكود في الممارسة العملية. معلنا ص: مثل س، تحصل على ضمان ذلك ذسوف يتغير بعد أي نوع من الإقرارات المتكررة xعند سليل. في غياب هذه الآلية ، سيعيد المطورون التصريح باستمرار ، محاولين الحفاظ على اتساق الأنواع المختلفة.

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

عند تطوير أنظمة البرمجياتفي الواقع ، هناك حاجة إلى خاصية أخرى ، متأصلة في بيئة التطوير نفسها - إعادة تجميع تزايدي سريع. عندما تكتب أو تعدل نظامًا ، فأنت تريد أن ترى تأثير التغييرات في أسرع وقت ممكن. مع الكتابة الثابتة ، يجب أن تمنح المترجم الوقت لإعادة فحص الأنواع. تتطلب إجراءات التجميع التقليدية إعادة تجميع النظام بأكمله (و مجلسها) ، ويمكن أن تكون هذه العملية طويلة بشكل مؤلم ، خاصة مع الانتقال إلى الأنظمة واسعة النطاق. أصبحت هذه الظاهرة حجة لصالح الترجمةالأنظمة ، مثل بيئات Lisp أو Smalltalk المبكرة ، التي شغلت النظام مع معالجة قليلة أو معدومة ، ولا فحص للنوع. الآن تم نسيان هذه الحجة. يكتشف المترجم الحديث الجيد كيف تغيرت الشفرة منذ التجميع الأخير ولا يعالج سوى التغييرات التي يجدها.

"هل الطفل مُصنَّف"؟

هدفنا - حازمكتابة ثابتة. هذا هو السبب في أننا يجب أن نتجنب أي ثغرات في "اللعب وفقًا للقواعد" ، على الأقل تحديدها بدقة إذا كانت موجودة.

الثغرة الأكثر شيوعًا في اللغات المكتوبة بشكل ثابت هي وجود التحويلات التي تغير نوع الكيان. في لغة C واللغات المشتقة منها ، يطلق عليهم اسم "نوع الصب" أو الصب. تسجيل (OTHER_TYPE) xيشير إلى أن القيمة xينظر إليه المترجم على أنه من النوع OTHER_TYPE، مع مراعاة قيود معينة على الأنواع الممكنة.

آليات مثل هذه تتجاوز قيود فحص النوع. يعتبر Casting شائعًا في برمجة C ، بما في ذلك لهجة ANSI C. حتى في C ++ ، يظل أسلوب الصب ، رغم أنه أقل شيوعًا ، شائعًا وربما ضروريًا.

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

الكتابة والربط

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

يتعامل كل من الكتابة والربط مع دلالات البناء الأساسي x.f (arg)لكن أجب عن سؤالين مختلفين:

الكتابة والربط

[x]. سؤال حول الكتابة: عندما نحتاج أن نعرف على وجه اليقين أن عملية مماثلة Fينطبق على الكائن المرفق بالكيان x(مع المعلمة حج)?

[x]. ربط السؤال: متى نحتاج إلى معرفة العملية التي تبدأها مكالمة معينة؟

الكتابة تجيب على سؤال التوفر مرة على الأقلالعمليات ، ملزم هو المسؤول عن الاختيار ضروري.

في إطار نهج الكائن:

[x].مشكلة الكتابة مرتبطة بـ تعدد الأشكال: بسبب ال xفي وقت التشغيليمكن أن تشير إلى كائنات من عدة أنواع مختلفة ، يجب أن نتأكد من أن العملية تمثل F, متاحفي كل حالة من هذه الحالات ؛

[x].تسبب مشكلة ملزمة إعلانات متكررة: نظرًا لأنه يمكن للفئة تغيير المكونات الموروثة ، فقد تكون هناك عمليتان أو أكثر تدعي أنها تمثل Fفي هذه المكالمة.

يمكن حل كلتا المشكلتين ديناميكيًا وثابتًا. في اللغات الموجودةيتم عرض جميع الحلول الأربعة.

[x].يقوم عدد من اللغات غير الموضوعية ، مثل Pascal و Ada ، بتنفيذ كل من الكتابة الثابتة والربط الثابت. يمثل كل كيان كائنات من نوع واحد محدد بشكل ثابت. هذا يضمن موثوقية الحل ، والسعر الذي يمثل مرونته.

[x].تحتوي لغة Smalltalk ولغات OO الأخرى على ارتباط ديناميكي وكتابة ديناميكية. يتم إعطاء الأفضلية للمرونة على حساب موثوقية اللغة.

[x].تدعم بعض اللغات غير الموضوعية الكتابة الديناميكية والربط الثابت. من بينها لغات التجميع وعدد من لغات البرمجة النصية.

[x].تتجسد أفكار الكتابة الثابتة والربط الديناميكي في الملاحظات المقترحة في هذا الكتاب.

لاحظ خصوصية لغة C ++ ، التي تدعم الكتابة الثابتة ، على الرغم من أنها ليست صارمة بسبب وجود نوع الصب ، والربط الثابت (افتراضيًا) ، والربط الديناميكي عندما يكون افتراضيًا ( افتراضي) إعلانات.

سبب اختيار الكتابة الثابتة والربط الديناميكي واضح. السؤال الأول هو: "متى نعرف عن وجود المكونات؟" - يقترح استجابة ثابتة: " في وقت سابق كان ذلك أفضل"، وهو ما يعني: في وقت الترجمة. السؤال الثاني ،" ما المكون الذي يجب استخدامه؟ "يقترح استجابة ديناميكية:" الذي تحتاجه"، المطابق للنوع الديناميكي للكائن المحدد في وقت التشغيل. هذا هو الحل الوحيد المقبول إذا أدى الربط الثابت والديناميكي إلى نتائج مختلفة.

سيساعد المثال التالي للتسلسل الهرمي للميراث في توضيح هذه المفاهيم:

أرز. 17.3.أنواع الطائرات

ضع في اعتبارك المكالمة:


my_aircraft.lower_landing_gear

سؤال حول الكتابة: متى يجب التأكد من وجود أحد المكونات هنا low_landing_gear("إطلاق معدات الهبوط") ، تنطبق على كائن (ل النحاسلن يكون على الإطلاق) مسألة الربط: أي من الإصدارات العديدة الممكنة للاختيار.

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

باستخدام الكتابة الثابتة ، لن يرفض المترجم مكالمة إذا كان من الممكن ضمان ذلك عند تنفيذ البرنامج للكيان طائراتيسيتم إرفاق الكائن المزود مع المكون المقابل low_landing_gear. الأسلوب الأساسي للحصول على الضمانات بسيط: مع إقرار إلزامي طائراتيالفئة الأساسية من نوعها مطلوبة لتضمين مثل هذا المكون. لهذا طائراتيلا يمكن التصريح عنها كـ الطائرات، لأن هذا الأخير لا يملك low_landing_gearعلى هذا المستوى؛ طائرات الهليكوبتر ، على الأقل في مثالنا ، لا تعرف كيف تطلق معدات الهبوط. إذا أعلنا أن الكيان هو طائرة، - الفئة التي تحتوي على المكون المطلوب - كل شيء سيكون على ما يرام.

تتطلب الكتابة الديناميكية بأسلوب Smalltalk انتظار المكالمة ، وفي وقت تنفيذها ، تحقق من وجود المكون المطلوب. هذا السلوك ممكن للنماذج الأولية والتطورات التجريبية ، لكنه غير مقبول للأنظمة الصناعية - في وقت الرحلة ، فات الأوان للسؤال عما إذا كان لديك جهاز هبوط.

التغاير وإخفاء الطفل

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

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

التغاير

ماذا يحدث لوسائط المكون عند إعادة تعريف نوعه؟ هذه مشكلة كبيرة ، وقد رأينا بالفعل عددًا من الأمثلة عليها: الأجهزة والطابعات ، والقوائم المرتبطة منفردة ومزدوجة ، وما إلى ذلك (انظر الأقسام 16.6 ، 16.7).

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

تخيل فريق تزلج جامعي يستعد لبطولة. فصل بنتيشمل المتزلجين الذين هم جزء من فريق السيدات ، ولد- المتزلجين. تم تصنيف عدد من المشاركين من كلا الفريقين ، مما يدل على نتائج جيدة في المسابقات السابقة. هذا مهم بالنسبة لهم ، لأنهم الآن سوف يركضون أولاً ، ويكتسبون ميزة على الآخرين. (هذه القاعدة ، التي تمنح امتيازًا بالفعل ، ربما تكون هي ما يجعل التعرج والتزلج الريفي على الثلج أمرًا جذابًا للغاية في نظر كثير من الناس ، كونه استعارة جيدة للحياة نفسها.) لذلك لدينا فئتان جديدتان: RANKED_GIRLو رتبت.

أرز. 17.4.تصنيف المتزلج

تم حجز عدد من الغرف لسكن الرياضيين: للرجال فقط ، للفتيات فقط ، للفائزات فقط. لعرض هذا ، نستخدم التسلسل الهرمي للفئة المتوازية: غرفة, غرفة_الفتاةو RANKED_GIRL_ROOM.

هنا هو مخطط الفصل المتزحلق:


- رفيق السكن.
... تم حذف المكونات الأخرى المحتملة في هذه الفئات والفئات اللاحقة ...

نحن مهتمون بمكونين: السمة رفيق السكنوالإجراء يشارك، الذي "يضع" هذا المتزلج في نفس الغرفة مع المتزلج الحالي:


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

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


- رفيق السكن.

أعد تعريف حجة الإجراء على التوالي يشارك. يبدو الآن إصدار أكثر اكتمالا من الفصل كما يلي:


- رفيق السكن.
- اختر أخرى كجار.

وبالمثل ، يجب عليك تغيير كل ما تم إنشاؤه من المتزحلقالفئات (نحن لا نستخدم تحديد النوع الآن). نتيجة لذلك ، لدينا تسلسل هرمي:

أرز. 17.5.التسلسل الهرمي للأعضاء وإعادة التعريفات

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

توضح جميع الأمثلة لدينا بشكل مقنع الضرورة العملية للتغاير.

[x].عنصر قائمة مرتبط بشكل منفرد قابل للربطيجب أن يقترن بعنصر مشابه آخر ، والمثال BI_LINKABLE- مع واحدة مماثلة. سيحتاج المتغير المشترك إلى تجاوزه والحجة فيه ضع الحق.

[x].كل روتين فرعي بتنسيق LINKED_LISTمع نوع الوسيطة قابل للربطعند الانتقال إلى TWO_WAY_LISTسوف يتطلب حجة BI_LINKABLE.

[x].إجراء set_alternateيقبل جهاز-حجة في الصف جهازو طابعة-حجة - في الصف طابعة.

تحظى إعادة تعريف المتغير بشعبية خاصة لأن إخفاء المعلومات يؤدي إلى إنشاء إجراءات للنموذج


- اضبط السمة على v.

للعمل مع السمةيكتب بعض الانواع. هذه الإجراءات ، بالطبع ، متغايرة ، لأن أي فئة تغير نوع السمة يجب أن تعيد تعريف الوسيطة وفقًا لذلك. set_attrib. على الرغم من أن الأمثلة المقدمة تتناسب مع مخطط واحد ، إلا أن التغاير أكثر انتشارًا. فكر ، على سبيل المثال ، في إجراء أو وظيفة تؤدي تسلسل القوائم المرتبطة منفردة ( LINKED_LIST). يجب إعادة تعريف حجتها كقائمة مرتبطة بشكل مزدوج ( TWO_WAY_LIST). عملية إضافة عالمية infix "+"يقبل رقمي-حجة في الصف رقمي, حقيقي- في الفصل حقيقيو عدد صحيح- في الفصل عدد صحيح. في التسلسل الهرمي للخدمات الهاتفية المتوازية ، الإجراء يبدأفي الفصل خدمة الهاتفقد تكون الحجة مطلوبة عنوان، يمثل عنوان المشترك ، (للفواتير) ، بينما نفس الإجراء في الفصل خدمة الشركاتنوع الوسيطة المطلوبة CORPORATE_ADDRESS.

أرز. 17.6.خدمات الاتصالات

ماذا يمكن أن يقال عن الحل المخالف؟ في مثال المتزلج ، هذا يعني أنه إذا كان ، يتم الانتقال إلى الفصل RANKED_GIRL، نوع النتيجة رفيق السكنأعيد تعريفها كـ RANKED_GIRL، إذن ، بسبب التناقض ، نوع الحجة يشاركيمكن إعادة تعريفها للكتابة بنتأو المتزحلق. النوع الوحيد غير المسموح به بموجب الحل المخالف هو RANKED_GIRL! كفى لإثارة أسوأ الشكوك لدى والدي الفتيات.

التسلسلات الهرمية المتوازية

حتى لا تترك حجرًا دون قلبه ، ضع في اعتبارك نوعًا مختلفًا من المثال المتزحلقمع اثنين من التسلسلات الهرمية المتوازية. سيسمح لنا ذلك بمحاكاة موقف تمت مواجهته بالفعل في الممارسة: TWO_WAY_LIST> LINKED_LISTو BI_LINKABLE> LINKABLE؛ أو التسلسل الهرمي مع خدمة الهاتف خدمة الهاتف.

يجب ألا يكون هناك تسلسل هرمي مع فئة غرفةالذي هو سليل غرفة_الفتاة(فصل ولدمحذوف):

أرز. 17.7.المتزلجين والغرف

فصولنا المتزلج في هذا التسلسل الهرمي المتوازي بدلاً من رفيق السكنو يشاركسيكون لها مكونات مماثلة إقامة (إقامة) و يستوعب (مكان):


الوصف: "متغير جديد بتسلسلات هرمية متوازية"
تتسع (r: ROOM) ... تتطلب ... تفعل

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

ضلال تعدد الأشكال

ألا توجد أمثلة كافية تؤكد التطبيق العملي للتغاير؟ لماذا قد يفكر أي شخص في التعارض الذي يتعارض مع ما هو مطلوب في الممارسة (باستثناء سلوك بعض الشباب)؟ لفهم هذا ، ضع في اعتبارك المشكلات التي تنشأ عند الجمع بين تعدد الأشكال واستراتيجية التغاير. إن التوصل إلى مخطط تخريبي ليس بالأمر الصعب ، وربما تكون قد أنشأته بنفسك بالفعل:


خلق ب ؛ إنشاء ز ؛ - إنشاء كائنات الصبي والفتاة.

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

مخطط التسلسل الهرمي المتوازي بسيط للغاية: استبدال المتزحلقعلى التزلج 1، تحدي يشارك- في مكالمة s.accommodate (غرام)، أين غرام- نوع الكيان غرفة_الفتاة. النتيجة هي نفسها.

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

لذلك ، دون محاولة سحب الملابس المتناقضة على الجسد المتغاير ، يجب على المرء أن يتقبل الواقع المتغير ويبحث عن طرق للقضاء على التأثير غير المرغوب فيه.

الاختباء من قبل النسل

قبل البحث عن حل لمشكلة التغاير ، ضع في اعتبارك آلية أخرى يمكن أن تؤدي إلى انتهاكات النوع في ظل ظروف تعدد الأشكال. الإخفاء المتسلسل هو قدرة الفئة على عدم تصدير مكون تم استلامه من والديه.

أرز. 17.8.الاختباء من قبل النسل

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


مثال غير برمجي: صنف "Ostrich" يخفي طريقة "Fly" الواردة من الوالد "Bird".

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


مبتكر. - قم بإنشاء كائن RECTANGLE.
ع: = ص ؛ - التخصيص متعدد الأشكال.

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

صحة الأنظمة والفئات

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

النظام يسمى نظام صحيح (نظام صالح)، في حالة عدم حدوث انتهاك للنوع أثناء تنفيذه.

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

الجانب العملي

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

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

بعد ذلك ، سوف نتطرق إلى الجوانب الدقيقة جدًا وغير الواضحة في كثير من الأحيان لمقاربة الكائن. إذا كنت تقرأ هذا الكتاب لأول مرة ، فقد ترغب في تخطي الأقسام المتبقية من هذه المحاضرة. إذا كنت جديدًا على تقنية OO ، فستفهم هذه المادة بشكل أفضل بعد دراسة المحاضرات 1-11 من الدورة التدريبية "أساسيات التصميم الموجه للكائنات" ، والمخصصة لمنهجية الميراث ، وعلى وجه الخصوص المحاضرة 6 من الدورة التدريبية "أساسيات التصميم الكينوني "، المكرس لمنهجية الميراث.

صحة الأنظمة: التقريب الأول

دعنا نركز أولاً على مشكلة التغاير ، فالأهم من الاثنين. هناك مؤلفات واسعة مكرسة لهذا الموضوع ، تقدم عددًا من الحلول المختلفة.

التناقض والثبات

يزيل التباين المشاكل النظرية المرتبطة بانتهاك صحة النظام. ومع ذلك ، فإن هذا يفقد واقعية نظام الكتابة ، ولهذا السبب ، ليست هناك حاجة لمزيد من النظر في هذا النهج.

أصالة لغة C ++ هي أنها تستخدم الإستراتيجية الابتداء، مما يمنعك من تغيير نوع الحجج في الإجراءات الفرعية التي تم تجاوزها! إذا كانت لغة C ++ لغة مكتوبة بقوة ، فسيكون من الصعب استخدام نظام الكتابة الخاص بها. إن أبسط حل للمشكلة في هذه اللغة ، بالإضافة إلى تجاوز القيود الأخرى لـ C ++ (على سبيل المثال ، عدم وجود عالمية محدودة) ، هو استخدام casting - type casting ، والذي يسمح لك بتجاهل آلية الكتابة الحالية تمامًا. لا يبدو هذا الحل جذابًا. لاحظ ، مع ذلك ، أن عددًا من المقترحات التي تمت مناقشتها أدناه ستعتمد على انعدام التباين ، والذي سيتم تقديم معناه من خلال إدخال آليات جديدة للعمل مع الأنواع بدلاً من إعادة تعريف المتغير المشترك.

استخدام المعلمات العامة

العالمية هي جوهر فكرة مثيرة للاهتمام اقترحها لأول مرة فرانز ويبر. دعنا نعلن عن فئة التزلج 1، تقييد تعميم المعلمة العامة على الفئة غرفة:


ميزة فئة SKIER1
استيعاب (r: G) هو ... يتطلب ... القيام بالسكن: = r end

ثم الطبقة فتاة 1سيكون الوريث التزلج 1يمكن استخدام نفس الأسلوب ، مهما بدا غريبًا للوهلة الأولى ، في غياب التسلسل الهرمي الموازي: فئة التزلج.

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

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

اكتب المتغيرات

توصل عدد من المؤلفين ، بما في ذلك Kim Bruce و David Shang و Tony Simons ، إلى حل يعتمد على متغيرات النوع التي تكون قيمها أنواعًا. فكرتهم بسيطة:

[x].بدلاً من التجاوزات المتغيرة ، السماح بإعلانات النوع التي تستخدم متغيرات النوع ؛

[x].توسيع قواعد توافق النوع لإدارة مثل هذه المتغيرات ؛

[x].توفر القدرة على تعيين متغيرات النوع كقيم لأنواع اللغة.

يمكن للقراء العثور على عرض تفصيلي لهذه الأفكار في عدد من المقالات حول هذا الموضوع ، وكذلك في منشورات كارديلي (كارديلي) ، وكاستاغنا (كاستاغنا) ، ويبر (ويبر) ، وغيرهم. لن نتعامل مع هذه المشكلة ، وهذا هو السبب.

[x].تندرج آلية متغير النوع المنفذة بشكل صحيح في فئة السماح باستخدام نوع دون تحديده بالكامل. تتضمن نفس الفئة تنوعًا وترسيخًا للإعلان. يمكن أن تحل هذه الآلية محل الآليات الأخرى في هذه الفئة. في البداية ، يمكن تفسير ذلك لصالح متغيرات النوع ، لكن النتيجة يمكن أن تكون كارثية ، لأنه ليس من الواضح ما إذا كانت هذه الآلية الشاملة يمكنها التعامل مع جميع المهام بسهولة وبساطة متأصلة في التعميم ونوع التثبيت.

[x].افترض أنه تم تطوير آلية متغيرة من النوع يمكنها التغلب على مشاكل الجمع بين التغاير وتعدد الأشكال (لا تزال تتجاهل مشكلة إخفاء السليل). ثم سيحتاج مطور الفصل حدس غير عاديمن أجل تحديد أي من المكونات سيكون متاحًا لإعادة تعريف الأنواع في الفئات المشتقة مسبقًا وأيها لن يكون متاحًا. أدناه سنناقش هذه المشكلة ، والتي تحدث في ممارسة إنشاء البرامج ، وللأسف ، تلقي بظلال من الشك على قابلية تطبيق العديد من المخططات النظرية.

هذا يجبرنا على العودة إلى الآليات التي تم التفكير فيها بالفعل: عالمية محدودة وغير مقيدة ، نوع التثبيت ، وبالطبع الميراث.

الاعتماد على نوع التثبيت

سنجد حلاً شبه جاهز لمشكلة التغاير من خلال النظر في آلية التصريحات المثبتة المعروفة لدينا.

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


المشاركة (أخرى: مثل Current) هي ... تتطلب ... تفعل
استيعاب (r: مثل الإقامة) ... تتطلب ... تفعل

الآن يمكن للأطفال مغادرة الفصل المتزحلقدون تغيير و التزلج 1سيحتاجون فقط إلى تجاوز السمة إقامة. الكيانات المثبتة: السمة رفيق السكنوالحجج الروتينية يشاركو يستوعب- سيتغير تلقائيًا. هذا يبسط العمل بشكل كبير ويؤكد حقيقة أنه في حالة عدم وجود إرساء (أو آلية أخرى مماثلة ، مثل متغيرات النوع) ، من المستحيل كتابة منتج OO بكتابة واقعية.

لكن هل تمكنت من القضاء على انتهاكات صحة النظام؟ لا! يمكننا ، كما في السابق ، التفوق على فحص النوع عن طريق القيام بمهام متعددة الأشكال تسبب انتهاكات لصحة النظام.

صحيح ، سيتم رفض النسخ الأصلية للأمثلة. اسمحوا ان:


إنشاء ب ؛ إنشاء ز ؛ - إنشاء كائنات الصبي والفتاة.
ق: = ب ؛ - التخصيص متعدد الأشكال.

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

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


ق: التزلج ؛ ب: الصبي. ز: الإعجابات ؛ real_g: فتاة ؛
خلق ب ؛ إنشاء الفعلي _g - إنشاء كائنات BOY و GIRL.
ق: = ج الفعلي ؛ g: = s - إلحاق g بـ GIRL عبر s.
ق: = ب - مهمة متعددة الأشكال.

نتيجة لذلك ، يتم إجراء المكالمة غير القانونية.

هناك طريقة للخروج. إذا كنا جادين في استخدام تثبيت الإعلان باعتباره الآلية الوحيدة للتغاير ، فيمكننا التخلص من انتهاكات الصحة النظامية عن طريق الحظر التام لتعدد أشكال الكيانات المثبتة. سيتطلب هذا تغييرًا في اللغة: أدخل كلمة رئيسية جديدة مِرسَاة(نحتاج إلى هذا البناء الافتراضي فقط لاستخدامه في هذه المناقشة):


دعونا نسمح بتصريحات مثل الإعجاباتفقط عندما سوصفت بأنها مِرسَاة. دعنا نغير قواعد التوافق لضمان: سوعناصر من النوع الإعجاباتيمكن فقط إرفاقها (في المهام أو الحجة المارة) ببعضها البعض.

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


أثناء الفصل ج- الأبوين دبدا


أين صتقابل X، نعيد تعريف المكون الآن صسيبدو هكذا:


يبقى في الفصل دنوع التجاوز مرساتك.

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

[x].يعتمد التثبيت على فكرة الفصل الصارم متغيرويحتمل أن تكون متعددة الأشكال (أو ، باختصار ، متعددة الأشكال). تم إعلان جميع الكيانات باسم مِرسَاةأو مثل some_anchorمتغير. البعض الآخر متعدد الأشكال. في كل من الفئتين ، يُسمح بأي مرفقات ، لكن لا يوجد كيان أو تعبير ينتهك الحدود. لا يمكنك ، على سبيل المثال ، تعيين مصدر متعدد الأشكال لهدف متغير.

[x].هذا الحل البسيط والأنيق يسهل شرحه حتى للمبتدئين.

[x].إنه يلغي تمامًا إمكانية انتهاك صحة النظام في الأنظمة التي يتم إنشاؤها بشكل متغاير.

[x].إنه يحتفظ بالإطار المفاهيمي المنصوص عليه أعلاه ، بما في ذلك مفاهيم العالمية المحدودة وغير المحدودة. (نتيجة لذلك ، فإن هذا الحل ، في رأيي ، هو الأفضل من نوع المتغيرات التي تحل محل آليات التباين المشترك والعالمية ، المصممة لحل المشكلات العملية المختلفة.)

[x].يتطلب تغييرًا طفيفًا في اللغة - إضافة كلمة رئيسية واحدة تنعكس في قاعدة المطابقة - ولا ينطوي على أي صعوبات تنفيذ ملحوظة.

[x].إنه واقعي (على الأقل من الناحية النظرية): يمكن إعادة كتابة أي نظام ممكن سابقًا عن طريق استبدال التجاوزات المتغيرة مع إعادة التصريح الثابتة. صحيح أن بعض المرفقات ستكون غير صالحة كنتيجة لذلك ، لكنها تتوافق مع الحالات التي يمكن أن تؤدي إلى انتهاكات في النوع ، وبالتالي يجب استبدالها بمحاولات الإسناد والتعامل معها في وقت التشغيل.

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

[x].من المحتمل أن يكون الكيان متعدد الأشكال: الآن أو لاحقًا (عن طريق تمرير المعلمات أو عن طريق التعيين) يمكن إرفاقه بكائن يختلف نوعه عن النوع المعلن. لا يمكن تغيير نوع الكيان الأصلي بواسطة أي تابع للفئة.

[x].الكيان هو موضوع تجاوز النوع ، مما يعني أنه إما مرتبط أو محوري في حد ذاته.

ولكن كيف يمكن للمطور أن يتوقع كل هذا؟ كل جاذبية طريقة OO ، المعبر عنها بعدة طرق في مبدأ Open-Closed ، ترجع تحديدًا إلى إمكانية التغييرات التي يحق لنا إجراؤها على العمل الذي تم إنجازه مسبقًا ، فضلاً عن حقيقة أن مطور الحلول العالمية لايجب أن يتمتع بحكمة لا حصر لها ، وأن يفهم كيف يمكن للأحفاد تكييف منتجه مع احتياجاتهم.

مع هذا النهج ، فإن إعادة تعريف الأنواع والاختباء من قبل المتحدرين هو نوع من "صمام الأمان" الذي يجعل من الممكن إعادة استخدام فئة موجودة تكاد تكون مناسبة لأغراضنا:

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

[x].يحمي الاختباء من قبل السليل من العديد من حالات الفشل عند إنشاء فئة. من الممكن انتقاد مشروع فيه مستطيل, باستخدام حقيقة ذلكسليل مضلع، يحاول إضافة قمة. بدلاً من ذلك ، يمكن للمرء أن يقترح هيكلًا وراثيًا يتم فيه فصل الأرقام ذات العدد الثابت من الرؤوس عن جميع الأشكال الأخرى ، ولن تظهر المشكلة. ومع ذلك ، عند تصميم هياكل الوراثة ، من الأفضل دائمًا امتلاك الهياكل التي لا تمتلكها استثناءات تصنيفية. لكن هل يمكن القضاء عليها تمامًا؟ عند مناقشة قيود التصدير في إحدى المحاضرات التالية ، سنرى أن هذا غير ممكن لسببين. الأول هو وجود معايير تصنيف متنافسة. ثانيًا ، احتمال ألا يجد المطور الحل الأمثل ، حتى لو كان موجودًا.

التحليل الشامل

هذا القسم مخصص لوصف النهج الوسيط. يتم عرض الحلول العملية الرئيسية في المحاضرة 17.

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


كل واحد منهم هو مثال على التطبيق الصحيح لآليات OO الهامة: الأول - تعدد الأشكال ، والثاني - إعادة تعريف النوع. تبدأ المشاكل عند دمجها لنفس الكيان س. بصورة مماثلة:


تبدأ المشاكل باتحاد اثنين من المشغلين المستقلين والأبرياء تمامًا.

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

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

في أمثلةنا ، عامل التشغيل ق: = بيشير إلى أن الطبقة ولدينتمي إلى مجموعة الأنواع لـ س(لأنه نتيجة لتنفيذ بيان الإنشاء خلق بإنه ينتمي إلى مجموعة الأنواع لـ ب). بنتوذلك لوجود التعليمات خلق ز، ينتمي إلى مجموعة أنواع لـ ز. ولكن بعد ذلك التحدي يشاركسيكون غير صالح للهدف سيكتب ولدوالحجة زيكتب بنت. بصورة مماثلة مستطيلهو في النوع المحدد ل ص، والذي يرجع إلى التخصيص متعدد الأشكال ، ومع ذلك ، الدعوة add_vertexل صيكتب مستطيلسيكون غير صالح.

تقودنا هذه الملاحظات إلى التفكير في الخلق عالميالنهج القائم على قاعدة الكتابة الجديدة:

قاعدة صحة النظام

يتصل x.f (arg)يكون صحيحًا للنظام فقط إذا كان مناسبًا للفئة بالنسبة لـ x، و حج، والتي لها أي أنواع من مجموعات الأنواع الخاصة بها.

في هذا التعريف ، تعتبر المكالمة صحيحة للفئة إذا لم تنتهك قاعدة استدعاء المكون ، والتي تنص على: إذا جهناك فئة أساسية مثل x، عنصر Fيجب أن يتم تصديرها جوالنوع حجيجب أن يكون متوافقًا مع نوع المعلمة الرسمية F. (تذكر ، من أجل التبسيط ، نفترض أن كل روتين فرعي يحتوي على معلمة واحدة فقط ، ولكن ليس من الصعب توسيع القاعدة إلى عدد اعتباطي من الوسائط.)

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

1 لكل كيان ، مجموعة الأنواع الأولية فارغة.

2 بعد أن اجتمع تعليمات أخرى من النموذج إنشاء (SOME_TYPE) أ، يضيف بعض الانواعإلى مجموعة الأنواع لـ أ. (من أجل التبسيط ، سنفترض أن أي تعليمات إنشاءسيتم استبداله بالتعليمات إنشاء (ATYPE) أ، أين نوع- نوع الكيان أ.)

3 مواجهة تخصيص آخر للنموذج أ: = ب، أضف إلى مجموعة أنواع أ ب.

4 لو أهي معلمة رسمية للروتين الفرعي ، بعد تلبية المكالمة التالية مع المعلمة الفعلية ب، أضف إلى مجموعة أنواع أجميع عناصر مجموعة الأنواع لـ ب.

5 سنكرر الخطوتين (3) و (4) حتى تتوقف مجموعات الأنواع عن التغيير.

هذه الصياغة لا تأخذ في الاعتبار آلية العالمية ، ومع ذلك ، من الممكن تمديد القاعدة حسب الحاجة دون أي مشاكل خاصة. الخطوة (5) ضرورية بسبب إمكانية سلاسل التخصيصات والتحويلات (from بل أ، من جل بإلخ.). من السهل أن نفهم أنه بعد عدد محدود من الخطوات ستتوقف هذه العملية.

كما لاحظت ، فإن القاعدة لا تأخذ في الاعتبار تسلسل التعليمات. متى


إنشاء (TYPE1) t ؛ s: = t ؛ إنشاء (TYPE2) ر

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


سيتم الإعلان عن عدم صحة النظام ، على الرغم من حقيقة أن تسلسل تنفيذها لا يؤدي إلى انتهاك النوع.

تم تقديم التحليل الشامل للنظام (بمزيد من التفصيل) في الفصل الثاني والعشرين من الدراسة. في الوقت نفسه ، تم حل مشكلة التباين المشترك ومشكلة قيود التصدير أثناء الميراث. ومع ذلك ، فإن هذا النهج به عيب عملي مؤسف ، وهو: من المفترض أن يتحقق النظام ككلبدلا من كل فئة على حدة. تبين أن القاعدة (4) قاتلة ، والتي عند استدعاء روتين فرعي للمكتبة ، ستأخذ في الاعتبار جميع مكالماتها المحتملة في الفصول الأخرى.

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

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

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

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

حذار من catcalls متعددة الأشكال!

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

العودة إلى يالطا

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

كما في السابق ، نحصر مسألة التغاير في عمليتين. في مثالنا الرئيسي ، هذه مهمة متعددة الأشكال: ق: = ب، واستدعاء الروتين الفرعي المتغير: s.share (g). عند تحليل من هو الجاني الحقيقي للانتهاكات ، فإننا نستبعد الحجة زمن المشتبه بهم. أي حجة من النوع المتزحلقأو المشتق منه ، لا يناسبنا بسبب تعدد الأشكال سوالتغاير يشارك. لذلك ، إذا وصفت الجوهر بشكل ثابت آخركيف المتزحلقوربطها ديناميكيًا بالكائن المتزحلقثم المكالمة s.share (أخرى)ستعطي بشكل ثابت انطباعًا بأنها مثالية ، ولكنها ستؤدي إلى انتهاكات في النوع إذا تم تعيينها بشكل متعدد الأشكال سمعنى ب.

المشكلة الأساسية هي أننا نحاول استخدامها سبطريقتين غير متوافقين: ككيان متعدد الأشكال وكهدف لمكالمة روتين فرعي متغير. (في مثالنا الآخر ، المشكلة هي استخدام صككيان متعدد الأشكال وكهدف لاستدعاء روتين فرعي للطفل الذي يخفي المكون add_vertex.)

حل Catcall ، مثل Pinning ، جذري: فهو يحظر استخدام كيان متعدد الأشكال ومتغير في نفس الوقت. مثل التحليل العام ، فإنه يحدد بشكل ثابت الكيانات التي يمكن أن تكون متعددة الأشكال ، لكنه لا يحاول أن يكون ذكيًا جدًا من خلال البحث عن مجموعات من الأنواع المحتملة للكيانات. بدلاً من ذلك ، يُنظر إلى أي كيان متعدد الأشكال على أنه مريب بدرجة كافية بحيث يُمنع التحالف مع دائرة من الأشخاص المحترمين ، بما في ذلك التغاير والاختباء المتحدرين.

قاعدة واحدة والعديد من التعاريف

قاعدة الكتابة لحل Catcall لها صيغة بسيطة:

اكتب Rule for Catcall

catcalls متعددة الأشكال غير صحيحة.

إنه يقوم على تعريفات بسيطة بنفس القدر. بادئ ذي بدء ، كيان متعدد الأشكال:

التعريف: كيان متعدد الأشكال

جوهر xالنوع المرجعي (غير الموسع) متعدد الأشكال إذا كان يحتوي على إحدى الخصائص التالية:

1 يحدث في مهمة س: = صحيث الجوهر ذله نوع مختلف أو متعدد الأشكال بالعودة.

2 وجدت في تعليمات الإنشاء إنشاء (OTHER_TYPE) x، أين OTHER_TYPEليس من النوع المحدد في الإعلان x.

3 إنها حجة رسمية لإجراء فرعي.

4 هي وظيفة خارجية.

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

في أمثلةنا ، المتزلج سوالمضلع صمتعددة الأشكال وفقًا للقاعدة (1). يتم تعيين كائن أول واحد الصبي ب، والثاني - الكائن مستطيل ص.

إذا نظرت في تعريف مجموعة من الأنواع ، ستلاحظ مدى تشاؤم تعريف الكيان متعدد الأشكال ، ومدى سهولة اختباره. دون محاولة العثور على جميع الأنواع الديناميكية الممكنة للكيان ، نحن راضون عن السؤال العام: هل يمكن لكيان معين أن يكون متعدد الأشكال أم لا؟ الأكثر إثارة للدهشة هي القاعدة (3) ، والتي بموجبها متعدد الأشكالالعد كل معلمة رسمية(ما لم يتم تمديد نوعه ، كما هو الحال مع الأعداد الصحيحة ، وما إلى ذلك). نحن لا نهتم حتى بتحليل المكالمات. إذا كان للروتين الفرعي حجة ، فإنه يكون تحت تصرف العميل بالكامل ، مما يعني أنه لا يمكنك الاعتماد على النوع المحدد في الإعلان. ترتبط هذه القاعدة ارتباطًا وثيقًا بإعادة الاستخدام - الهدف من تقنية الكائن - حيث يمكن تضمين أي فئة في مكتبة ويتم استدعاؤها عدة مرات من قبل عملاء مختلفين.

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

يمكن أن تكون المكالمات ، مثل الكيانات ، متعددة الأشكال:

التعريف: دعوة متعددة الأشكال

تكون المكالمة متعددة الأشكال إذا كان هدفها متعدد الأشكال.

كلا النداءين في الأمثلة لدينا متعدد الأشكال: s.share (g)بسبب تعدد الأشكال س, p.add_vertex (...)بسبب تعدد الأشكال ص. بحكم التعريف ، يمكن أن تكون المكالمات المؤهلة فقط متعددة الأشكال. (إجراء مكالمة غير مؤهلة F(...)نوع من المؤهلين Current.f (...]فنحن لا نغير جوهر الأمر منذ ذلك الحين حاضِر، التي لا يمكن تخصيص أي شيء لها ، ليس كائنًا متعدد الأشكال.)

بعد ذلك ، نحتاج إلى مفهوم Catcall ، استنادًا إلى مفهوم CAT. (CAT هو اختصار لـ Changing Availability أو Type). يعتبر الروتين الفرعي روتينًا فرعيًا لـ CAT إذا أدى بعض إعادة تعريفه بواسطة الطفل إلى أحد نوعين من التغييرات التي رأيناها من المحتمل أن تكون خطيرة: تغيير نوع الوسيطة (بشكل متغاير) أو إخفاء مكون تم تصديره مسبقًا.

التعريف: إجراءات CAT

يُطلق على الروتين اسم روتين CAT إذا أدت إعادة تعريفه إلى تغيير حالة التصدير أو نوع أي من وسائطه.

تسمح هذه الخاصية مرة أخرى بالتحقق المتزايد: أي إعادة تعريف لنوع الوسيطة أو حالة التصدير تجعل الإجراء أو الوظيفة روتينًا فرعيًا لـ CAT. هذا هو المكان الذي تأتي فيه فكرة Catcall: استدعاء إجراء فرعي CAT يمكن أن يكون خاطئًا.

التعريف: Catcall

يُطلق على المكالمة اسم Catcall إذا كان من شأن إعادة تعريف الروتين أن تجعله يفشل بسبب تغيير في حالة التصدير أو نوع الوسيطة.

التصنيف الذي أنشأناه يسمح لنا بتمييز مجموعات خاصة من المكالمات: متعددة الأشكال و catcalls. تمنح الاستدعاءات متعددة الأشكال قوة تعبيرية لمقاربة الكائن ، وتسمح لك الاستدعاءات المتكررة بإعادة تعريف الأنواع وتقييد الصادرات. باستخدام المصطلحات المقدمة سابقًا في هذا الفصل ، يمكننا القول أن المكالمات متعددة الأشكال تمتد فائدة، catcalls - سهولة الاستخدام.

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

درجة

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

لقد رأينا ثلاثة حلول لمشكلة التغاير ، تناول اثنان منها أيضًا قيود التصدير. أيهما صحيح؟

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

يبدو التحليل الشامل غير عملي بسبب الفحص الكامل للنظام بأكمله. ومع ذلك ، فقد ساعدنا على فهم المشكلة بشكل أفضل.

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

إذا اضطررنا إلى التخلي عن التثبيت ، فإن حل Catcall يبدو أنه الأنسب ، والذي يمكن شرحه بسهولة وقابل للتطبيق في الممارسة العملية. لا ينبغي أن يمنع تشاؤمه مجموعات مفيدة من المشغلين. في الحالة التي يتم فيها إنشاء catcall متعدد الأشكال من خلال عبارة "شرعية" ، فمن الآمن دائمًا الاعتراف بها عن طريق تقديم محاولة تعيين. وبالتالي ، يمكن تحويل عدد من الشيكات إلى وقت تنفيذ البرنامج. ومع ذلك ، يجب أن يكون عدد هذه الحالات صغيرًا للغاية.

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

الالتزام التام

في ختام مناقشة التباين المشترك ، من المفيد فهم كيفية تطبيق طريقة عامة على مشكلة عامة إلى حد ما. ظهرت الطريقة كنتيجة لنظرية Catcall ، ولكن يمكن استخدامها في إطار الإصدار الأساسي للغة دون إدخال قواعد جديدة.

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

قد يكون هناك حل بسيط بناءً على المناقشة السابقة ومحاولة التعيين. تأمل الوظيفة العامة تركيب(يعتمد):


المجهزة (أخرى: عامة): مثل الأخرى
- الكائن الحالي (Current) ، إذا كان نوعه يطابق نوع الكائن ،
- تعلق على أخرى ، وإلا باطلة.
إذا كان other / = Void ثم يتوافق مع (other) إذن

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

إستبدال يتوافق معإلى مكون آخر عامبالاسم نفس النوعيهيعطينا وظيفة تركيب مثالي (الالتزام التام) الذي يعود فارغإذا كانت أنواع كلا الكائنين غير متطابقة.

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


- حدد ، إن أمكن ، أخرى كجار رقم.
- Gender_ascertained - تحديد الجنس
Gender_ascertained_other: مثل الحالي
Gender_ascertained_other: = آخر. ملائم (حاليًا)
إذا كان gender_ascertained_other / = لاغٍ إذن
مشاركة (الجنس_المستحق_الآخر)
"الخلاصة: الاستنتاج مع الآخرين غير ممكن"

ل آخرنوع تعسفي المتزحلق(ليس فقط مثل الحالي) تحديد الإصدار الجنس_المستحق_الآخر، والذي تم تعيين نوع له حاضِر. ستساعدنا الوظيفة على ضمان هوية الأنواع. تركيب مثالي.

إذا كانت هناك قائمتان متوازيتان للمتزلجين يمثلان مكان الإقامة المخطط له:


راكب 1 ، راكب 2: LIST

من الممكن تنظيم حلقة عن طريق تنفيذ مكالمة في كل خطوة:


Occupant1.item.safe_share (Occupant2.item)

مطابقة عناصر القائمة إذا وفقط إذا كانت أنواعها متوافقة تمامًا.

المفاهيم الرئيسية

[x].الكتابة الثابتة هي مفتاح الموثوقية وسهولة القراءة والكفاءة.

[x].لكي تكون واقعيًا ، تتطلب الكتابة الثابتة مجموعة من الآليات: التأكيدات ، والوراثة المتعددة ، ومحاولة التخصيص ، والعام المحدود وغير المحدود ، والإعلانات الثابتة. يجب ألا يسمح نظام الكتابة باستخدام الاعتراضات (قوالب الكتابة).

[x].يجب أن تسمح القواعد الأساسية لإعادة الإعلان بإعادة تعريف المتغير المشترك. يجب أن تكون النتيجة التي تم تجاوزها وأنواع الوسيطات متوافقة مع الأنواع الأصلية.

[x].التباين المشترك ، بالإضافة إلى قدرة الطفل على إخفاء عنصر تم تصديره من قبل سلف ، إلى جانب تعدد الأشكال ، يخلق مشكلة انتهاك نوع نادرة ولكنها خطيرة للغاية.

[x].يمكن تجنب هذه الانتهاكات باستخدام: التحليل الشامل (وهو غير عملي) ، وقصر التباين على الأنواع الثابتة (وهو ما يتعارض مع مبدأ Open-Closed) ، وحل Catcall ، الذي يمنع الهدف متعدد الأشكال من استدعاء روتين فرعي مع التغاير أو إخفاء طفل.

ملاحظات ببليوغرافية

تم عرض عدد من المواد من هذه المحاضرة في التقارير في منتديات OOPSLA 95 و TOOLS PACIFIC 95 ، وتم نشرها أيضًا في. تم استعارة عدد من مواد المراجعة من المقال.

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

يمكن العثور على تقنيات تحسين كفاءة التعليمات البرمجية في اللغات المكتوبة ديناميكيًا في سياق اللغة الذاتية.

كتب Luca Cardelli و Peter Wegner مقالة نظرية حول الأنواع في لغات البرمجة التي كان لها تأثير كبير على المتخصصين. هذا العمل ، المبني على أساس حساب لامدا (انظر) ، كان بمثابة الأساس للعديد من الدراسات الإضافية. وسبقه ورقة أساسية أخرى من قبل كارديلي.

يتضمن دليل ISE مقدمة لمشاكل التطبيق المشترك لتعدد الأشكال ، والتغاير ، والاختباء المتحدر. أدى عدم وجود تحليل مناسب في الإصدار الأول من هذا الكتاب إلى عدد من المناقشات النقدية (أولها تعليقات فيليب إلينك في عمل البكالوريوس "De la Conception-Programmation par Objets" ، Memoire de License ، Universite Libre de Bruxelles (بلجيكا) ، 1988) ، معبرًا عنه في الأعمال و. تقدم مقالة كوك العديد من الأمثلة المتعلقة بمشكلة التغاير وتحاول حلها. اقترح فرانز ويبر حلًا يعتمد على معلمات النوع للكيانات المتغيرة في TOOLS EUROPE 1992. يتم تقديم تعريفات دقيقة لمفاهيم صحة النظام ، وكذلك صحة الفئة ، كما تم اقتراح حل باستخدام تحليل نظام كامل هناك. تم اقتراح حل Catcall لأول مرة في ؛ أنظر أيضا .

تم تقديم حل الإصلاح في حديثي في ​​ندوة TOOLS EUROPE 1994. ولكن في ذلك الوقت ، لم أكن أرى الحاجة إلى مِرسَاة-ads وقيود التوافق ذات الصلة. سارع بول دوبوا وأميرام يهودي إلى الإشارة إلى أن مشكلة التغاير لا تزال قائمة في ظل هذه الظروف. هم ، بالإضافة إلى راينهاردت بودي ، وكارل هاينز سيلا ، وكيم والدن ، وجيمس مكيم ، قدموا العديد من التعليقات التي كانت ذات أهمية أساسية في العمل الذي أدى إلى كتابة هذه المحاضرة.

يخصص قدر كبير من الأدب لقضايا التغاير. في و سوف تجد كلاً من ببليوغرافيا شاملة ونظرة عامة على الجوانب الرياضية للمشكلة. للحصول على قائمة روابط لمواد عبر الإنترنت حول نظرية نوع OOP وصفحات الويب الخاصة بمؤلفيها ، راجع صفحة Laurent Dami. يتم استعارة مفهومي التغاير والتناقض من نظرية الفئات. نحن مدينون بظهورهم في سياق برنامج الكتابة إلى Luca Cardelli ، الذي بدأ باستخدامهم في خطاباته في أوائل الثمانينيات ، لكنه لم يلجأ إليهم في الطباعة حتى أواخر الثمانينيات.

الأساليب القائمة على متغيرات النوع موصوفة في ، ،.

تم تطبيق التناقض في لغة Sather. يتم تقديم التفسيرات في.

تحتوي هذه المقالة على الحد الأدنى من الأشياء التي تحتاج فقط لمعرفتها حول الكتابة حتى لا تسمي الكتابة الديناميكية شريرة ، و Lisp لغة غير مكتوبة ، و C لغة مكتوبة بقوة.

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

أوصي بقراءة النسخة القصيرة من المقال أولاً ، ثم قراءة النسخة الكاملة ، إذا كنت ترغب في ذلك.

نسخة مختصرة

تنقسم لغات برمجة الكتابة عادةً إلى معسكرين كبيرين - مكتوب وغير مطبوع (غير مطبوع). الأول يشمل C و Python و Scala و PHP و Lua ، بينما يشمل الأخير لغة التجميع و Forth و Brainfuck.

نظرًا لأن "الكتابة غير المطبوعة" هي بطبيعتها بسيطة مثل الفلين ، فلا يتم تقسيمها إلى أي أنواع أخرى. لكن اللغات المكتوبة مقسمة إلى عدة فئات متداخلة:

  • الكتابة الثابتة / الديناميكية. يتم تحديد Static من خلال حقيقة أن الأنواع النهائية من المتغيرات والوظائف يتم تعيينها في وقت الترجمة. أولئك. بالفعل المترجم متأكد 100٪ أي نوع هو المكان. في الكتابة الديناميكية ، يتم تحديد جميع الأنواع في وقت التشغيل.

    أمثلة:
    ثابت: C ، Java ، C # ؛
    ديناميكي: Python و JavaScript و Ruby.

  • كتابة قوية / ضعيفة (تسمى أحيانًا قوية / فضفاضة). تتميز الكتابة القوية بحقيقة أن اللغة لا تسمح بخلط أنواع مختلفة في التعبيرات ولا تؤدي إلى تحويلات ضمنية تلقائية ، على سبيل المثال ، لا يمكنك طرح مجموعة من سلسلة. تقوم اللغات المكتوبة بشكل ضعيف بإجراء العديد من التحويلات الضمنية تلقائيًا ، حتى لو كان فقدان الدقة أو التحويل غامضًا.

    أمثلة:
    قوي: جافا ، بايثون ، هاسكل ، ليسب ؛
    ضعيف: C ، JavaScript ، Visual Basic ، PHP.

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

    أمثلة:
    صريح: C ++ ، D ، C #
    ضمنيًا: PHP و Lua و JavaScript

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

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

نسخة مفصلة

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

كتابة غير نمطية

في لغات البرمجة غير المصنفة ، تعتبر جميع الكيانات مجرد تسلسلات من وحدات بت ذات أطوال مختلفة.

عادةً ما تكون الكتابة غير النمطية متأصلة في اللغات ذات المستوى المنخفض (لغة المجمع ، فورث) واللغات الباطنية (Brainfuck ، HQ9 ، Piet). ومع ذلك ، إلى جانب عيوبه ، فإن له أيضًا بعض المزايا.

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

نعم ، هذا موجود. على سبيل المثال ، في لغة التجميع (بالنسبة للهندسة المعمارية x86 / x86-64 ، لا أعرف الآخرين) لا يمكنك تجميع برنامج إذا حاولت تحميل البيانات من سجل rax (64 بت) في سجل cx (16 أجزاء).

موف cx ، eax ؛ خطأ وقت التجميع

لذلك اتضح أن المجمع لا يزال يكتب؟ أعتقد أن هذه الفحوصات ليست كافية. ورأيك بالطبع يعتمد عليك فقط.

الكتابة الثابتة والديناميكية

الشيء الرئيسي الذي يميز الكتابة الثابتة (الثابتة) عن الديناميكية (الديناميكية) هو أن جميع عمليات التحقق من النوع يتم إجراؤها في وقت الترجمة ، وليس في وقت التشغيل.

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

دعونا نفهم ذلك.

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

البرمجة العامة

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

كيف سنحلها؟ دعنا نحلها بثلاث لغات مختلفة: واحدة مع الكتابة الديناميكية واثنتان بالكتابة الثابتة.

سآخذ واحدة من أبسط خوارزمية البحث - التعداد. ستستقبل الوظيفة العنصر الذي تم البحث عنه ، المصفوفة (أو القائمة) نفسها وتعيد فهرس العنصر ، أو إذا لم يتم العثور على العنصر - (-1).

الحل الديناميكي (Python):

def find (required_element، list): for (index، element) في التعداد (list): if element == required_element: return index return (-1)

كما ترى ، كل شيء بسيط ولا توجد مشاكل مع حقيقة أن القائمة يمكن أن تحتوي على أرقام زوجية ، أو حتى قوائم ، على الرغم من عدم وجود مصفوفات أخرى. جيد جدًا. دعنا نذهب أبعد من ذلك - حل نفس المشكلة في لغة سي!

محلول ثابت (ج):

find_int غير موقعة (int required_element ، مجموعة int ، حجم int غير موقعة) (لـ (int i = 0 ؛ i< size; ++i) if (required_element == array[i]) return i; return (-1); } unsigned int find_float(float required_element, float array, unsigned int size) { for (unsigned int i = 0; i < size; ++i) if (required_element == array[i]) return i; return (-1); } unsigned int find_char(char required_element, char array, unsigned int size) { for (unsigned int i = 0; i < size; ++i) if (required_element == array[i]) return i; return (-1); }

حسنًا ، كل وظيفة على حدة تشبه إصدار بايثون ، لكن لماذا توجد ثلاثة؟ هل فقدت البرمجة الثابتة؟

نعم و لا. هناك العديد من تقنيات البرمجة ، سننظر في إحداها الآن. إنها تسمى البرمجة العامة ، وتدعمها لغة C ++ جيدًا. دعنا نلقي نظرة على الإصدار الجديد:

حل ثابت (برمجة عامة ، C ++):

نموذج البحث غير الموقعة (T required_element، std :: vector مجموعة) (لـ (بدون إشارة int i = 0 ؛ i< array.size(); ++i) if (required_element == array[i]) return i; return (-1); }

بخير! لا يبدو الأمر أكثر تعقيدًا من إصدار Python ، ولم يتطلب الأمر الكثير من الكتابة. بالإضافة إلى ذلك ، حصلنا على التنفيذ لجميع المصفوفات ، وليس فقط الثلاثة المطلوبة لحل المشكلة!

يبدو أن هذا الإصدار هو بالضبط ما نحتاجه - نحصل على مزايا الكتابة الثابتة وبعض مزايا الديناميكية.

إنه لأمر رائع أنه ممكن ، لكن يمكن أن يكون أفضل. أولاً ، يمكن أن تكون البرمجة العامة أكثر ملاءمة وجمالًا (على سبيل المثال ، في Haskell). ثانيًا ، بالإضافة إلى البرمجة العامة ، يمكنك أيضًا استخدام تعدد الأشكال (ستكون النتيجة أسوأ) ، أو التحميل الزائد للوظيفة (بالمثل) أو وحدات الماكرو.

ثابت في الديناميات

وتجدر الإشارة أيضًا إلى أن العديد من اللغات الثابتة تسمح بالكتابة الديناميكية ، على سبيل المثال:

  • يدعم C # النوع الزائف الديناميكي.
  • يدعم F # السكر النحوي في شكل عامل التشغيل ، والذي يمكن استخدامه لمحاكاة الكتابة الديناميكية.
  • هاسكل - يتم توفير الكتابة الديناميكية بواسطة وحدة Data.Dynamic.
  • دلفي - من خلال نوع خاص متغير.

أيضًا ، تسمح لك بعض اللغات المكتوبة ديناميكيًا بالاستفادة من الكتابة الثابتة:

  • التصريحات الشائعة من نوع Lisp.
  • Perl - منذ الإصدار 5.6 ، محدود نوعًا ما.

كتابة قوية وضعيفة

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

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

غالبًا ما يتم الخلط بين الكتابة الضعيفة والكتابة الديناميكية ، وهو أمر خاطئ تمامًا. يمكن أن تكون اللغة المكتوبة ديناميكيًا مكتوبة بشكل ضعيف وقوي.

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

يجب أن تحتوي اللغة أيضًا على كتابة قوية. في الواقع ، إذا كان المترجم بدلاً من الإبلاغ عن خطأ يضيف سلسلة إلى رقم ، أو الأسوأ من ذلك ، أن يطرح أخرى من مصفوفة واحدة ، فما الفائدة من أن تكون جميع "عمليات التحقق" من الأنواع في مرحلة التجميع؟ هذا صحيح - الكتابة الثابتة الضعيفة أسوأ من الكتابة الديناميكية القوية! (حسنًا ، هذا رأيي)

فلماذا لا تتمتع الكتابة الضعيفة بأي مزايا على الإطلاق؟ قد يبدو الأمر كذلك ، ولكن على الرغم من حقيقة أنني مؤيد قوي للكتابة القوية ، يجب أن أوافق على أن الكتابة الضعيفة لها مزايا أيضًا.

هل تريد أن تعرف أيها؟

فوائد الكتابة القوية
  • الموثوقية - ستحصل على استثناء أو خطأ تجميع بدلاً من سوء التصرف.
  • السرعة - بدلاً من التحويلات الضمنية ، والتي يمكن أن تكون باهظة الثمن ، مع الكتابة القوية ، يجب عليك كتابتها بوضوح ، مما يجعل المبرمج على الأقل يدرك أن هذا الجزء من التعليمات البرمجية يمكن أن يكون بطيئًا.
  • فهم كيفية عمل البرنامج - مرة أخرى ، بدلاً من صب النوع الضمني ، يكتب المبرمج كل شيء بنفسه ، مما يعني أنه يفهم تقريبًا أن مقارنة سلسلة مع رقم لا يحدث من تلقاء نفسه وليس بالسحر.
  • اليقين - عندما تكتب التحولات باليد ، فأنت تعرف بالضبط ما الذي تقوم بتحويله وإلى ماذا. أيضًا ، ستفهم دائمًا أن مثل هذه التحويلات يمكن أن تؤدي إلى فقدان الدقة والنتائج غير الصحيحة.
فوائد الكتابة الضعيفة
  • سهولة استخدام التعبيرات المختلطة (على سبيل المثال ، من الأعداد الصحيحة والأرقام الحقيقية).
  • الاستخلاص من الكتابة والتركيز على المهمة.
  • إيجاز السجل.

حسنًا ، لقد اكتشفنا ذلك ، اتضح أن الكتابة الضعيفة لها أيضًا مزايا! هل توجد أي طرق لنقل مزايا الكتابة الضعيفة إلى الكتابة القوية؟

اتضح أن هناك حتى اثنين.

صب النوع الضمني ، في مواقف لا لبس فيها ودون فقدان البيانات

واو ... فقرة طويلة جدًا. اسمحوا لي أن أختصرها إلى "التحويل الضمني المقيد" فماذا يعني الموقف الواضح وفقدان البيانات؟

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

فقدان البيانات أسهل. إذا قمنا بتحويل الرقم الحقيقي 3.5 إلى عدد صحيح ، فسوف نفقد بعض البيانات (في الواقع ، هذه العملية غامضة أيضًا - كيف يتم التقريب؟ للأعلى؟ للأسفل؟ إسقاط الجزء الكسري؟).

التحويلات في المواقف الغامضة والتحويلات مع فقدان البيانات سيئة للغاية. لا يوجد شيء أسوأ من هذا في البرمجة.

إذا كنت لا تصدقني ، فتعلم لغة PL / I ، أو حتى ابحث عن مواصفاتها. لديها قواعد التحويل بين جميع أنواع البيانات! إنه مجرد جحيم!

حسنًا ، لنتذكر أمر التحويل الضمني المحدود. هل توجد مثل هذه اللغات؟ نعم ، على سبيل المثال في باسكال يمكنك تحويل عدد صحيح إلى رقم حقيقي ، ولكن ليس العكس. هناك أيضًا آليات مماثلة في C # و Groovy و Common Lisp.

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

سأشرحها باستخدام لغة هاسكل الرائعة كمثال.

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

على سبيل المثال ، في التعبير pi + 1 ، لا تريد كتابة pi + 1.0 أو pi + float (1). أريد أن أكتب فقط pi + 1!

ويتم ذلك في هاسكل ، وذلك بفضل حقيقة أن الحرف 1 ليس له نوع ملموس. إنه ليس كليًا ولا حقيقيًا ولا معقدًا. إنه مجرد رقم!

نتيجة لذلك ، عند كتابة مجموع دالة بسيط x y ، والذي يضرب جميع الأعداد من x إلى y (مع زيادة 1) ، نحصل على عدة إصدارات في وقت واحد - مجموع الأعداد الصحيحة ، ومجموع القيم الحقيقية ، ومجموع الأسس المنطقية ، ومجموع المعقد الأرقام ، وحتى جمع كل تلك الأنواع الرقمية التي حددتها بنفسك.

بالطبع ، هذه التقنية تحفظ فقط عند استخدام تعبيرات مختلطة مع حرفية رقمية ، وهذا مجرد غيض من فيض.

وبالتالي ، يمكننا القول إن أفضل طريقة للخروج هي الموازنة بين الكتابة القوية والضعيفة. ولكن حتى الآن ، لا توجد لغة تتمتع بتوازن مثالي ، لذلك أميل أكثر نحو اللغات المكتوبة بقوة (مثل Haskell و Java و C # و Python) بدلاً من اللغات المكتوبة بشكل ضعيف (مثل C و JavaScript و Lua و PHP) .

الكتابة الصريحة والضمنية

تتطلب اللغة المكتوبة صراحةً من المبرمج تحديد أنواع جميع المتغيرات والوظائف التي يصرح بها. المصطلح الإنجليزي لهذا هو الكتابة الصريحة.

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

في البداية ، قد يعتقد المرء أن الكتابة الضمنية تعادل الكتابة الديناميكية ، وأن الكتابة الصريحة تعادل الكتابة الثابتة ، لكننا سنرى لاحقًا أن هذا ليس هو الحال.

هل هناك مزايا لكل نوع ، ومرة ​​أخرى ، هل هناك مجموعات منها وهل هناك أي لغات تدعم كلا الطريقتين؟

فوائد الكتابة الصريحة
  • إن وجود توقيع لكل دالة (على سبيل المثال ، int add (int ، int)) يجعل من السهل تحديد وظيفة الوظيفة.
  • يكتب المبرمج على الفور نوع القيم التي يمكن تخزينها في متغير معين ، مما يلغي الحاجة إلى تذكر ذلك.
فوائد الكتابة الضمنية
  • الاختزال - def add (x، y) هو بوضوح أقصر من int add (int x، int y).
  • المرونة في التغيير. على سبيل المثال ، إذا كان المتغير المؤقت في إحدى الوظائف من نفس نوع وسيطة الإدخال ، ففي لغة مكتوبة بشكل واضح ، عندما يتغير نوع وسيطة الإدخال ، سيحتاج نوع المتغير المؤقت أيضًا إلى التغيير.

حسنًا ، يبدو أن كلا النهجين لهما إيجابيات وسلبيات (ومن توقع أي شيء آخر؟) ، لذلك دعونا نبحث عن طرق للجمع بين هذين النهجين!

الكتابة الصريحة عن طريق الاختيار

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

لا يوجد نوع صريح يضيف (س ، ص) = س + ص - نوع صريح إضافة :: (عدد صحيح ، عدد صحيح) -> عدد صحيح إضافة (س ، ص) = س + ص

ملاحظة: لقد استخدمت عمدا وظيفة غير مؤذية ، وكتبت عن قصد أيضًا توقيعًا خاصًا بدلاً من الإضافة الأكثر عمومية :: (Num a) -> a -> a -> a ، لأن أردت أن أعرض الفكرة دون أن أشرح بناء جملة هاسكل.

جلالة الملك. كما نرى ، إنها لطيفة جدًا وقصيرة. يستغرق إدخال الوظيفة 18 حرفًا فقط لكل سطر ، بما في ذلك المسافات!

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

هل هناك لغات بها كتابة صريحة بشكل افتراضي وكتابة ضمنية بحكم الضرورة؟ كون
بالتأكيد.

الكتابة الضمنية بالاختيار

قدم معيار لغة C ++ الجديد ، المسمى C ++ 11 (المعروف سابقًا باسم C ++ 0x) ، الكلمة الأساسية التلقائية ، والتي تسمح للمترجم باستنتاج النوع من السياق:

دعنا نقارن: // مواصفات النوع اليدوي غير موقعة int a = 5 ؛ عدد صحيح ب = أ + 3 ؛ // نوع الاستدلال التلقائي بدون إشارة int a = 5 ؛ تلقائي ب = أ + 3 ؛

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

// نوع يدوي الأمراض المنقولة جنسيا :: متجه Vec = randomVector (30) ؛ لـ (std :: vector :: const_iterator it = vec.cbegin () ؛ ...) (...) // Automatic Type Inference auto vec = randomVector (ثلاثون) ؛ لـ (auto it = vec.cbegin () ؛ ...) (...)

رائع! هنا هو الاختصار. حسنًا ، لكن هل من الممكن عمل شيء بروح هاسكل ، حيث يعتمد نوع الإرجاع على أنواع الحجج؟

مرة أخرى ، الإجابة هي نعم ، وذلك بفضل الكلمة الأساسية "رفض" جنبًا إلى جنب مع "تلقائي":

// Manual type int divide (int x، int y) (...) // Automatic type deduction auto divide (int x، int y) -> dentype (x / y) (...)

قد لا يبدو هذا الشكل من التدوين رائعًا ، ولكن عند دمجه مع الأدوية الجنيسة (القوالب / الأدوية) ، فإن الكتابة الضمنية أو الاستدلال التلقائي للكتابة تعمل العجائب.

بعض لغات البرمجة حسب هذا التصنيف

سأقدم قائمة قصيرة باللغات الشائعة وأكتب كيف يتم تصنيفها تحت كل فئة "كتابة".

جافا سكريبت - ديناميكي / ضعيف / روبي ضمني - ديناميكي / قوي / بايثون ضمني - ديناميكي / قوي / ضمني جافا - ثابت / قوي / صريح PHP - ديناميكي / ضعيف / ضمني C - ثابت / ضعيف / صريح C ++ - ثابت / شبه قوي / صريح بيرل - ديناميكي / ضعيف / ضمني الهدف- C - ثابت / ضعيف / صريح C # - ثابت / قوي / صريح هاسكل - ثابت / قوي / ضمني لثغة مشتركة - ديناميكي / قوي / ضمني

ربما أخطأت في مكان ما ، خاصةً مع CL و PHP و Obj-C ، إذا كان لديك رأي مختلف في بعض اللغات ، فاكتب في التعليقات.

  • الكتابة الديناميكية هي تقنية تستخدم على نطاق واسع في لغات البرمجة ولغات المواصفات ، حيث يرتبط المتغير بنوع ما في وقت تعيين القيمة ، وليس في وقت الإعلان عن المتغير. وبالتالي ، في أجزاء مختلفة من البرنامج ، يمكن أن يأخذ نفس المتغير قيمًا من أنواع مختلفة. أمثلة على اللغات المكتوبة ديناميكيًا هي Smalltalk و Python و Objective-C و Ruby و PHP و Perl و JavaScript و Lisp و xBase و Erlang و Visual Basic.

    الأسلوب المعاكس هو الكتابة الثابتة.

    في بعض اللغات ذات الكتابة الديناميكية الضعيفة ، توجد مشكلة في مقارنة القيم ، على سبيل المثال ، تحتوي PHP على عوامل المقارنة "==" ، "! =" و "===" ، "! ==" ، حيث الزوج الثاني من العمليات يقارن القيم وأنواع المتغيرات. يتم تقييم عامل التشغيل "===" إلى صحيح فقط إذا كان يتطابق تمامًا ، على عكس "==" الذي يعتبر التعبير التالي صحيحًا: (1 == "1"). من الجدير بالذكر أن هذه ليست مشكلة الكتابة الديناميكية بشكل عام ، ولكن من لغات البرمجة المحددة.

المفاهيم ذات الصلة

لغة البرمجة هي لغة رسمية لكتابة برامج الكمبيوتر. تحدد لغة البرمجة مجموعة من القواعد المعجمية والنحوية والدلالية التي تحدد مظهر البرنامج والإجراءات التي سيؤديها المؤدي (كمبيوتر عادةً) تحت سيطرته.

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

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

إن Extended Backus-Naur Form (EBNF) هو نظام تعريف نحوي رسمي يتم فيه تحديد بعض الفئات النحوية بشكل تسلسلي من خلال فئات أخرى. تستخدم لوصف القواعد النحوية الرسمية الخالية من السياق. اقترحه نيكلاوس ويرث. إنها إعادة صياغة موسعة لأشكال باكوس نور ، تختلف عن BNF في الإنشاءات "الأكثر رحابة" ، والتي ، بنفس القدرة التعبيرية ، تجعل من الممكن تبسيط ...

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

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

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

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

نوع البيانات الجبرية المعمم (GADT) هو أحد أنواع أنواع البيانات الجبرية ، والتي تتميز بحقيقة أن منشئيها يمكنهم إرجاع قيم ليست من النوع المرتبط بها. صمم تحت تأثير الأعمال على العائلات الاستقرائية بين الباحثين من الأنواع التابعة.

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

البرمجة الموجهة للكائنات (OOP) هي منهجية برمجة تعتمد على تمثيل البرنامج كمجموعة من الكائنات ، كل منها يمثل مثيلًا لفئة معينة ، وتشكل الفئات تسلسلًا هرميًا للميراث.

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

كل شيء بسيط للغاية. إنه مثل الفرق بين فندق وشقة خاصة.

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

يمكن لعائلة سيدوروف العيش في الفندق لفترة من الوقت. ليس عليهم حتى التسجيل هناك. ثم سيغادرون هناك ، وسوف ينتقل Pupkins إلى هناك. ثم كوزنتسوف. ثم شخص آخر. هذه كتابة ديناميكية.

إذا عدنا إلى البرمجة ، فإن الحالة الأولى (الكتابة الثابتة) تحدث ، على سبيل المثال ، C و C ++ و C # و Java وغيرها. قبل أن تقوم بالتخصيص لأول مرة قيمة متغيرة، يجب أن تخبر بما ستخزنه هناك: الأعداد الصحيحة وأرقام الفاصلة العائمة والسلاسل وما إلى ذلك ( سوف يعيش سيدوروف في هذه الشقة). الكتابة الديناميكية ، من ناحية أخرى ، ليست مطلوبة. عندما تقوم بتعيين قيمة ، فأنت تقوم في نفس الوقت بتعيين نوع متغير ( يعيش الآن Vasya Pupkin من عائلة Pupkin في هذه الغرفة الفندقية). يوجد هذا في لغات مثل PHP و Python و JavaScript.

كلا النهجين لهما مزايا وعيوب. أيهما أفضل أم أسوأ يعتمد على المهام المراد حلها. يمكن العثور على مزيد من التفاصيل ، على سبيل المثال ، على ويكيبيديا.

باستخدام الكتابة الثابتة ، فأنت تعرف بالضبط نوع المتغير وقت كتابة البرنامج وتطوير الخوارزمية ، وتأخذ ذلك في الاعتبار. أولئك. إذا قلت أن المتغير G عبارة عن عدد صحيح بدون إشارة مكون من أربعة بايت ، فسيكون دائمًا في الخوارزمية عددًا صحيحًا بدون إشارة من أربعة بايت (إذا كان هناك أي شيء ، فأنت بحاجة إلى تحويله صراحة أو معرفة كيفية تحويل المترجم له في دائرة معينة من المواقف ، ولكن بشكل أساسي إذا كان هناك عدم تطابق في النوع ، فهذا خطأ في الخوارزمية ، وسيحذرك المترجم على الأقل) ، مع ثابت لا يمكنك وضع السلسلة النصية "Vasya the fool" في الرقم والشيكات الإضافية قبل استخدام المتغير لـ "هل هناك رقم" - غير مطلوب ، فأنت تقضي كل صحة البيانات في وقت إدخالها في البرنامج أو كما هو مطلوب بواسطة الخوارزمية نفسها.

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