إرسال متعدد

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

فهم عملية الإرسال

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

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

في لغات البرمجة التقليدية، أي لغات البرمجة كائنية التوجه أحادية الإرسال ، عند استدعاء دالة ( إرسال رسالة في Smalltalk ، أو استدعاء دالة عضوية في C++ )، يُعامل أحد وسائطها معاملة خاصة ويُستخدم لتحديد أي من فئات الدوال (التي قد تكون كثيرة) التي تحمل نفس الاسم سيتم تطبيقها. في العديد من اللغات، يُشار إلى الوسيط الخاص نحويًا؛ على سبيل المثال، تضع بعض لغات البرمجة الوسيط الخاص قبل النقطة عند استدعاء دالة: ` doar`، بحيث يُصدر `doar` صوتًا عاليًا، بينما يُصدر `doar` صوتًا منخفضًا.special.method(other, arguments, here)lion.sound()sparrow.sound()

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

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

أنواع البيانات

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

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

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

مشاكل

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

التعبيرية والنمطية

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

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

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

الغموض

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

تشمل الحلول الممكنة ما يلي:

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

كفاءة

يُعدّ التنفيذ الفعال لتقنية الإرسال الأحادي، بما في ذلك في لغات البرمجة التي تُترجم بشكل منفصل إلى كود كائني وتُربط باستخدام رابط منخفض المستوى (غير مُدرك للغة)، بما في ذلك التنفيذ الديناميكي عند تحميل/بدء البرنامج أو حتى بتوجيه من كود التطبيق، أمرًا معروفًا جيدًا. تُعتبر طريقة " جدول الدوال الافتراضية " المُطوّرة في لغة C++ وغيرها من لغات البرمجة الكائنية المبكرة (حيث تحتوي كل فئة على مصفوفة من مؤشرات الدوال التي تُقابل الدوال الافتراضية لتلك الفئة) سريعة تقريبًا مثل استدعاء دالة ثابتة، وتتطلب تكلفة إضافية ثابتة O(1) وعملية بحث واحدة فقط في الذاكرة حتى في الحالة غير المُحسّنة. مع ذلك، تستخدم طريقة جدول الدوال الافتراضية اسم الدالة وليس نوع الوسيط كمفتاح بحث، ولا يُمكن توسيع نطاقها لتشمل حالة الإرسال المتعدد. (كما أنها تعتمد على نموذج البرمجة الكائنية الذي يعتبر الدوال ميزات للفئات، وليست كيانات مستقلة عن أي نوع بيانات مُحدد).

لا يزال التنفيذ الفعال لتقنية الإرسال المتعدد يمثل مشكلة بحثية مستمرة.

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

لتقدير مدى شيوع استخدام الإرسال المتعدد في الممارسة العملية، درس موشيفيتشي وآخرون [ 2 ] برامج تستخدم الإرسال الديناميكي. حللوا تسعة تطبيقات، معظمها مترجمات، مكتوبة بست لغات مختلفة: Common Lisp Object System ، و Dylan ، و Cecil ، وMultiJava، وDiesel، وNice. تُظهر نتائجهم أن 13-32% من الدوال العامة تستخدم النوع الديناميكي لوسيط واحد، بينما 2.7-6.5% منها تستخدم النوع الديناميكي لوسائط متعددة. أما النسبة المتبقية، 65-93% من الدوال العامة، فلها دالة ملموسة واحدة (دالة مُعاد تعريفها)، وبالتالي لا تُعتبر مستخدمة للأنواع الديناميكية لوسائطها. علاوة على ذلك، تشير الدراسة إلى أن 2-20% من الدوال العامة لها دالتان ملموستان، و3-6% لها ثلاث دوال ملموسة. تتناقص هذه النسب بسرعة للدوال التي تحتوي على عدد أكبر من الدوال المُعاد تعريفها.

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

تُلخّص البيانات من هذه الأوراق في الجدول التالي، حيث DRتمثل نسبة الإرسال متوسط ​​عدد الطرق لكل دالة عامة؛ CRوتمثل نسبة الاختيار متوسط ​​مربع عدد الطرق (لقياس تكرار الدوال ذات العدد الكبير من الطرق بشكل أفضل)؛ [ 2 ] [ 3 ] وتمثل درجة التخصص DoSمتوسط ​​عدد الوسائط المتخصصة بالنوع لكل طريقة (أي عدد الوسائط التي يتم إرسالها):

لغةمتوسط ​​الطرق (DR)نسبة الاختيار (CR)درجة التخصص (DoS)
سيسيل [ 2 ]2.3363.301.06
Common Lisp ( CMU ) [ 2 ]2.036.341.17
Common Lisp ( McCLIM ) [ 2 ]2.3215.431.17
Common Lisp ( Steel Bank ) [ 2 ]2.3726.571.11
الديزل [ 2 ]2.0731.650.71
ديلان (جويديان) [ 2 ]1.7418.272.14
ديلان (أوبن ديلان) [ 2 ]2.5143.841.23
جوليا [ 3 ]5.8651.441.54
جوليا (للمشغلين فقط) [ 3 ]28.1378.062.01
MultiJava [ 2 ]1.508.921.02
جميل [ 2 ]1.363.460.33

نظرية

