سؤال

هل يمكنني تحديد الواجهات عندما أعلن عضوًا؟

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

public interface IMyInterface
{
  public void MyMethod();
}

public class MyClass  //Does not explicitly implement IMyInterface
{
  public void MyMethod()  //But contains a compatible method definition
  {
    Console.WriteLine("Hello, world!");
  }
}

...

public void CallMyMethod(IMyInterface m)
{
  m.MyMethod();
}

...

MyClass obj = new MyClass();
CallMyMethod(obj);     // Automatically recognize that MyClass "fits" 
                       // MyInterface, and force a type-cast.

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

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

المحلول

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

والآن، هل يمكن بناء المزيد من المعلومات الاستخبارية في المجمع حتى يتسنى لها <م> ينحدر أنواع، بدلا من الاضطرار مبرمج <م> صراحة تعلن أنواع. المترجم قد يكون قادرا على رؤية أن MyClass تطبق طريقة MyMethod()، والتعامل مع هذه الحالة وفقا لذلك، <م> بدون الحاجة إلى إعلان صريح واجهات (كما اشرتم). هذا المترجم يمكن الاستفادة نوع الاستدلال، مثل هيندلي-ميلنر .

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

نصائح أخرى

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

كما هو موثق في الوثائق الرسمية (كجزء من Tour of Go، مع رمز المثال):

يتم تنفيذ واجهات ضمنا

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

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

وماذا عن استخدام القوالب في C ++؟

class IMyInterface  // Inheritance from this is optional
{
public:
  virtual void MyMethod() = 0;
}

class MyClass  // Does not explicitly implement IMyInterface
{
public:
  void MyMethod()  // But contains a compatible method definition
  {
    std::cout << "Hello, world!" "\n";
  }
}

template<typename MyInterface>
void CallMyMethod(MyInterface& m)
{
  m.MyMethod();  // instantiation succeeds iff MyInterface has MyMethod
}

MyClass obj;
CallMyMethod(obj);     // Automatically generate code with MyClass as 
                       // MyInterface

وأنا لم جمعت فعلا هذا الرمز، ولكن أعتقد أنه من عملي وتافهة جدا ج ++ - سعودة من التعليمات البرمجية الأصلية المقترحة (ولكن عدم العمل)

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

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

وF # يدعم ثابتة الكتابة بطة، ولكن مع الصيد: لديك لاستخدام القيود الأعضاء. التفاصيل متوفرة في هذا <وأ href = "http://www.atrevido.net/blog/2008/08/31/Statically+Typed+Duck+Typing+In+F.aspx" يختلط = "noreferrer" عنوان = " كتبته بشكل ثابت الكتابة بطة في F # "> دخول بلوق .

مثال من بلوق استشهد:

let inline speak (a: ^a) =
    let x = (^a : (member speak: unit -> string) (a))
    printfn "It said: %s" x
    let y = (^a : (member talk: unit -> string) (a))
    printfn "Then it said %s" y

type duck() =
    member x.speak() = "quack"
    member x.talk() = "quackity quack"
type dog() =
    member x.speak() = "woof"
    member x.talk() = "arrrr"

let x = new duck()
let y = new dog()
speak x
speak y

ومعظم لغات في دعم الأسرة ML <قوية> أنواع الهيكلية مع الاستدلال ومخططات نوع مقيدة ، أو الذي هو العبقري غريب الأطوار المصطلحات اللغات مصمم الذي يبدو على الأرجح ما تعنيه عبارة "دوك- ثابت الكتابة "في السؤال الأصلي.

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

open Printf

class type iMyInterface = object
  method myMethod: unit
end

class myClass = object
  method myMethod = printf "Hello, world!"
end

let callMyMethod: #iMyInterface -> unit = fun m -> m#myMethod

let myClass = new myClass

callMyMethod myClass

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

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

تايب سكريبت!

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

enter image description here

وبو بالتأكيد هي لغة كتبته بطة ثابتة: http://boo.codehaus.org/Duck + كتابة

ومقتطفات:

