سؤال

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

هل كانت مفيدة؟

المحلول

  • كتابة ثابتة/ديناميكية حول متى يتم الحصول على معلومات الكتابة (إما في وقت الترجمة أو في وقت التشغيل)

  • كتابة قوية/ضعيفة حول كيف بدقة يتم تمييز الأنواع (على سبيل المثال ما إذا كانت اللغة تحاول إجراء تحويل ضمني من الأوتار إلى الأرقام).

انظر ويكي صفحة لمزيد من المعلومات التفصيلية.

نصائح أخرى

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

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

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

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

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

على سبيل المثال في جافا:

String str = "Hello";  //statically typed as string
str = 5;               //would throw an error since java is statically typed

بينما في أ لغة مطبوعة ديناميكيا النوع هو متحرك, ، المعنى بعد تعيين متغير على نوع ما ، يمكنك تغييره. ذلك لأن الكتابة مرتبطة بالقيمة بدلاً من المتغير.

على سبيل المثال في بيثون:

str = "Hello" # it is a string
str = 5       # now it is an integer; perfectly OK

من ناحية أخرى ، كتابة قوية/ضعيفة في اللغة مرتبطة بتحويلات النوع الضمني (مأخوذة جزئيًا من إجابة @Dario):

على سبيل المثال في بيثون:

str = 5 + "hello" 
# would throw an error since it does not want to cast one type to the other implicitly. 

بينما في PHP:

$str = 5 + "hello"; // equals 5 because "hello" is implicitly casted to 0 
// PHP is weakly typed, thus is a very forgiving language.

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

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

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

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

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

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

وبالمثل ، ستظل اللغات المكتوبة بقوة تتحول تلقائيًا بين الأعداد الصحيحة والعوامات (وبعض اللغات الدقيقة Abitrary Bigints).

اليوم بحثًا عن هذا الموضوع ، صادفت هذا المقال الرائع http://blogs.perl.org/users/ovid/2010/08/what-to-know-before-debating-type-systems.html قامت بمسح الكثير من الأشياء بالنسبة لي واعتقدت أنها قد تضيف إلى بعض الإجابات الرائعة أعلاه.

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

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

أنواع ثابتة وديناميكية

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

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

أنواع صريحة/ضمنية:

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

من سكوت البرمجة البراغماتية, ، الطبعة الثالثة صفحة 291 ، لدينا

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

بعض الأمثلة: يتم كتابة ADA بقوة ، وبالنسبة للجزء الأكبر تم كتابتها بشكل ثابت (يجب التحقق من قيود نوع معينة في وقت التشغيل). يمكن أن يقوم تنفيذ Pascal أيضًا بمعظم فحص نوعه في وقت الترجمة ، على الرغم من أن اللغة ليست مكتوبة بقوة: سجلات متغير غير محدودة (تتم مناقشتها في القسم 7.3.4) هي ثغرةها الوحيدة. يتم كتابة C89 بقوة أكبر من لهجات سلفها ، ولكن لا يزال يتم كتابته بقوة أقل بكثير من Pascal. تشمل ثغراتها النقابات ، والأرقام المتغيرة من الروتين الفرعي من المعلمات ، وقابلية التشغيل البيني للمؤشرات والمصفوفات (ستناقش في القسم 7.7.1). نادراً ما تحقق تطبيقات C من أي شيء في وقت التشغيل.

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

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

لقد حاولت ترجمة وصف Scott إلى مخطط جميل ، والذي نشرته أدناه.

The Static/Dynamic - Strong/Weak Typing Plane

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

هنا مثالان:

  • يقول البعض أن هاسكل مكتوب بشدة ، لأنه لا يُسمح لك بالتصنيع أي اكتب التحويلات.

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

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