طُوِّرت نظرية لغات الإرسال المتعدد لأول مرة على يد كاستاغنا وآخرون، وذلك بتعريف نموذج للدوال المُحمَّلة بشكل زائد مع الربط المتأخر . [ 4 ] [ 5 ] وقد أسفرت هذه النظرية عن أول صياغة رسمية لمشكلة تباين النوع (التغاير والتغاير العكسي) للغات البرمجة كائنية التوجه [ 6 ] وحل لمشكلة الطرق الثنائية. [ 7 ]

أمثلة

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

اللغات التي تتضمن خاصية الإرسال المتعدد المدمجة

سي شارب

أضافت لغة C# دعمًا للأساليب المتعددة الديناميكية في الإصدار 4 [ 8 ] (أبريل 2010) باستخدام الكلمة المفتاحية 'dynamic'. يوضح المثال التالي كيفية استخدام الأساليب المتعددة. وكما هو الحال في العديد من اللغات ذات الكتابة الثابتة، تدعم C# أيضًا تحميل الأساليب الثابتة. [ 9 ] تتوقع مايكروسوفت أن يختار المطورون الكتابة الثابتة بدلًا من الكتابة الديناميكية في معظم الحالات. [ 10 ] تدعم الكلمة المفتاحية 'dynamic' التوافق مع كائنات COM ولغات .NET ذات الكتابة الديناميكية.

يستخدم المثال أدناه ميزات تم تقديمها في C# 9 و C# 10.

باستخدام مكتبة ColliderLibrary الثابتة ؛Console.WriteLine (" Collide ( new Asteroid ( 101 ) , new Spaceship ( 300 ))"); Console.WriteLine ( " Collide ( new Asteroid ( 10 ) , new Spaceship ( 10 ))"); Console.WriteLine ( " Collide ( new Spaceship ( 101 ), new Spaceship ( 10 ) ) " );دالة `Collide ( SpaceObject x , SpaceObject y ) ` تُرجع كائنًا من نوع ` SpaceObject` بحجم ` x` أكبر من 100 ، وكائنًا من نوع `SpaceObject` بحجم `y` أكبر من 100 ، حيث تُرجع الدالة ` CollideWith ( x as dynamic , y as dynamic ) ` كائنًا من نوع `SpaceObject` بحجم `x` أكبر من 100 ، وتُرجع الدالة `CollideWith(x as dynamic, y as dynamic)` كائنًا من نوع `SpaceObject` بحجم `x` أكبر من 100، حيث تُ ...class ColliderLibrary { public static string CollideWith ( Asteroid x , Asteroid y ) => "a/a" ; public static string CollideWith ( Asteroid x , Spaceship y ) => "a/s" ; public static string CollideWith ( Spaceship x , Asteroid y ) => "s/a" ; public static string CollideWith ( Spaceship x , Spaceship y ) => "s/s" ; }سجل مجرد SpaceObject ( int Size ); سجل Asteroid ( int Size ) : SpaceObject ( Size ); سجل Spaceship ( int Size ) : SpaceObject ( Size );

الناتج:

انفجار كبير! أ/س س/س

رائع

Groovy هي لغة برمجة عامة الأغراض متوافقة مع Java وقابلة للاستخدام المتبادل مع JVM ، والتي، على عكس Java، تستخدم الربط المتأخر / الإرسال المتعدد. [ 11 ]