<اقتباس فقرة>   

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

     

وأحيانا يكون من المناسب أن تتخلى   شبكة الأمان التي توفرها ثابت   الكتابة. ربما كنت ترغب فقط في استكشاف   وAPI دون القلق كثيرا عن   تواقيع طريقة أو ربما كنت   خلق التعليمات البرمجية التي يتحدث الخارجية   مكونات مثل الكائنات COM. إما   الطريقة التي ينبغي أن يكون الخيار لك لا   الألغام.

     

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

وإصدارات جديدة من C ++ التحرك في اتجاه ثابت الكتابة بطة. يمكنك في يوم من الأيام (؟ اليوم) كتابة شيء من هذا القبيل:

auto plus(auto x, auto y){
    return x+y;
}

وسيكون تفشل في تجميع اذا لم يكن هناك استدعاء دالة مطابقة لx+y.

وأما بالنسبة لنقدك:

<اقتباس فقرة>   يتم إنشاء

وA "CallMyMethod" جديدة لكل نوع من أنواع مختلفة يمكنك تمرير لها، حتى انها لم تكتب حقا الاستدلال.

ولكن من نوع الاستدلال (يمكنك أن تقول foo(bar) حيث foo هي وظيفة قالب)، ولها نفس التأثير، إلا أنها أكثر كفاءة من الوقت ويأخذ مساحة أكبر في التعليمات البرمجية المترجمة.

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

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

في كلتا الحالتين، التي تسمح لك ضمنيا ودون قصد لكسر التسلسل الهرمي فئة، وهو شر ميزة جديدة لأنه يتعارض مع عادات ما تستخدم المبرمجين C # / جافا ل. مع قوالب C ++، كنت تعرف أنك في حقل ألغام (وهم أيضا إضافة ميزة ( "مفاهيم") للسماح قيود على المعلمات القالب).

وأنواع الهيكلية في سكالا يفعل شيئا من هذا القبيل.

وانظر <لأ href = "http://web.archive.org/web/20090818051106/http://neilbartlett.name/blog/2007/09/13/statically-checked-duck-typing-in-scala / "يختلط =" نوفولو noreferrer "> تم الفحص بشكل ثابت" بطة الكتابة "في سكالا

وكان تصميم ما قبل النشر لمدة 9 البصرية الأساسية لدعم ساكنة الكتابة البط باستخدام واجهات دينامية لكن قطعوا ميزة <لأ href = "http://www.infoq.com/news/2007/04/Dynamic-Interface "يختلط =" نوفولو noreferrer "> * من أجل شحن في الوقت المحدد.

D ( http://dlang.org ) هو لغة مترجمة بشكل ثابت ويوفر بطة الكتابة عبر التفاف () وبسط () ( http://dlang.org/phobos-prerelease/std_typecons.html # .unwrap ).

كريستال هي لغة مكتوبة بشكل ثابت. مثال:

def add(x, y)
  x + y
end

add(true, false)

الدعوة الى add يسبب هذا الخطأ في التجميع:

Error in foo.cr:6: instantiating 'add(Bool, Bool)'

add(true, false)
^~~

in foo.cr:2: undefined method '+' for Bool

  x + y
    ^

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

MyClass obj = new MyClass();
CallMyMethod(obj);

ويمكنك أن تكتب:

MyClass obj = new MyClass();
CallMyMethod(obj as IMyInterface);

وكما هو الحال في المثال الخاص بك، في هذه الحالة MyClass لم يكن لديك لتنفيذ صراحة IMyInterface، ولكن إذا فعلت المدلى بها يمكن أن يحدث ضمنيا ويمكن حذف المشغل as.

ولقد كتبت أكثر قليلا عن الأسلوب الذي أسميه صريحة الهيكلية الفرعية الكتابة في <لأ href = "http://dobbscodetalk.com/index.php؟option=com_myblog&show=Explicit-Structural-Typing-Duck-Typing -.html & Itemid = 29 "يختلط =" نوفولو noreferrer "> هذه المقالة .

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