سؤال

اعتادت ويكيبيديا أن تقول* بطة:

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

(* Ed. ملاحظة: منذ نشر هذا السؤال ، تم تحرير مقالة Wikipedia لإزالة كلمة "Dynamic".).

تقول عنها الكتابة الهيكلية:

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

يتناقض مع الأنظمة الفرعية الهيكلية مع بطة التصميم كما هو:

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

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

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

لذا فإن سؤالي هو: لماذا لا يمكنني استدعاء تصميم البطة الفرعية الهيكلية؟ هل هناك حتى لغات مكتوبة ديناميكيًا والتي لا يمكن تصنيفها أيضًا على أنها مملوءة بالبط؟

بوستسكريبت:

كشخص اسمه Daydreamdrunk على reddit.com لذلك وضعت ببلاغة "إذا كان يجمع مثل البط وروابط مثل البط ..."

بعد بوستسكريبت

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

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

المحلول

قوالب C ++ و D هي مثال مثالي على كتابة البط غير ديناميكي. إنه بالتأكيد:

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

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

نصائح أخرى

نظام النوع الهيكلي

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

كتابة البط

تعتبر كتابة البطة نوعين متكافئين للمهمة في متناول اليد إذا كان بإمكانهما التعامل مع هذه المهمة. لنوعين A و B أن تكون مكافئة لقطعة من الكود تريد الكتابة إلى ملف ، A و B كلاهما يجب أن ينفذ طريقة الكتابة.

ملخص

أنظمة النوع الهيكلي تقارن كل توقيع طريقة (بنية كاملة). تقارن كتابة البط الطرق ذات الصلة بمهمة محددة (بنية ذات صلة بمهمة ما).

يعني كتابة البط إذا كان الأمر مناسبًا ، فلا بأس

ينطبق هذا على كلاهما المكتوب ديناميكيًا

def foo obj
    obj.quak()
end

أو مكتوبة بشكل ثابت ، اللغات المترجمة

template <typename T>
void foo(T& obj) {
    obj.quak();
}

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

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

سيكون رمز مكتوب هيكليًا (على غرار Scala) للمثال أعلاه

def foo(obj : { def quak() : Unit }) {
    obj.quak()
}

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

لست متأكدًا مما إذا كان يجيب حقًا على سؤالك ، لكن ...

يشبه رمز C ++ templated إلى حد كبير ، ولكنه ثابت ، وقت التجميع ، الهيكلية.

template<typename T>
struct Test
{
    void op(T& t)
    {
        t.set(t.get() + t.alpha() - t.omega(t, t.inverse()));
    }
};

أفهم أن الكتابة الهيكلية تستخدم من خلال الاستدلالات النوعية وما شابه ذلك لتحديد معلومات النوع (فكر في Haskell أو OCAML) ، في حين أن كتابة البط لا تهتم بـ "أنواع" في حد ذاتها ، فقط يمكن أن يتعامل الشيء الوصول إلى الممتلكات ، وما إلى ذلك (فكر respond_to? في Ruby أو القدرة على التحقق من JavaScript).

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

var x:Object = new SomeClass();
if ("begin" in x) {
    x.begin();
}

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

هناك مواقف تتصرف فيها كتابة البط الديناميكية والرمز الثابتة المماثلة (في IE C ++) بشكل مختلف:

template <typename T>
void foo(T& obj) {
    if(obj.isAlive()) {
        obj.quak();
    }
}

في C ++ ، يجب أن يكون للكائن كلاهما isAlive و quak طرق الرمز لتجميع ؛ بالنسبة للرمز المكافئ في اللغات المكتوبة ديناميكيًا ، يحتاج الكائن فقط إلى الحصول على quak طريقة إذا isAlive() يعود صحيح. أفسر هذا على أنه فرق بين الهيكل (الكتابة الهيكلية) والسلوك (كتابة البط).

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

أرى "كتابة البط" أكثر كأسلوب برمجة ، في حين أن "الكتابة الهيكلية" هي ميزة نظام النوع.

تشير الكتابة الهيكلية إلى قدرة نظام النوع التعبير الأنواع التي تتضمن جميع القيم التي لها خصائص هيكلية معينة.

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

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

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

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top