/*  تطبيق Groovy لمثال C# أعلاه.  يعمل الربط المتأخر بنفس الطريقة عند استخدام طرق غير ثابتة أو عند تجميع الفئة/الطرق بشكل ثابت  (باستخدام التعليق التوضيحي @CompileStatic). */ class Program { static void main ( String [] args ) { println Collider . collide ( new Asteroid ( 101 ), new Spaceship ( 300 )) println Collider . collide ( new Asteroid ( 10 ), new Spaceship ( 10 )) println Collider . collide ( new Spaceship ( 101 ), new Spaceship ( 10 )) } }class Collider { static String collide ( SpaceObject x , SpaceObject y ) { ( x . size > 100 && y . size > 100 ) ? "big-boom" : collideWith ( x , y ) // إرسال ديناميكي إلى دالة collideWith }private static String collideWith ( Asteroid x , Asteroid y ) { "a/a" } private static String collideWith ( Asteroid x , Spaceship y ) { "a/s" } private static String collideWith ( Spaceship x , Asteroid y ) { "s/a" } private static String collideWith ( Spaceship x , Spaceship y ) { "s/s" } }class SpaceObject { int size SpaceObject ( int size ) { this . size = size } }@InheritConstructors class Asteroid extends SpaceObject {} @InheritConstructors class Spaceship extends SpaceObject {}

لغة الشفرة الشائعة

في لغة ذات إرسال متعدد، مثل لغة Common Lisp ، قد يبدو الأمر أشبه بهذا (مثال Common Lisp معروض):

( defclass asteroid () (( size :reader size :initarg :size ))) ( defclass spaceship () (( size :reader size :initarg :size ))) ( defun space-object ( class size ) ( make-instance class :size size ))الدالة collide-with هي دالة عامة ذات إرسال متعدد ( defmethod collide-with (( x asteroid ) ( y asteroid )) "a/a" ) ( defmethod collide-with (( x asteroid ) ( y spaceship )) "a/s" ) ( defmethod collide-with (( x spaceship ) ( y asteroid )) "s/a" ) ( defmethod collide-with (( x spaceship ) ( y spaceship )) "s/s" )( defun collide ( x y ) ( if ( and ( > ( size x ) 100 ) ( > ( size y ) 100 )) "big-boom" ( collide-with x y )))( اطبع ( اصطدام ( الكائن الفضائي 'الكويكب 101 ) ( الكائن الفضائي 'السفينة الفضائية 300 ))) ( اطبع ( اصطدام ( الكائن الفضائي 'الكويكب 10 ) ( الكائن الفضائي 'السفينة الفضائية 10 ))) ( اطبع ( اصطدام ( الكائن الفضائي 'السفينة الفضائية 101 ) ( الكائن الفضائي 'السفينة الفضائية 10 )))

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

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

جوليا

تتضمن لغة جوليا خاصية الإرسال المتعدد المدمجة، وهي عنصر أساسي في تصميم اللغة. [ 3 ] قد تبدو نسخة جوليا من المثال أعلاه كما يلي:

نوع مجرد كائن فضائي نهايةstruct Asteroid <: SpaceObject size :: Int end struct Spaceship <: SpaceObject size :: Int endcollide_with ( :: Asteroid , :: Spaceship ) = "a/s" collide_with ( :: Spaceship , :: Asteroid ) = "s/a" collide_with ( :: Spaceship , :: Spaceship ) = "s/s" collide_with ( :: Asteroid , :: Asteroid ) = "a/a"collide ( x :: SpaceObject , y :: SpaceObject ) = ( x.size > 100 && y.size > 100 ) ? " انفجار كبير ! " : collide_with ( x , y )

الناتج:

julia> collide ( Asteroid ( 101 ), Spaceship ( 300 )) "انفجار كبير!"julia> collide ( Asteroid ( 10 ), Spaceship ( 10 )) "a/s"julia> collide ( Spaceship ( 101 ), Spaceship ( 10 )) "s/s"

راكو

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

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

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

مجموعة فرعية من الكتلة الحقيقية حيث 0 إلى ما لا نهاية ؛ دور الكائن النجمي { له كتلة $.mass مطلوب ؛ اسم الدالة ( ) يُرجع Str {...}; } class Asteroid does Stellar-Object { method name () { 'an asteroid' } } class Spaceship does Stellar-Object { has Str $.name = 'some unnamed spaceship' ; } my Str @destroyed = < تم محوه، تم تدميره، تم تشويهه >; my Str @damaged = « تالف ، 'اصطدم بـ' ، 'تضرر بسبب' »; # نضيف مرشحين متعددين إلى عوامل المقارنة العددية لأننا نقارنها عدديًا، # ولكن ليس من المنطقي إجبار الكائنات على أن تكون من النوع العددي. # (لو تم إجبارها، لما احتجنا بالضرورة إلى إضافة هذه العوامل.) # كان بإمكاننا أيضًا تعريف عوامل جديدة تمامًا بنفس الطريقة. `multi sub infix: « <=> » ( Stellar-Object:D $a , Stellar-Object:D $b ) { $a . mass <=> $b . mass }` ` multi sub infix: « < » ( Stellar-Object:D $a , Stellar-Object:D $b ) { $a . mass < $b . mass }` ` multi sub infix: « > » ( Stellar-Object:D $a , Stellar-Object:D $b ) { $a . mass > $b . الكتلة } متعدد فرعي infix: « == » ( Stellar-Object:D $a , Stellar-Object:D $b ) { $a . mass == $b . mass } # تعريف مُوزِّع متعدد جديد، وإضافة بعض قيود النوع إلى المعاملات. # لو لم نُعرِّفه، لحصلنا على مُوزِّع عام بدون قيود. proto sub collide ( Stellar-Object:D $, Stellar-Object:D $ ) {*} # لا داعي لتكرار الأنواع هنا لأنها مطابقة للنموذج الأولي. # ينطبق قيد "where" تقنيًا على $b فقط وليس على التوقيع بأكمله. # لاحظ أن قيد "where" يستخدم عامل التشغيل `<` الذي أضفناه سابقًا. multi sub collide ( $a , $b where $a < $b ) { say "$a.name() was @destroyed.pick() by $b.name()" ; } multi sub collide ( $a , $b where $a > $b ) { # إعادة التوجيه إلى المرشح السابق مع تبديل الوسائط samewith $b , $a ; } # يجب أن يكون هذا بعد أول اثنين لأن الآخرين # لديهم قيود "where"، والتي يتم التحقق منها # بالترتيب الذي كُتبت به العمليات الفرعية. (هذا سيتطابق دائمًا.) multi sub collide ( $a , $b ) { # عشوائية الترتيب my ( $n1 , $n2 ) = ( $a . name , $b . name ). pick (*); say "$n1 @damaged.pick() $n2" ; } # يمكن أن يكون المرشحان التاليان في أي مكان بعد النموذج الأولي، # لأنهما يمتلكان أنواعًا أكثر تخصصًا من الأنواع الثلاثة السابقة.# إذا كانت كتلة السفينتين غير متساوية، فسيتم استدعاء أحد المرشحين الأولين بدلاً من ذلك. multi sub collide ( Spaceship $a , Spaceship $b where $a == $b ){ my ( $n1 , $n2 ) = ( $a . name , $b . name ). pick (*); say "اصطدمت السفينة $n1 بالسفينة $n2، وكانت كلتا السفينتين " , ( @destroyed . pick , 'left damage' ). pick ; } # يمكنك تفكيك السمات إلى متغيرات داخل التوقيع. # يمكنك حتى وضع قيد عليها `(:mass($a) where 10)`. multi sub collide ( Asteroid $ (: mass ( $a )), Asteroid $ (: mass ( $b )) ){ say "اصطدم كويكبان واندمجا في كويكب واحد أكبر كتلته { $a + $b }" ; } سفينتي الفضائية $Enterprise .= new (: mass ( 1 ),: name ( 'The Enterprise' )); collide Asteroid . new (: mass ( .1 )), $Enterprise ; collide $Enterprise , Spaceship . new (: mass ( .1 )); collide $Enterprise , Asteroid . new (: mass ( 1 )); collide $Enterprise , Spaceship . new (: mass ( 1 )); collide Asteroid . new (: mass ( 10 )), Asteroid . new (: mass ( 5 )); 

توسيع اللغات باستخدام مكتبات الإرسال المتعدد

جافا سكريبت

في اللغات التي لا تدعم الإرسال المتعدد على مستوى تعريف اللغة أو على مستوى بناء الجملة، يُمكن غالبًا إضافة الإرسال المتعدد باستخدام مكتبة برمجية . لا تدعم لغتا جافا سكريبت وتايب سكريبت الدوال المتعددة على مستوى بناء الجملة، ولكن يُمكن إضافة الإرسال المتعدد عبر مكتبة برمجية. على سبيل المثال، توفر حزمة multimethod [ 12 ] تطبيقًا للإرسال المتعدد، وهو عبارة عن دوال عامة.

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

import { multi , method } from '@arrows/multimethod'class Asteroid {} class Spaceship {}const collideWith = multi ( method ([ Asteroid , Asteroid ], ( x , y ) => { // التعامل مع اصطدام الكويكب بالكويكب }), method ([ Asteroid , Spaceship ], ( x , y ) => { // التعامل مع اصطدام الكويكب بالمركبة الفضائية }), method ([ Spaceship , Asteroid ], ( x , y ) => { // التعامل مع اصطدام المركبة الفضائية بالكويكب }), method ([ Spaceship , Spaceship ], ( x , y ) => { // التعامل مع اصطدام المركبة الفضائية بالمركبة الفضائية }), )

نسخة ذات كتابة ثابتة مكتوبة بلغة TypeScript:

import { multi , method , Multi } from '@arrows/multimethod'class Asteroid {} class Spaceship {}نوع CollideWith = Multi & { ( x : Asteroid , y : Asteroid ) : void ( x : Asteroid , y : Spaceship ) : void ( x : Spaceship , y : Asteroid ) : void ( x : Spaceship , y : Spaceship ) : void }const collideWith : CollideWith = multi ( method ([ Asteroid , Asteroid ], ( x , y ) => { // التعامل مع اصطدام الكويكب بالكويكب }), method ([ Asteroid , Spaceship ], ( x , y ) => { // التعامل مع اصطدام الكويكب بالمركبة الفضائية }), method ([ Spaceship , Asteroid ], ( x , y ) => { // التعامل مع اصطدام المركبة الفضائية بالكويكب }), method ([ Spaceship , Spaceship ], ( x , y ) => { // التعامل مع اصطدام المركبة الفضائية بالمركبة الفضائية }), )

بايثون

يمكن إضافة خاصية الإرسال المتعدد إلى لغة بايثون باستخدام مكتبة إضافية. على سبيل المثال، باستخدام الوحدة multimethod.py [ 13 ] ، وكذلك باستخدام الوحدة multimethods.py [ 14 ] التي توفر دوال متعددة على غرار CLOS للغة بايثون دون تغيير بنية اللغة أو كلماتها المفتاحية.

من typing استورد Anyاستورد game_behaviors من game_objects استورد Asteroid و Spaceship من multimethods استورد Dispatchتصادم : Dispatch = Dispatch () تصادم . إضافة_قاعدة (( كويكب ، مركبة فضائية سلوكيات_اللعبة . as_func ) تصادم . إضافة_قاعدة (( مركبة فضائية ، مركبة فضائية سلوكيات_اللعبة . ss_func ) تصادم . إضافة_قاعدة (( مركبة فضائية ، كويكب سلوكيات_اللعبة . sa_func )def aa_func ( a : Any , b : Any ) -> None : """السلوك عند اصطدام كويكب بكويكب آخر.""" # ...تعريف سلوك جديد...collide.add_rule ( ( Asteroid , Asteroid ) , aa_func )
# ...لاحقًا... يصطدمان ( الشيء 1 ، الشيء 2 )

من الناحية الوظيفية، هذا مشابه جدًا لمثال CLOS، لكن بناء الجملة هو بايثون التقليدي.

باستخدام الزخارف (التي تم تقديمها منذ بايثون 2.4)، أنتج غيدو فان روسوم نموذجًا لتنفيذ الأساليب المتعددة [ 15 ] بصيغة مبسطة:

@multimethod ( Asteroid , Asteroid ) def collide ( a : Asteroid , b : Asteroid ) -> None : """السلوك عند اصطدام كويكب بكويكب آخر.""" # ...تعريف سلوك جديد...@multimethod ( Asteroid , Spaceship ) def collide ( a : Asteroid , b : Spaceship ) -> None : """السلوك عند اصطدام كويكب بمركبة فضائية.""" # ...تعريف سلوك جديد...# ... تحديد قواعد أخرى متعددة الأساليب ...

ثم ينتقل إلى تعريف مُزخرف الأساليب المتعددة.

توفر حزمة PEAK-Rules إمكانية إرسال البيانات المتعددة بصيغة مشابهة للمثال أعلاه. [ 16 ] وقد تم استبدالها لاحقًا بـ PyProtocols. [ 17 ]

تدعم مكتبة Reg أيضًا الإرسال المتعدد والإرسال الشرطي. [ 18 ]

مع إدخال تلميحات الأنواع ، أصبح الإرسال المتعدد ممكنًا باستخدام صيغة أبسط. على سبيل المثال، باستخدام plum-dispatch ،

من شركة بلوم للاستيراد والشحن@dispatch def collide ( a : Asteroid , b : Asteroid ) -> None : """السلوك عند اصطدام كويكب بكويكب آخر.""" # ...تعريف سلوك جديد...@dispatch def collide ( a : Asteroid , b : Spaceship ) -> None : """السلوك عند اصطدام كويكب بمركبة فضائية.""" # ...تعريف سلوك جديد...# ...تحديد المزيد من القواعد...

محاكاة الإرسال المتعدد

ج

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

typedef void ( * CollisionCase )( void );void collisionAsteroidAsteroid ( void ) { // معالجة تصادم الكويكبات... }void collisionAsteroidSpaceship ( void ) { // معالجة تصادم الكويكب مع المركبة الفضائية... }void collisionSpaceshipAsteroid ( void ) { // معالجة تصادم المركبة الفضائية مع الكويكب... }void collisionSpaceshipSpaceship ( void ) { // معالجة تصادم المركبات الفضائية... }typedef enum { COLLIDEABLE_ASTEROID = 0 , COLLIDEABLE_SPACESHIP , COLLIDEABLE_COUNT // ليس نوعًا من Collideable بحد ذاته، بل يُستخدم لإيجاد عدد الكائنات الفضائية المُعرّفة } Collideable ;CollisionCase collisionCases [ COLLIDEABLE_COUNT ][ COLLIDEABLE_COUNT ] = { { & collisionAsteroidAsteroid , & collisionAsteroidSpaceship }, { & collisionSpaceshipAsteroid , & collisionSpaceshipSpaceship } };دالة تصادم ( قابلة للتصادم أ ، قابلة للتصادم ب ) { ( * حالات التصادم [ أ ][ ب ])(); }int main ( void ) { collide ( COLLIDEABLE_SPACESHIP , COLLIDEABLE_ASTEROID ); }

باستخدام مكتبة نظام كائنات C [ 19 ] ، تدعم لغة C الإرسال الديناميكي المشابه لـ CLOS. وهي قابلة للتوسيع بالكامل ولا تتطلب أي معالجة يدوية للأساليب. يتم إرسال الرسائل الديناميكية (الأساليب) بواسطة مُرسِل COS، وهو أسرع من Objective-C . إليك مثال في COS:

#include <stdio.h> #include <cos/Object.h> #include <cos/gen/object.h>// الفئاتdefclass ( Asteroid ) // أعضاء البيانات endclassdefclass ( Spaceship ) // أعضاء البيانات endclass// الأنواع العامةdefgeneric ( bool , collide_with , _1 , _2 );// طرق متعددةdefmethod ( bool , collide_with , Asteroid , Asteroid ) // التعامل مع اصطدام الكويكب بالكويكب endmethoddefmethod ( bool , collide_with , Asteroid , Spaceship ) // التعامل مع اصطدام الكويكب بالمركبة الفضائية endmethoddefmethod ( bool , collide_with , Spaceship , Asteroid ) // التعامل مع اصطدام المركبة الفضائية بالكويكب endmethoddefmethod ( bool , collide_with , Spaceship , Spaceship ) // التعامل مع اصطدام مركبة فضائية بمركبة فضائية endmethod// مثال على الاستخدامint main ( void ) { OBJ a = gnew ( Asteroid ); OBJ s = gnew ( Spaceship );printf ( "<a,a> = %d \n " , collide_with ( a , a )); printf ( "<a,s> = %d \n " , collide_with ( a , s )); printf ( "<s,a> = %d \n " , collide_with ( s , a )); printf ( "<s,s> = %d \n " , collide_with ( s , s ));grelease ( a ); grelease ( s ); }

لغة سي++

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

// مثال باستخدام مقارنة أنواع البيانات في وقت التشغيل عبر dynamic_castclassCollideable{public:virtualvoidcollideWith(Collideable&other)=0;};classAsteroid:publicCollideable{public:voidcollideWith(Collideable&other){// dynamic_cast to a pointer type returns nullptr if the cast fails// (dynamic_cast to a reference type would throw an exception on failure)if(Asteroid*asteroid=dynamic_cast<Asteroid*>(&other)){// handle Asteroid-Asteroid collision}elseif(Spaceship*spaceship=dynamic_cast<Spaceship*>(&other)){// handle Asteroid-Spaceship collision}else{// default collision handling here}}};classSpaceship:publicCollideable{public:voidcollideWith(Collideable&other){if(Asteroid*asteroid=dynamic_cast<Asteroid*>(&other)){// handle Spaceship-Asteroid collision}elseif(Spaceship*spaceship=dynamic_cast<Spaceship*>(&other)){// handle Spaceship-Spaceship collision}else{// default collision handling here}}};

or pointer-to-method lookup table:

importstd;usingstd::unordered_map;classCollideable{protected:explicitCollideable(uint32_tcid):tid{cid}{}virtual ~ Collideable () = default ;const uint32_t tid ; // معرف النوعباستخدام CollisionHandler = void ( Collideable ::* )( Collideable & other ); باستخدام CollisionHandlers = unordered_map < uint64_t , CollisionHandler > ;static void addHandler ( uint32_t id1 , uint32_t id2 , CollisionHandler handler ) { collisionCases . insert ( CollisionHandlers :: value_type ( key ( id1 , id2 ), handler )); }static uint64_t key ( uint32_t id1 , uint32_t id2 ) { return uint64_t ( id1 ) << 32 | id2 ; }static inline CollisionHandlers collisionCases {}; public : void collideWith ( Collideable & other ) { if ( auto handler = collisionCases . find ( key ( tid , other . tid )); handler != collisionCases . end ()) { ( this ->* handler -> second )( other ); // استدعاء مؤشر إلى الدالة } else { // معالجة التصادم الافتراضية } } };class Asteroid : public Collideable { private : void asteroidCollision ( Collideable & other ) { // معالجة تصادم الكويكبات }void spaceshipCollision ( Collideable & other ) { // معالجة تصادم الكويكب مع المركبة الفضائية } public : Asteroid () : Collideable ( cid ) {}~ كويكب () = افتراضي ;static void initCases (); static inline const uint32_t cid = typeid ( Asteroid ) .hash_code (); };class Spaceship : public Collideable { private : void asteroidCollision ( Collideable & other ) { // معالجة تصادم المركبة الفضائية مع الكويكب }void spaceshipCollision ( Collideable & other ) { // معالجة تصادم المركبات الفضائية } public : Spaceship () : Collideable ( cid ) {}~ Spaceship () = default ;static void initCases (); static inline const uint32_t cid = typeid ( Spaceship ) .hash_code (); // معرف الفئة };void Asteroid::initCases () { addHandler ( cid , cid , CollisionHandler ( & Asteroid :: asteroidCollision )); addHandler ( cid , Spaceship :: cid , CollisionHandler ( & Asteroid :: spaceshipCollision )); }void Spaceship::initCases () { addHandler ( cid , Asteroid :: cid , CollisionHandler ( & Spaceship :: asteroidCollision )); addHandler ( cid , cid , CollisionHandler ( & Spaceship :: spaceshipCollision )); }int main ( int argc , char * argv []) { Asteroid :: initCases (); Spaceship :: initCases ();الكويكب أ1 ؛ الكويكب أ2 ؛ المركبة الفضائية س1 ؛ المركبة الفضائية س2 ؛a1.collideWith ( a2 ) ; a1.collideWith ( s1 ) ;s1.collideWith ( s2 ) ; s1.collideWith ( a1 ) ; }

توفر مكتبة YOMM2 [ 21 ] تطبيقًا سريعًا ومتعامدًا للأساليب المتعددة المفتوحة.

استُلهمت صيغة تعريف الدوال المفتوحة من اقتراح لتنفيذ أصلي بلغة C++. تتطلب المكتبة من المستخدم تسجيل جميع الفئات المستخدمة كوسائط افتراضية (وفئاتها الفرعية)، ولكنها لا تتطلب أي تعديلات على الشيفرة البرمجية الموجودة. تُنفَّذ الدوال كدوال C++ عادية مضمنة؛ ويمكن إعادة تعريفها وتمريرها بواسطة مؤشر. لا يوجد حد لعدد الوسائط الافتراضية، ويمكن مزجها بشكل عشوائي مع الوسائط غير الافتراضية.

تستخدم المكتبة مزيجًا من التقنيات (جداول الإرسال المضغوطة، وجدول التجزئة للأعداد الصحيحة الخالي من التصادمات ) لتنفيذ استدعاءات الدوال في وقت ثابت، مع تقليل استهلاك الذاكرة. يستغرق إرسال استدعاء دالة مفتوحة ذات وسيط افتراضي واحد وقتًا أطول بنسبة 15-30% فقط من استدعاء دالة عضو افتراضية عادية، عند استخدام مُصرّف حديث مُحسِّن .

يمكن تطبيق مثال الكويكبات على النحو التالي:

#include <yorel/yomm2/keywords.hpp>استيراد std ؛باستخدام std :: unique_ptr ؛class Collideable { public : virtual ~ Collideable () = default ; };class Asteroid : public Collideable { // ... };class Spaceship : public Collideable { // ... };register_classes ( Collideable , Spaceship , Asteroid );declare_method ( void , collideWith , ( virtual_ < Collideable &> , virtual_ < Collideable &> ));define_method ( void , collideWith , ( Collideable & left , Collideable & right )) { // معالجة التصادم الافتراضية }define_method ( void , collideWith , ( Asteroid & left , Asteroid & right )) { // معالجة تصادم الكويكبات }define_method ( void , collideWith , ( Asteroid & left , Spaceship & right )) { // معالجة تصادم الكويكب مع المركبة الفضائية }define_method ( void , collideWith , ( Spaceship & left , Asteroid & right )) { // معالجة تصادم المركبة الفضائية مع الكويكب }define_method ( void , collideWith , ( Spaceship & left , Spaceship & right )) { // معالجة تصادم المركبة الفضائية مع المركبة الفضائية }int main ( int argc , char * argv []) { yorel :: yomm2 :: update_methods ();unique_ptr <Collideable> a1 ( std :: make_unique <Asteroid> ( ) ); unique_ptr<Collideable> a2 ( std :: make_unique <Asteroid> ( ) ) ; unique_ptr <Collideable> s1 ( std :: make_unique <Spaceship> ( ) ) ; unique_ptr <Collideable> s2 ( std :: make_unique <Spaceship> ( ) ) ; // ملاحظة : تم حذف الأنواع جزئيًاcollideWith ( * a1 , * a2 ); // تصادم بين كويكبين collideWith ( * a1 , * s1 ); // تصادم بين كويكب ومركبة فضائية collideWith ( * s1 , * a1 ); // تصادم بين مركبة فضائية وكويكب collideWith ( * s1 , * s2 ); // تصادم بين مركبتين فضائيتينreturn 0 ; }

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

د

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

// مصفوفة الإعلان بالإضافة إلى ( مصفوفة افتراضية ! ، مصفوفة افتراضية ! );// إعادة تعريف دالة الجمع لكائنين من نوع DenseMatrix @method Matrix _plus ( DenseMatrix a , DenseMatrix b ) { const int nr = a . rows ; const int nc = a . cols ; assert ( a . nr == b . nr ); assert ( a . nc == b . nc ); auto result = new DenseMatrix ; result . nr = nr ; result . nc = nc ; result . elems . length = a . elems . length ; result . elems [] = a . elems [] + b . elems []; return result ; }// إعادة تعريف دالة جمع كائنين من نوع DiagonalMatrix @method Matrix _plus ( DiagonalMatrix a , DiagonalMatrix b ) { assert ( a . rows == b . rows ); double [] sum ; sum . length = a . elems . length ; sum [] = a . elems [] + b . elems []; return new DiagonalMatrix ( sum ); }

جافا

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

UML class Java single dispatch.svg

واجهة قابلة للتصادم { void collideWith ( Collideable other );// ستحتاج هذه الدوال إلى أسماء مختلفة في لغة لا تدعم تحميل الدوال الزائد. void collideWith ( Asteroid asteroid ); void collideWith ( Spaceship spaceship ); }class Asteroid implements Collideable { public void collideWith ( Collideable other ) { // استدعاء الدالة collideWith على الكائن الآخر. other . collideWith ( this ); }public void collideWith ( Asteroid asteroid ) { // معالجة تصادم الكويكبات. }public void collideWith ( Spaceship spaceship ) { // معالجة تصادم الكويكب مع المركبة الفضائية. } }class Spaceship implements Collideable { public void collideWith ( Collideable other ) { // استدعاء collideWith على الكائن الآخر. other . collideWith ( this ); }public void collideWith ( Asteroid asteroid ) { // معالجة تصادم المركبة الفضائية مع الكويكب. }public void collideWith ( Spaceship spaceship ) { // معالجة تصادم المركبات الفضائية. } }

instanceofيمكن أيضًا استخدام عمليات التحقق أثناء التشغيل على مستوى واحد أو كلا المستويين.

الدعم في لغات البرمجة

النموذج الأساسي

دعم الأساليب المتعددة العامة

عبر الامتدادات

انظر أيضاً

مراجع

  1. ^ رانكا ، سانجاي. بانيرجي، أرونافا؛ بيسواس، كاناد كيشور؛ دوا، سوميت؛ ميشرا، برابهات؛ مونا ، راجات (26/07/2010). الحوسبة المعاصرة: المؤتمر الدولي الثاني، IC3 2010، نويدا، الهند، 9-11 أغسطس 2010. وقائع . سبرينغر. رقم ISBN 9783642148248.
  2. 1 2 3 4 5 6 7 8 9 10 11 موشيفيتشي، رادو؛ بوتانين، أليكس؛ تيمبيرو، إيوان؛ نوبل، جيمس (2008). "الإرسال المتعدد في الممارسة العملية". وقائع المؤتمر الثالث والعشرين لجمعية ACM SIGPLAN حول أنظمة لغات البرمجة وتطبيقاتها الموجهة للكائنات . OOPSLA '08. ناشفيل، تينيسي، الولايات المتحدة الأمريكية: ACM. الصفحات 563-582 . doi : 10.1145/1449764.1449808 . ISBN  9781605582153. S2CID 7605233 . 
  3. 1 2 3 4 5 بيزانسون، جيف؛ إيدلمان، آلان؛ كاربينسكي، ستيفان؛ شاه، فيرال ب. (7 فبراير 2017). "جوليا: منهج جديد للحوسبة العددية". مجلة SIAM Review . 59 (1): 65-98 . arXiv : 1411.1607 . doi : 10.1137/141000671 . S2CID 13026838 . 
  4. كاستاغنا، جوزيبي؛ غيلي، جورجيو؛ ولونغو، جوزيبي (1995). "حساب التفاضل والتكامل للدوال المحملة بشكل زائد مع التنميط الفرعي" . المعلومات والحوسبة . 117 (1): 115-135 . doi : 10.1006/inco.1995.1033 .
  5. كاستاغنا، جوزيبي (1996). البرمجة الكائنية التوجه: أساس موحد . التقدم في علوم الحاسوب النظرية. بيركهاوزر. ص 384. ISBN  978-0-8176-3905-1.
  6. كاستاغنا، جوزيبي (1995). "التغاير والتغاير العكسي: صراع بلا سبب". معاملات ACM في لغات البرمجة والأنظمة . 17 (3): 431-447 . CiteSeerX 10.1.1.115.5992 . doi : 10.1145/203095.203096 . S2CID 15402223 .  
  7. بروس، كيم؛ كارديلي، لوكا؛ كاستاغنا، جوزيبي؛ ليفنز، غاري تي؛ بيرس، بنجامين (1995). "حول الطرق الثنائية" . نظرية وممارسة أنظمة الكائنات . 1 (3): 221-242 . doi : 10.1002/j.1096-9942.1995.tb00019.x . تاريخ الاسترجاع : 19 أبريل 2013 .
  8. "استخدام النوع الديناميكي (دليل برمجة C#)" . تم الاطلاع عليه بتاريخ 14-05-2020 .
  9. "المفاهيم الأساسية" . تم الاطلاع عليه بتاريخ 14-05-2020 .
  10. "Dynamic .NET - فهم الكلمة المفتاحية Dynamic في C# 4" . 10 أغسطس 2015. تم الاطلاع عليه بتاريخ 14 مايو 2020 .
  11. غروفي - طرق متعددة
  12. @arrows/multimethod إرسال متعدد في JavaScript/TypeScript مع حل إرسال قابل للتكوين بواسطة Maciej Cąderek.
  13. كودي، أريك، multimethod: إرسال الوسائط المتعددة. ، تم الاطلاع عليه بتاريخ 28 يناير 2021
  14. multimethods.py مؤرشف في 2005-03-09 على Wayback Machine ، الإرسال المتعدد في بايثون مع حل إرسال قابل للتكوين بواسطة ديفيد ميرتز وآخرون.
  15. "الأساليب المتعددة في بايثون في خمس دقائق" .
  16. "PEAK-Rules 0.5a1.dev" . فهرس حزم بايثون . تم الاطلاع عليه بتاريخ 21 مارس 2014 .
  17. "PyProtocols" . مجموعة أدوات تطبيقات بايثون للمؤسسات . تم الاطلاع عليه بتاريخ 26 أبريل 2019 .
  18. "Reg" . اقرأ الوثائق . تم الاطلاع عليه بتاريخ 26 أبريل 2019 .
  19. "نظام كائنات C: إطار عمل يرتقي بلغة C إلى مستوى لغات البرمجة عالية المستوى الأخرى وما بعدها: CObjectSystem/COS" . GitHub . 19-02-2019.
  20. "تقرير عن دعم اللغة للأساليب المتعددة والأساليب المفتوحة للغة C++" (ملف PDF) . 11-03-2007. يُعد الإرسال المتعدد - وهو اختيار دالة ليتم استدعاؤها بناءً على النوع الديناميكي لوسيطين أو أكثر - حلاً للعديد من المشكلات الكلاسيكية في البرمجة الكائنية التوجه.
  21. yomm2 ، طرق متعددة مفتوحة وسريع ومتعامد للغة C++ من تأليف جان لويس ليروي.
  22. ستروستروب، بيارن (1994). "القسم 13.8". تصميم وتطور لغة C++ . إنديانابوليس، إنديانا، الولايات المتحدة الأمريكية: أديسون ويسلي. Bibcode : 1994dec..book.....S . ISBN 978-0-201-54330-8.
  23. openmethods ، Open Multi-Methods for D by Jean-Louis Leroy.
  24. "الأساليب" . دليل جوليا . جوليالانج. مؤرشف من الأصل في 17 يوليو 2016. تم الاسترجاع في 11 مايو 2014 .
  25. "الأساليب المتعددة في لغة C# 4.0 مع 'الديناميكي'"تم الاطلاع عليه بتاريخ 20 أغسطس 2009 .
  26. "لغة سيسيل" . تم الاطلاع عليه بتاريخ 13-04-2008 .
  27. "الأساليب المتعددة في كلوجر" . تم الاطلاع عليه بتاريخ 2008-09-04 .
  28. ستيل، جاي ل. (1990). "28" . لغة ليسب الشائعة: اللغة . بيدفورد، ماساتشوستس، الولايات المتحدة الأمريكية: دار النشر الرقمية. ISBN 978-1-55558-041-4.
  29. "الخلفية والأهداف" . تم الاطلاع عليه بتاريخ 13-04-2008 .
  30. "مواصفات لغة فورتريس، الإصدار 1.0" (ملف PDF) . مؤرشف من الأصل (ملف PDF) بتاريخ 20 يناير 2013. تم الاطلاع عليه بتاريخ 23 أبريل 2010 .
  31. "الأساليب المتعددة في Groovy" . تم الاطلاع عليه بتاريخ 13-04-2008 .
  32. "الأساليب - LassoGuide 9.2" . تم الاطلاع عليه بتاريخ 11-11-2014 .
  33. "نمط الزائر مقابل الأساليب المتعددة" . تم الاطلاع عليه بتاريخ 13-04-2008 .
  34. "دليل لغة نيم: طرق متعددة" . تم الاطلاع عليه بتاريخ 2022-05-03 .
  35. "أسئلة وأجوبة حول بيرل 6" . تم الاطلاع عليه بتاريخ 13-04-2008 .
  36. "كيف تعمل طرق S4" (ملف PDF) . تم الاطلاع عليه بتاريخ 13-04-2008 .
  37. "دليل نظام TADS 3" . تم الاطلاع عليه بتاريخ 19-03-2012 .
  38. "VB.Net Multiple Dispatch" . تم الاطلاع عليه بتاريخ 31-03-2020 .
  39. "ميزات جديدة في C# 4.0 و VB.Net 10.0" . 4 نوفمبر 2010. تم الاطلاع عليه بتاريخ 31 مارس 2020 .
  40. "ملاحظات لخبراء لغات البرمجة" . تم الاطلاع عليه بتاريخ 21-08-2016 .
  41. "إرسال متعدد" .