بشكل ثابت V/S اللغات المكتوبة ديناميكيًا

  • اللغات المكتوبة بشكل ثابت هي تلك التي يتم فيها إجراء فحص النوع في وقت الترجمة ، لذلك هذا يعني أيضًا أنه في اللغات المكتوبة بشكل ثابت ، كل متغير له نوع ولا يتغير خلال الدورة التدريبية. الآن ، على النقيض من ذلك ، اللغات المكتوبة ديناميكيًا هي تلك التي يتم فيها إجراء فحص النوع في وقت التشغيل ، ولا يوجد أي نوع فحص في وقت الترجمة ، لذلك هذا يعني أيضًا أنه في اللغات المكتوبة ديناميكيًا قد يكون أو لا يكون هناك نوع مرتبط بالمتغيرات, ، وإذا ارتبط نوع ما ، فقد يكون نوعًا عامًا مثل "var" في JS والذي يمتلك جيدًا لكل من السلسلة والرقم.
    • "تربط تطبيقات اللغات التي يتم فحصها ديناميكيًا بشكل عام كل كائن وقت تشغيل مع علامة النوع (أي ، مرجع إلى نوع) يحتوي على معلومات النوع الخاصة به. يمكن أيضًا استخدام معلومات نوع وقت التشغيل (RTTI) لتنفيذ الإرسال الديناميكي ، والربط المتأخر ، والأسفل ، والتفكير ، والميزات المماثلة. "
  • حتى إذا كانت اللغة يتم كتابتها بشكل ثابت ، فلا يزال من الممكن أن تحتوي على بعض الميزات المكتوبة ديناميكيًا ، مما يعني أساسًا أن نوعًا من الفحص في وقت التشغيل أيضًا. هذا مفيد في صب الأنواع.
    • "لا يمكن فحص عدد من ميزات لغة البرمجة المفيدة والشائعة بشكل ثابت ، مثل الصب لأسفل. وبالتالي ، سيكون لدى العديد من اللغات فحص النوع الثابت والديناميكي ؛ يتحقق مدقق النوع الثابت ما يمكنه ، والتحقق الديناميكي تحقق من الباقي. "
  • "تسمح بعض اللغات بالكتابة التي لم تكن آمنة من النوع. على سبيل المثال ، في C ، يمكن للمبرمجين إلقاء قيمة بحرية بين أي نوعين لهما نفس الحجم. "
  • ميزة اللغات المكتوبة "بشكل ثابت" هي:
    • نظرًا لأنه يتم إجراء فحص النوع في وقت الترجمة بحيث يمكن أن يعمل المترجم أو وقت التشغيل بأقصى سرعة ، دون القلق بشأن الأنواع.
    • إنه يؤدي إلى عدد أقل من استثناء وقت التشغيل أو الأخطاء المتعلقة بالنوع ، لأن معظم فحص النوع يتم في وقت الترجمة.
  • ميزة اللغات المكتوبة "ديناميكيًا" هي:
    • يمكن أن تساعد في النماذج الأولية السريعة للغاية ، نظرًا لأن المطور لا يحتاج إلى فهم نظام النوع حتى يتمكن Dev من إنشاء متغيرات بشكل فضفاض وتشغيله ، وهذا يؤدي إلى النماذج الأولية السريعة للغاية.
  • قائمة اللغات المكتوبة بشكل ثابت وديناميكي:
    • ثابتة:
      • جافا
      • C (C هي لغة مكتوبة بشكل ثابت ولكنها تكتب "بقوة" مقارنة بـ Java لأنها تتيح تحويلات أكثر ضمنية)
      • C ++
      • ج#
    • ديناميكيا:
      • بيرل
      • بي أتش بي
      • بيثون
      • جافا سكريبت
      • روبي
  • يعد فحص النوع ميزة أمان مهمة. لنفترض أنه لا يوجد فحص من النوع ، وأسلوب يقبل كائن من النوع "BankAccount" الذي يحتوي على طريقة تسمى "CreditAccount (BankAccountDetails)" ، الآن في وقت التشغيل إذا لم يكن هناك أي نوع من التحقق من النوع ، يمكنني تمرير كائن خاص بي الفئة التي لها نفس الطريقة "CreditAccount (BankAccountDetails)" وسيتم تنفيذها ، مع الأخذ في الاعتبار أننا نتحدث عن اللغة الموجهة نحو الكائن لأن OOP يدعم "تعدد الأشكال" وهنا ما نناقشه ليس سوى "تعدد الأشكال". لذلك ، في الأساس لغة موجهة للكائن (والتي تعني بشكل أساسي أنها تدعم "تعدد الأشكال") والتي لا تحتوي على فحص قوي يمكن أن يؤدي إلى مشكلات أمان.

بقوة v/s اللغات المكتوبة بشكل ضعيف

  • اللغات المكتوبة بقوة هي تلك التي لا يُسمح فيها بتحويلات ضمنية إذا كان هناك فقدان للدقة. على سبيل المثال ، في Java ، يمكنك إلقاء "int to long" لأنه لا توجد خسارة للدقة ، لكن لا يمكنك "ضمنيًا" إلقاء "طويل إلى int" لأنه سيكون هناك فقدان للدقة. في المقابل ، في اللغات المكتوبة بشكل ضعيف ، يُسمح بتحويلات ضمنية حتى لو كانت هناك فقدان الدقة.
  • أعتقد أن اللغة المكتوبة ديناميكيًا يمكن أن تكون أيضًا لغة مكتوبة بقوة إذا "في وقت التشغيل" ، فهي لا تسمح بتحويلات ضمنية تكون هناك فقدان للدقة.

مزيد من القراءات

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

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

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

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

char *a = "123";
int b = (int)a;

سوف ينتج رمز Java المكافئ خطأ في الترجمة ، وهو الأفضل عمومًا:

String a = "123"
int b = (int)a;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top