ما الفرق بين اللغة المكتوبة بقوة واللغة المكتوبة بشكل ثابت؟

StackOverflow https://stackoverflow.com/questions/2690544

سؤال

وأيضاً هل أحدهما يدل على الآخر؟

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

المحلول

ما هو الفرق بين اللغة المكتوبة بقوة ولغة مكتوبة بشكل ثابت؟

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

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

ثابت مقابل ديناميكي

عكس الكتابة الثابتة "مطبوعة ديناميكيًا" ، مما يعني ذلك

  1. يتم تصنيف القيم المستخدمة في وقت التشغيل إلى أنواع.
  2. هناك قيود على كيفية استخدام هذه القيم.
  3. عندما يتم انتهاك هذه القيود ، يتم الإبلاغ عن انتهاك كخطأ من النوع (الديناميكي).

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

قوي مقابل ضعيف

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

ما الذي يحدث حقًا هنا؟

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

  • غالبًا ما يخلط الهواة مع "ثابت" و "ديناميكي".

  • يبدو أن "الكتابة الضعيفة" يستخدم من قبل بعض الأشخاص للحديث عن الانتشار النسبي أو عدم وجود تحويلات ضمنية.

  • لا يمكن للمهنيين الاتفاق على ما تعنيه الشروط بالضبط.

  • بشكل عام ، من غير المرجح أن تقوم بإبلاغ جمهورك أو تنويره.

الحقيقة المحزنة هي أنه عندما يتعلق الأمر بكتابة الأنظمة ، "القوي" و "الضعيف" ليس لديهم معنى تقني متفق عليه عالميًا. إذا كنت ترغب في مناقشة القوة النسبية لأنظمة النوع ، فمن الأفضل مناقشة الضمانات التي يتم توفيرها بالضبط ولا يتم توفيرها. على سبيل المثال ، سؤال جيد لطرحه هو: "هل كل قيمة لنوع معين (أو فئة) مضمونة بإنشائها عن طريق استدعاء أحد منشئي هذا النوع؟" في ج الجواب هو لا. في Clu و F#و Haskell إنه نعم. بالنسبة لـ C ++ ، لست متأكدًا - أود أن أعرف.

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

هل يعني أحدهما الآخر؟

على مستوى متحمس ، لا ، لأن كلمة "قوية" لا تعني حقًا أي شيء. لكن في الممارسة العملية ، يقوم الناس دائمًا بعمل واحد من شيئين:

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

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

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

نصائح أخرى

غالبًا ما يُساء فهم هذا الأمر، لذا اسمحوا لي أن أوضح الأمر.

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

الكتابة الثابتة هو المكان الذي يرتبط فيه النوع بـ عامل.يتم فحص الأنواع في وقت الترجمة.

الكتابة الديناميكية هو المكان الذي يرتبط فيه النوع بـ قيمة.يتم فحص الأنواع في وقت التشغيل.

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

String s = "abcd";

s سيكون "إلى الأبد" أ String.خلال حياته قد يشير إلى مختلفة Stringس (منذ s هو مرجع في جافا).قد يكون لها null القيمة ولكنها لن تشير أبدًا إلى Integer أو أ List.هذه كتابة ثابتة.

في PHP:

$s = "abcd";          // $s is a string
$s = 123;             // $s is now an integer
$s = array(1, 2, 3);  // $s is now an array
$s = new DOMDocument; // $s is an instance of the DOMDocument class

هذه كتابة ديناميكية.

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

(تحرير التنبيه!)

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

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

الكتابة ضعيفة يشير ذلك إلى أن المترجم لا يفرض نظامًا للكتابة، أو ربما يمكن بسهولة تخريب هذا التنفيذ.

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

String s = "abc" + 123; // "abc123";

هذا الكود هو مثال للترويج الضمني:يتم تحويل 123 ضمنيًا إلى سلسلة قبل أن يتم تسلسلها "abc".يمكن القول أن مترجم Java يعيد كتابة هذا الكود على النحو التالي:

String s = "abc" + new Integer(123).toString();

خذ بعين الاعتبار مشكلة PHP الكلاسيكية "تبدأ بـ":

if (strpos('abcdef', 'abc') == false) {
  // not found
}

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

يوضح هذا المثال كيف يمكن لمزيج من التحويل الضمني والكتابة الديناميكية أن يؤدي إلى ضلال المبرمجين.

قارن ذلك بروبي:

val = "abc" + 123

وهو خطأ في وقت التشغيل لأنه في روبي هدف 123 هو لا تم تحويله ضمنيًا فقط لأنه تم تمريره إلى ملف + طريقة.في روبي، يجب على المبرمج أن يجعل التحويل واضحًا:

val = "abc" + 123.to_s

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

ثابت/ديناميكي مقابل قوي/ضعيف

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

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

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

ولكن من المهم أن نفهم أن اللغة يمكن أن تكون ثابتة/قوية، ثابتة/ضعيفة، ديناميكية/قوية أو ديناميكية/ضعيفة.

كلاهما أعمدة على محورين مختلفين:

  • كتبت بقوة مقابل الكتابة بشكل ضعيف
  • تم كتابتها بشكل ثابت مقابل الكتابة ديناميكيًا

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

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

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

لا يعني إكراه البيانات بالضرورة مكتوبة بشكل ضعيف لأنه في بعض الأحيان السكر العلمي:

مثال أعلاه من جافا يتم كتابته بشكل ضعيف بسبب

String s = "abc" + 123;

ليس مثالًا مكتوبًا بشكل ضعيف لأنه يفعل حقًا:

String s = "abc" + new Integer(123).toString()

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

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

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

تعديل:بعد أن فكرت في ذلك ، ليس بالضرورة صحيحًا لأن وقت التشغيل لا يجب أن يكون لجميع الأنواع المُحيدة في نظام وقت التشغيل ليكون نظامًا قويًا. لدى Haskell و ML تحليلًا ثابتًا كاملاً لدرجة أنهما يمكنهما محتملين لمعلومات نوع Ommit من وقت التشغيل.

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

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

ربما تعني الكتابة القوية أن المتغيرات لها نوع محدد جيدًا وأن هناك قواعد صارمة حول الجمع بين متغيرات الأنواع المختلفة في التعبيرات. على سبيل المثال ، إذا كان A عبارة عن عدد صحيح و B عبارة عن تعويم ، فقد تكون القاعدة الصارمة حول A+B هي أن A يتم إلقاؤها على تعويم وعادت النتيجة كتعويم. إذا كانت A عبارة عن عدد صحيح و B عبارة عن سلسلة ، فقد تكون القاعدة الصارمة هي أن A+B غير صالحة.

ربما تعني الكتابة الثابتة أن الأنواع يتم تعيينها في وقت الترجمة (أو ما يعادلها للغات غير المنقوشة) ولا يمكن تغييرها أثناء تنفيذ البرنامج.

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

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

تم تقديم الإجابة بالفعل أعلاه. في محاولة للتمييز بين الأسبوع القوي مقابل الأسبوع الثابت مقابل المفهوم الديناميكي.

ما الذي تم كتابته بقوة مقابل مكتوبة بشكل ضعيف؟

كتبت بقوة: لن يتم تحويلها تلقائيًا من نوع إلى آخر

في GO أو Python مثل اللغات المكتوبة بقوة "2" + 8 سوف ترفع خطأ في النوع ، لأنها لا تسمح بـ "الإكراه نوع".

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

مثال بيرل:

my $a = "2" + 8;
print $a,"\n";

احفظه إلى main.pl و raut perl main.pl وستحصل على الإخراج 10.

ما هو النوع الثابت مقابل النوع dyamic؟

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

  • ثابت: الأنواع التي تم فحصها قبل وقت التشغيل
  • ديناميكية: الأنواع التي تم فحصها في الذبابة ، أثناء التنفيذ

ماذا يعني هذا؟

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

package main

import "fmt"

func foo(a int) {
    if (a > 0) {
        fmt.Println("I am feeling lucky (maybe).")
    } else {
        fmt.Println("2" + 8)
    }
}

func main() {
    foo(2)
}

احفظ هذا الملف في main.go وقم بتشغيله ، ستحصل على رسالة فاشلة تجميع لهذا.

go run main.go
# command-line-arguments
./main.go:9:25: cannot convert "2" (type untyped string) to type int
./main.go:9:25: invalid operation: "2" + 8 (mismatched types string and int)

ولكن هذه القضية غير صالحة للبيثون. على سبيل المثال ، سيتم تنفيذ كتلة الكود التالية لمكالمة FOOR FOO (2) وسوف تفشل في مكالمة FOO (0) الثانية. ذلك لأن Python يتم كتابتها ديناميكيًا ، فهو يترجم فقط ويكتب الكود الذي يتم تنفيذه عليه. لا تنفذ الكتلة الأخرى أبدًا لـ FOO (2) ، لذا فإن "2" + 8 لا يتم النظر إليها أبدًا وللاستدعاء Foo (0) سيحاول تنفيذ تلك الكتلة وفشلها.

def foo(a):
    if a > 0:
        print 'I am feeling lucky.'
    else:
        print "2" + 8
foo(2)
foo(0)

سترى الإخراج التالي

python main.py
I am feeling lucky.
Traceback (most recent call last):
  File "pyth.py", line 7, in <module>
    foo(0)
  File "pyth.py", line 5, in foo
    print "2" + 8
TypeError: cannot concatenate 'str' and 'int' objects
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top