مرجع
آخر الزيارات

برمجة عامة

6٬231 كلمة•0 مشاهدة•🗒️ منذ 19 ساعة
باختصار: البرمجة العامة هي نمط من أنماط البرمجة تُكتب فيه الخوارزميات من حيث أنواع البيانات "يتم تحديدها لاحقًا"، ثم تُنشأ "تجسيداتها" عند الحاجة لأنواع محددة تُمرر كوسيط. تتناول المقالة 84 قسماً، منها «LIST [G]»، «g+h -> either fl fl» و«جافا».
المحتويات
  1. LIST [G]
  2. g+h -> either fl fl
  3. جافا
  4. {
  5. Rec -> \x -> x
  6. std::cout << max(3, 7); // تطبع 7
  7. القوالب العامة في .NET [C#, VB.NET]
  8. في دلفي
  9. تخصيص القوالب
  10. GC2.Free;
  11. القوالب في لغة دي
  12. flatten = cata fl
  13. begin
  14. Comparer: IComparer); overload;
  15. end Stacks;
  16. PolyP
  17. Swap(world, hello);
  18. هاسكل
  19. العمومية في إيفل
  20. {
  21. دعم لغات البرمجة للعمومية
  22. T max(T x, T y) {
  23. enum htmlTemplate = import("example.htt");
  24. في اللغات الكائنية التوجه
  25. Con t -> \x -> []
  26. نظرة فنية عامة
  27. {
  28. TUtils = class
  29. العمومية المقيدة
  30. enum htmlDCode = htmlTemplateToD(htmlTemplate);
  31. template
  32. القوالب العامة في أيدا
  33. enum bool isInputRange = is(typeof(
  34. // مُنشئ بسيط
  35. توليد الشيفرة
  36. {
  37. العمومية الأساسية غير المقيدة
  38. Element_Type => Bookmark_Type);
  39. في فري باسكال
  40. -- قائمة الودائع
  41. سي++, دي
  42. {
  43. {
  44. end;
  45. القوالب العامة في باسكال
  46. generic-programming.org
  47. المزايا والقيود
  48. لغات أخرى
  49. }
  50. القوالب العامة في هاسكل
  51. private
  52. GC2.Free;
  53. // نقطة الدخول للرمز الرئيسي
  54. feature -- تغيير العنصر
  55. ستيبانوف–مويسر وأنماط أخرى من البرمجة العامة
  56. generic
  57. }
  58. int max(int x, int y) {
  59. default: cbrt, \
  60. Max_Size : Natural; -- قيمة شكلية قالبية
  61. المزايا والعيوب
  62. }
  63. end;
  64. List list_of_cars;
  65. القوالب العامة في جافا
  66. Initial_Size : in Size_Type := Max_Size);
  67. end;
  68. }
  69. -- العنصر الذي يشير إليه المؤشر حاليًا
  70. دلفي، أوبجكت باسكال
  71. r.popFront; // يمكن استدعاء popFront
  72. ReadLn;
  73. type Bookmark_Type is new Natural;
  74. end;
  75. سي#, .نيت
  76. {
  77. }
  78. هاسكل العامة
  79. قوالب سي++
  80. -- إضافة `new_item` إلى نهاية القائمة
  81. begin
  82. مثال
  83. قراءة إضافية
  84. كلين

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

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

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

من جانب آخر، وقدّم أندريه ألكسندرسكو تقنيات جديدة في كتابه تصميم C++ الحديث: البرمجة العامة وأنماط التصميم المطبقة عام 2001، ثم طبقتها لغة دي لاحقًا.

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

LIST [G]

  • ...
  • feature -- Access
  • item: G

g+h -> either fl fl

  • g*h -> \(x,y) -> fl x ++ fl y
  • -> \x -> []
  • Par -> \x -> [x]

جافا

ومن جهة أخرى، Peter Sestoft، Java Precisely, الطبعة الثانية، 2005 MIT Press.

من جانب آخر، Maurice Naftalin و Philip Wadler، Java Generics and Collections، 2006، O'Reilly Media, Inc.

Gilad Bracha، القوالب في لغة البرمجة جافا, 2004.

، 2004 Sun Microsystems, Inc.

{

  • // متغير ثابت - سيتم زيادته مرة واحدة لكل مثيل
  • public static int Counter;
  • // مُنشئ بسيط
  • public CountedInstances

Rec -> \x -> x

d@g -> concat . flatten . pmap fl

std::cout << max(3, 7); // تطبع 7

إضافةً إلى ذلك، يقوم المترجم بتحليل المعاملات المستعملة لاستدعاء max ويحدد أن الاستدعاء هو max(int, int). ثم يُنشئ نسخة من الدالة حيث النوع T هو int، ويكافئ ذلك الدالة التالية:

القوالب العامة في .NET [C#, VB.NET]

  • using System;
  • class Sample
  • {
  • static void Main

ومن ناحية أخرى، يسمح .NET بستة أنواع من القيود على أنواع القوالب باستخدام الكلمة المفتاحية where، بما في ذلك تقييد القوالب لتكون من أنواع القيم، أو أن تكون من فئة معينة، أو أن يكون لها مُنشئ، أو أن تنفذ واجهات. فيما يلي مثال مع قيد الواجهة:

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

في دلفي

من جهة ثانية، حصلت أوبجكت باسكال (دلفي) على القوالب العامة في إصدار دلفي 11 عام 2007 بواسطة كود جير، في البداية مع المترجم .NET (الذي تم إيقافه لاحقًا) قبل أن يتم إضافتها إلى الشيفرة الأصلية في إصدار دلفي 12 عام 2009. تمت محاكاة دلالات وقدرات قوالب دلفي إلى حد كبير على قوالب .NET 2.0، على الرغم من أن التنفيذ كان مختلفًا بالضرورة. إليك ترجمة شبه مباشرة لأول مثال C# الذي تم عرضه أعلاه:

  • program Sample;
  • {$APPTYPE CONSOLE}
  • uses
  • Generics.Defaults; // لاستخدام IComparer
  • type

تخصيص القوالب

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

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

وفي السياق ذاته، تُعد "تخصيص القوالب" من الميزات القوية في قوالب C++. تتيح هذه الميزة توفير تنفيذات بديلة اعتمادًا على خصائص معينة لنوع المعامل الذي يتم إنشاؤه (instantiated). يهدف تخصيص القوالب إلى أمرين: السماح ببعض أشكال التحسين (Optimization)، وتقليل تضخم الشيفرة (Code Bloat).

GC2.Free;

اللغات الدالية

end.

القوالب في لغة دي

هذا يتجنب قالب (سي++) بسبب التضارب مع عوامل المقارنة.

من جهة ثانية، يدعم لغة دي القوالب التي تعتمد في تصميمها على سي++. أغلب أساليب قوالب سي++ تعمل في دي دون تعديل، ولكن دي تضيف بعض الوظائف:

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

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

template isInputRange(R)

{

إضافةً إلى ذلك، تستعمل القوالب في دي بناء جملة مختلفًا عن C++: بينما يتم تضمين معلمات القوالب في C++ داخل أقواس زاوية (مثل Template)، يستعمل دي علامة تعجب والأقواس: Template!(param1, param2).

إذا كان هناك معلمة واحدة فقط، يمكن الاستغناء عن الأقواس.

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

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

وفي السياق ذاته، توفر قيود القوالب وعبارة static if بديلاً عن سي++ وif constexpr في C++.

ومن ناحية أخرى، مثلًا، يتم تعريف النطاق كأي نوع يفي بالتحقق الذي يتم بواسطة isInputRange، والذي يتم تعريفه كما يلي:

flatten = cata fl

case f of

polytypic fl :: f a [a] -> [a]

begin

  • -- تهيئة مكدس العلامات المرجعية:
  • Bookmark_Stacks.Create (S => Document.Bookmarks, Initial_Size => 10);
  • -- ثم فتح الملف Document_Name وقراءته...
  • end Edit;

Comparer: IComparer); overload;

وعلى صعيد آخر، class procedure MakeAtLeast(Arr: TArray; const Lowest: T); overload;

end Stacks;

استنساخ الحزمة القالبية:

PolyP

دالة flatten في PolyP هنا موضحة كمثال:

flatten :: Regular d => d a -> [a]

ومن ناحية أخرى، كان PolyP هو أول امتداد للبرمجة العامة في هاسكل. في PolyP، تسمى الدوال العامة بـ "بوليتبيك" (Polytypic). يقدم اللغة بناء خاص حيث يمكن تعريف هذه الدوال البوليتبيكية عبر الاستقراء الهيكلي على هيكل الدالة النموذجية لنوع البيانات العادي. أنواع البيانات العادية في PolyP هي مجموعة فرعية من أنواع البيانات في هاسكل. يجب أن يكون النوع العادي t من النوع * → *، وإذا كان a هو النوع الرسمي في التعريف، فيجب أن تكون جميع الاستدعاءات التكرارية لـ t على شكل t a. هذه القيود تستبعد أنواع البيانات عالية الأنواع وأنواع البيانات المتداخلة، حيث تكون الاستدعاءات التكرارية من شكل مختلف.

Swap(world, hello);

من جهة ثانية، وقدمت سي شارب 2.0، وأوكسجين 1.5 (سابقًا كروم)، وفيجوال بيسك دوت نت 2005 بناءات تستفيد من دعم العمومية المدمج في دوت نت فريموورك من الإصدار 2.0.

إضافةً إلى ذلك، std::cout << world << hello << ‘\n’; // الناتج هو "Hello, World!".

وفي السياق ذاته، يُعتبر بناء template في لغة C++ كما في المثال أعلاه، من أكثر آليات العمومية شهرةً وانتشارًا، وقد ساهم في ترسيخ مفهوم العمومية بين المبرمجين ومصممي لغات البرمجة. وتدعم لغة D كذلك قوالب كاملة العمومية استنادًا إلى سابقات C++ ولكن ببنية أبسط. أما لغة جافا، فقد وفرت آليات للعمومية ببنية نحوية مستوحاة من C++ منذ إصدار منصة جافا 5.0.

هاسكل

علاوةً على ذلك، Ralf Hinze، "القوالب من أجل الجميع "، في إجراءات جمعية آلات الحوسبة SIGPLAN المؤتمر الدولي للبرمجة الوظيفية (ICFP)، 2004.

علاوةً على ذلك، Andres Löh، استكشاف Generic Haskell, أطروحة دكتوراه، 2004 جامعة أترخت.

كذلك، Johan Jeuring، Sean Leather، José Pedro Magalhães، وAlexey Rodriguez Yakushev. المكتبات للبرمجة العامة في هاسكل. جامعة أوترخت.

إضافةً إلى ذلك، Ralf Lämmel وسيمون بيتن جونز، "تخلص من الرتابة: نمط تصميم عملي للبرمجة العامة"، في إجراءات ورشة العمل الدولية لـ جمعية آلات الحوسبة SIGPLAN حول الأنواع في تصميم وتنفيذ اللغات (TLDI'03)، 2003. (انظر كذلك الموقع المخصص لهذا البحث)

Generic Haskell: لغة للبرمجة العامة

سيمون بيتن جونز، محرر، تقرير لغة هاسكل 98 ، المنقح 2002.

إضافةً إلى ذلك، Dæv Clarke، Johan Jeuring وAndres Löh، دليل المستعمل لـ Generic Haskell

العمومية في إيفل

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

{

}

// ...

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

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

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

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

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

T max(T x, T y) {

return x < y ? y : x;

enum htmlTemplate = import("example.htt");

// تحويل قالب HTML إلى كود D.

في اللغات الكائنية التوجه

  • template
  • class List {
  • // محتوى الصنف
  • };
  • List list_of_animals;

علاوةً على ذلك، عند إنشاء أصناف حاوية في لغات ذات تصنيف ثابت، يكون من غير العملي كتابة تنفيذات خاصة بكل نوع بيانات يحتويه الصنف، خاصة إذا كانت الشيفرة لكل نوع متشابهة إلى حد كبير. مثلًا، في لغة C++، يمكن تفادي تكرار الشيفرة بتعريف قالب صنف:

Con t -> \x -> []

cata :: Regular d => (FunctorOf d a b -> b) -> d a -> b

نظرة فنية عامة

وفي السياق ذاته، توجد أنواع عديدة من القوالب، وأكثرها شيوعًا هي قوالب الدوال وقوالب الأصناف. قالب الدالة هو نمط لإنشاء دوال عادية استنادًا إلى أنواع المعاملات التي تُمرَّر عند الاستدعاء. مثلًا، تحتوي مكتبة القوالب المعيارية على قالب دالة max(x, y) ينشئ دالة تُرجع إما "x" أو "y" أيهما أكبر. يمكن تعريف max كما يلي:

template

{

  • for (int i = 0; i < list.Length; i++)
  • if (list[i].CompareTo(lowest) < 0)
  • list[i] = lowest;
  • }

TUtils = class

class procedure MakeAtLeast(Arr: TArray; const Lowest: T;

العمومية المقيدة

من جانب آخر، بالنسبة للفئة القائمة التي تم عرضها أعلاه، يمكن أن تكون المعلمة العامة الفعلية التي تحل محل G أي فئة أخرى متاحة. لتقييد مجموعة الفئات التي يمكن اختيار معلمات عامة فعلية صالحة منها، يمكن تحديد "قيد عام". في إعلان الفئة SORTED_LIST أدناه، يحدد القيد العام أن أي معلمة عامة فعلية صالحة ستكون فئة ترث من الفئة COMPARABLE. يضمن القيد العام أن عناصر SORTED_LIST يمكن فرزها بالفعل.

class

SORTED_LIST [G -> COMPARABLE]

enum htmlDCode = htmlTemplateToD(htmlTemplate);

// لصق محتويات htmlDCode ككود D.

mixin(htmlDCode);

template

  • void Swap(T& a, T& b) { // يوجد دالة مشابهة ولكن أكثر أمانًا وسرعة في مكتبة
  • T temp = b;
  • b = a;
  • a = temp;
  • }
  • std::string world = "World!";
  • std::string hello = "Hello, ";

القوالب العامة في أيدا

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

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

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

من جهة ثانية، تمتاز أيدا بدعمها للقوالب منذ تصميمها الأول في الفترة بين 1977–1980. وتستعمل المكتبة المعيارية القوالب لتوفير الكثير من الخدمات. وقد أضافت أيدا 2005 مكتبة حاويات عامة شاملة إلى المكتبة القياسية، مستوحاة من مكتبة القوالب المعيارية في ++C.

enum bool isInputRange = is(typeof(

(inout int = 0)

// مُنشئ بسيط

  • public GenTest(T t)
  • {
  • _t = t;
  • }
  • }
  • // فئة
  • public class CountedInstances

توليد الشيفرة

ومن ناحية أخرى، يتيح تنفيذ الدوال أثناء الترجمة (CTFE) جزءًا من دي (مقتصرًا على العمليات الآمنة) ليتم تفسيره أثناء الترجمة.

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

في هذا الإطار، فضلًا عن البرمجة الميتاقالبية ، تقدم دي عدة ميزات لتمكين توليد الشيفرة أثناء الترجمة:

في هذا الإطار، يمكن أن تشير السمات التي يعرفها المستعمل كذلك إلى قواعد التسلسل.

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

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

// استيراد محتويات example.htt كقيمة ثابتة نصية.

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

وفي السياق ذاته، يتيح الانعكاس أثناء الترجمة تفحص القيم والتصريحات وأعضائها أثناء الترجمة.

علاوةً على ذلك، يسمح تعبير import بقراءة ملف من القرص واستخدام محتوياته كتعبير نصي.

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

ومن ناحية أخرى، مثلًا، نظرًا لدالة تأخذ سلسلة تحتوي على قالب HTML وتُرجع كود دي المعادل، يمكن استخدامها على النحو التالي:

{

if (r.empty) {} // يمكن اختبار إذا كان فارغًا

R r = R.init; // يمكن تعريف كائن نطاق

العمومية الأساسية غير المقيدة

ومن جهة أخرى، يتم الإعلان عن القوالب العامة باستخدام اسم الفئة وقائمة من "المعلمات العامة الرسمية". في الشيفرة التالية، تحتوي الفئة LIST على معلمة عامة رسمية واحدة G

class

Element_Type => Bookmark_Type);

  • -- يسمح للمستعمل بالقفز بين المواقع المسجلة في المستند
  • استخدام نسخة من حزمة قالبية:
  • type Document_Type is record
  • Contents : Ada.Strings.Unbounded.Unbounded_String;
  • Bookmarks : Bookmark_Stacks.Stack;
  • end record;
  • procedure Edit (Document_Name : in String) is
  • Document : Document_Type;

في فري باسكال

وفي السياق ذاته، تم تنفيذ القوالب العامة في فري باسكال في سنة 2006، قبل دلفي وبصيغة ودلالات مختلفة. ومع ذلك، منذ إصدار FPC 2.6.0، أصبحت صيغة دلفي متاحة عند استخدام وضع اللغة {$mode Delphi}. وبالتالي، يدعم فري باسكال القوالب العامة في أي من الأساليب.

  • مثال دلفي وفري باسكال:
  • // أسلوب دلفي
  • unit A;
  • {$ifdef fpc}
  • {$mode delphi}
  • {$endif}
  • interface
  • type
  • TGenericClass = class
  • function Foo(const AValue: T): T;
  • end;
  • implementation
  • function TGenericClass.Foo(const AValue: T): T;
  • begin
  • Result := AValue + AValue;

-- قائمة الودائع

كذلك، ضمن نظام النوع في إيفل، على الرغم من أن الفئة LIST [G] تعتبر فئة، إلا أنها لا تُعتبر نوعًا. ومع ذلك، يتم اعتبار اشتقاق قالب LIST [G] مثل LIST [ACCOUNT] نوعًا.

سي++, دي

من جهة ثانية، Walter Bright، القوالب المعاد النظر فيها . David Vandevoorde، Nicolai M Josuttis، قوالب C++: الدليل الكامل، 2003 Addison-Wesley.

{

  • int[] array = { 0, 1, 2, 3 };
  • MakeAtLeast(array, 2); // تغيير المصفوفة إلى { 2, 2, 2, 3 }
  • foreach (int i in array)
  • Console.WriteLine(i); // طباعة النتائج.
  • Console.ReadKey(true);

{

  • // متغير ثابت - سيتم إنشاؤه لكل نوع عند الانعكاس
  • static CountedInstances OnePerType = new CountedInstances;
  • // عضو بيانات
  • private T _t;

end;

  • end.
  • // أسلوب فري باسكال ObjFPC
  • unit B;
  • {$ifdef fpc}
  • {$mode objfpc}
  • {$endif}
  • interface
  • type
  • generic TGenericClass = class
  • function Foo(const AValue: T): T;
  • end;
  • implementation
  • function TGenericClass.Foo(const AValue: T): T;
  • begin
  • Result := AValue + AValue;

القوالب العامة في باسكال

في هذا الإطار، بالنسبة لباسكال، تم تنفيذ القوالب العامة لأول مرة في سنة 2006 في تنفيذ فري باسكال.

generic-programming.org

ومن ناحية أخرى، Alexander A. Stepanov، مجموعة أوراق ألكسندر أ. ستبانوف (مؤسس مكتبة القوالب المعيارية)

المزايا والقيود

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

لغات أخرى

ومن جهة أخرى، قد يتخذ فيريلوج وحدة برمجية واحدة أو أكثر من المعلمات، حيث يتم تعيين قيمها الفعلية عند تنفيذ الوحدة. أحد الأمثلة هو مصفوفة سجل (العتاد) عامة حيث يتم تحديد عرض المصفوفة عبر معلمة. يمكن لهذه المصفوفة، إلى جانب ناقل الأسلاك العام، أن تُشكل ذاكرة أو مخزن عام بعرض بت عشوائي من خلال تنفيذ وحدة واحدة فقط.Verilog by Example, Section The Rest for Reference. Blaine C. Readler, Full Arc Press, 2011.

#define cbrt(x) _Generic((x), long double: cbrtl, \

وفي هذا السياق، تدعم سي "التعبيرات العامة المرتبطة بالنوع" باستخدام الكلمة المفتاحية _GenericWG14 N1516 Committee Draft — October 4, 2010

في هذا الإطار، يشتمل في إتش دي إل، المشتق من آدا، كذلك على قدرات عامة.https://www.ics.uci.edu/~jmoorkan/vhdlref/generics.html VHDL Reference

وفي هذا الصدد، اللغات في عائلة أم أل تدعم البرمجة العامة من خلال التعددية البراميترية والبرمجة التركيبية العامة المسماة "الدوال"، والتي هي مشابهة لقوالب الفئات في C++ وعبوات البرمجة العامة في لغة آدا. توفر كل من أم أل المعيارية ولغة كامل الموضوعية دوال (Functors)، التي تشبه قوالب الفئات في C++ وعبوات البرمجة العامة في آدا. كما أن سكيم توفر تجريدات تركيبية ترتبط بالتعميم - وهي في الواقع مجموعة شاملة من قوالب C++.

}

من جهة ثانية، يمكن استدعاء التخصيصات لهذه الدالة، أي النُسخ المنشأة بأنواع معينة، كما لو كانت دوال عادية:

القوالب العامة في هاسكل

deriving (Eq, Show)

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

ومن ناحية أخرى، ينتج عن ذلك تعريف دالة التساوي (==) ودالة تمثيل السلسلة النصية (show) تلقائيًا لأي نوع من النوع BinTree T بشرط أن يدعم T هذه العمليات.

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

private

  • subtype Index_Type is Size_Type range 1 .. Max_Size;
  • type Vector is array (Index_Type range ) of Element_Type;
  • type Stack (Allocated_Size : Size_Type := 0) is record
  • Top : Index_Type;
  • Storage : Vector (1 .. Allocated_Size);
  • end record;

GC2.Free;

  • end.
  • // مثال للاستخدام بأسلوب ObjFPC
  • program TestGenDelphi;
  • {$ifdef fpc}
  • {$mode objfpc}
  • {$endif}
  • uses
  • A,B;
  • // مطلوب في ObjFPC
  • type
  • TAGenericClassInt = specialize A.TGenericClass;
  • TBGenericClassString = specialize B.TGenericClass;
  • var
  • GC1: TAGenericClassInt;
  • GC2: TBGenericClassString;
  • begin
  • GC1 := TAGenericClassInt.Create;
  • GC2 := TBGenericClassString.Create;
  • WriteLn(GC1.Foo(100)); // 200
  • WriteLn(GC2.Foo('hello')); // hellohello
  • GC1.Free;

// نقطة الدخول للرمز الرئيسي

  • // في نهاية التنفيذ، سيكون CountedInstances.Counter = 2
  • GenTest g1 = new GenTest(1);
  • GenTest g11 = new GenTest(11);
  • GenTest g111 = new GenTest(111);
  • GenTest g2 = new GenTest(1.0);

feature -- تغيير العنصر

put (new_item: G)

ستيبانوف–مويسر وأنماط أخرى من البرمجة العامة

في هذا الإطار، في هذه المقالة، نُميز بين أنماط نمط برمجة البرمجة العمومية عالية المستوى، كما ورد أعلاه، وبين آليات "العمومية" على مستوى اللغة المستعملة في تنفيذها (انظر دعم لغات البرمجة للعمومية). لمزيد من النقاش والمقارنة بين أنماط البرمجة العمومية، انظر:

أشار بيارن ستروستروب إلى:

تُعرّف البرمجة العامة في على النحو الآتي:

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

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

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

في هذا الإطار، وقد طُبّق نهج البرمجة العامة بالمثل في مجالات أخرى مثل خوارزميات الرسوم البيانية.

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

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

generic

  • type Index_Type is ; -- يجب أن يكون نوعاً منفصلاً
  • type Element_Type is private; -- يمكن أن يكون أي نوع غير محدود
  • type Array_Type is array (Index_Type range ) of Element_Type;

وعلى صعيد آخر، في هذا المثال، يتم تقييد النوع Array_Type بالنوعين Index_Type وElement_Type. وعند استنساخ الوحدة، يجب على المبرمج تمرير نوع مصفوفة فعلي يحقق هذه القيود.

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

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

كذلك، * الكائنات الفعلية المقابلة لكائن شكلي قالبي تُعتبر دائماً غير ساكنة داخل القالب؛ انظر Generic formal objects في ويكي الكتب لمزيد من التفاصيل والنتائج.

علاوةً على ذلك، وعلى عكس ++C، لا تسمح أيدا بإنشاء نسخ متخصصة للقوالب، وتتطلب أن يتم استنساخ كل قالب بشكل صريح. لهذه القواعد عدة نتائج:

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

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

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

وفي هذا الصدد، يمكن للمُصرّف تنفيذ "قوالب مشتركة": يمكن مشاركة الشيفرة الكائنية لوحدة قالبية بين كل النسخ (ما لم يطلب المبرمج تضمين البرامج الفرعية، بطبيعة الحال). وكنتيجة لذلك:

من جانب آخر، * لا توجد احتمالية للتضخم البرمجي (وهو شائع في ++C ويحتاج لعناية خاصة).

}

if (isInputRange!Range)

auto fun(Range)(Range range)

علاوةً على ذلك، دالة تقبل فقط النطاقات المدخلات يمكنها فيما بعد استخدام القالب أعلاه في قيد القالب:

int max(int x, int y) {

return x < y ? y : x;

default: cbrt, \

  • float: cbrtf)(x)
  • انظر كذلك
  • تعددية الأشكال
  • المراجع
  • المصادر

Max_Size : Natural; -- قيمة شكلية قالبية

  • type Element_Type is private; -- نوع شكلي قالب؛ يقبل أي نوع غير محدود
  • package Stacks is
  • type Size_Type is range 0 .. Max_Size;
  • type Stack is limited private;
  • procedure Create (S : out Stack;

المزايا والعيوب

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

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

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

لكن، هناك أربع سلبيات رئيسية لاستخدام القوالب:

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

وفي هذا الصدد، بعض استخدامات القوالب، مثل دالة max، كانت تُنفّذ سابقًا باستخدام معالج مسبق وماكرو (علم الحاسوب) شبيه بالدالة (وهو من بقايا لغة سي). مثلًا، إليك تنفيذ ممكن لماكرو مماثل:

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

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

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

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

#define max(a,b) ((a) < (b) ? (b) : (a))

من جانب آخر، قد تُنتج المترجمات رسائل خطأ طويلة ومربكة وغير مفيدة أحيانًا عند اكتشاف أخطاء في الشيفرات التي تستعمل مبدأ "الفشل في الاستبدال ليس خطأً" (SFINAE)، لا سيما في الإصدارات السابقة لـ C++20.، مما يصعب تطوير القوالب.

}

// فئة عامة

public class GenTest

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

علاوةً على ذلك، يمكن كذلك كتابة الطريقة أعلاه بدون القوالب العامة، باستخدام ببساطة النوع غير العام Array. ومع ذلك، بما أن المصفوفات هي لاتباين وتباين مرافق وتباين معاكس، فإن التحويل لن يكون سلامة الأنماط، ولن يتمكن المترجم من العثور على بعض الأخطاء المحتملة التي سيتم اكتشافها عند استخدام القوالب العامة. فضلًا عن ذلك، ستحتاج الطريقة إلى الوصول إلى عناصر المصفوفة كـ object بدلاً من ذلك، وستتطلب التحويل في c++ لمقارنة عنصرين. (بالنسبة لأنواع القيم مثل int، يتطلب هذا التعبئة، على الرغم من أنه يمكن التغلب على ذلك باستخدام فئة Comparer، كما هو الحال في فئات التجميع القياسية).

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

end;

  • class procedure TUtils.MakeAtLeast(Arr: TArray; const Lowest: T);
  • begin
  • MakeAtLeast(Arr, Lowest, nil);
  • end;
  • var
  • Ints: TArray;
  • Value: Integer;
  • begin
  • Ints := TArray.Create(0, 1, 2, 3);
  • TUtils.MakeAtLeast(Ints, 2);
  • for Value in Ints do
  • WriteLn(Value);

List list_of_cars;

وعلى صعيد آخر، في المثال أعلاه، T هو عنصر نائب يُستبدل بالنوع الذي يُحدَّد عند إنشاء القائمة. هذه "الحاويات من نوع T"، والتي تُعرف عمومًا باسم القالب، تتيح إعادة استخدام الصنف مع أنواع بيانات مختلفة طالما تم احترام بعض العقود مثل الأنواع الفرعية وتوقيع النوع. لا ينبغي الخلط بين هذه الآلية العمومية وبين تعددية الأشكال، التي تشير إلى الاستخدام الخوارزمي للفئات القابلة للاستبدال: مثلًا، قائمة من الكائنات من النوع Moving_Object تحتوي على كائنات من نوع Animal وCar. يمكن كذلك استخدام القوالب لإنشاء دوال مستقلة عن النوع كما في مثال Swap أدناه:

// "&" تعني تمرير بالمرجع

القوالب العامة في جافا

كذلك، تم إضافة دعم للقوالب العامة، أو "الحاويات من النوع T"، إلى جافا في سنة 2004 كجزء من J2SE 5.0. في جافا، يتم التحقق من القوالب العامة فقط في وقت الترجمة للتأكد من صحة الأنواع. ثم يتم إزالة معلومات النوع عبر عملية تُسمى محو النوع، للحفاظ على التوافق مع الإصدارات القديمة من آلة جافا الافتراضية، مما يجعلها غير متاحة في وقت التشغيل. مثلًا، يتم تحويل List إلى النوع الخام List. يقوم المترجم بإدراج التحويل في c++ لتحويل العناصر إلى نوع String عندما يتم استرجاعها من القائمة، مما يقلل من الأداء مقارنة بالتنفيذات الأخرى مثل قوالب C++.

Initial_Size : in Size_Type := Max_Size);

  • procedure Push (Into : in out Stack; Element : in Element_Type);
  • procedure Pop (From : in out Stack; Element : out Element_Type);
  • Overflow : exception;
  • Underflow : exception;

end;

  • end.
  • // مثال للاستخدام بأسلوب دلفي
  • program TestGenDelphi;
  • {$ifdef fpc}
  • {$mode delphi}
  • {$endif}
  • uses
  • A,B;
  • var
  • GC1: A.TGenericClass;
  • GC2: B.TGenericClass;
  • begin
  • GC1 := A.TGenericClass.Create;
  • GC2 := B.TGenericClass.Create;
  • WriteLn(GC1.Foo(100)); // 200
  • WriteLn(GC2.Foo('hello')); // hellohello
  • GC1.Free;

}

وعلى صعيد آخر، static void MakeAtLeast(T[] list, T lowest) where T : IComparable

-- العنصر الذي يشير إليه المؤشر حاليًا

...

دلفي، أوبجكت باسكال

وفي هذا الصدد، Nick Hodges، "دليل مراجعي Delphi 2009 "، أكتوبر 2008، شبكة مطوري Embarcadero، Embarcadero.

  • Craig Stuntz، "Delphi 2009 القوالب وقيود النوع"، أكتوبر 2008
  • Dr. Bob، "Delphi 2009 القوالب "
  • فري باسكال: دليل مرجع Free Pascal الفصل 8: القوالب، Michaël Van Canneyt، 2007
  • Delphi for Win32: القوالب مع Delphi 2009 Win32 ، Sébastien DOERAENE، 2008
  • Delphi for .NET: Delphi القوالب ، Felix COLIBRI، 2008
  • إيفل
  • مواصفة إيفل ISO/ECMA

r.popFront; // يمكن استدعاء popFront

auto h = r.front; // يمكن الحصول على مقدمة النطاق

}));

ReadLn;

end.

وفي هذا السياق، كما في C#، يمكن أن تحتوي الأساليب والأنواع الكاملة على معلمات نوع واحدة أو أكثر. في المثال، TArray هو نوع عام (مُعرف من قبل اللغة) وMakeAtLeast هو أسلوب عام. القيود المتاحة مشابهة جدًا لتلك المتاحة في C#: أي نوع من القيم، أي فئة، فئة أو واجهة محددة، وفئة بها مُنشئ بلا معلمات. القيود المتعددة تعمل كاتحاد إضافي.

type Bookmark_Type is new Natural;

-- يمثل موقعاً في مستند النص الجاري تعديله

package Bookmark_Stacks is new Stacks (Max_Size => 20,

end;

  • class procedure TUtils.MakeAtLeast(Arr: TArray; const Lowest: T;
  • Comparer: IComparer);
  • var
  • I: Integer;

سي#, .نيت

وفي هذا الصدد، Jason Clark، "تقديم القوالب في CLR الخاص بشركة Microsoft "، سبتمبر 2003، مجلة MSDN، Microsoft.

وفي هذا السياق، Jason Clark، "المزيد عن القوالب في CLR الخاص بشركة Microsoft "، أكتوبر 2003، مجلة MSDN، Microsoft.

وفي السياق ذاته، M. Aamir Maniar، Generics.Net . مكتبة قوالب مفتوحة المصدر لـ C#.

{

  • // زيادة العداد بمقدار واحد عند إنشاء الكائن
  • CountedInstances.Counter++;
  • }
  • }

}

ومن ناحية أخرى، يعمل هذا سواء كانت القيم x وy أعدادًا صحيحة أو سلاسل نصية أو أي نوع آخر يمكن تطبيق التعبير x < y عليه، أو بشكل أدق، لأي نوع تم تعريف العامل operator< له. لا يشترط وجود وراثة مشتركة بين الأنواع المستعملة، لذا فهو مشابه لمفهوم تنويع البط. يمكن لأي برنامج يعرّف نوع بيانات مخصص أن يحدد معنى العامل < لهذا النوع باستخدام تحميل زائد للعملية، مما يسمح باستخدامه مع قالب الدالة max. ورغم أن هذه الفائدة قد تبدو بسيطة في هذا المثال المحدود، إلا أنها توفر الكثير من الوظائف في سياق مكتبة شاملة مثل STL؛ إذ يكفي تعريف بعض المعاملات لنوع جديد من البيانات كي يصبح قابلًا للاستخدام مع خوارزميات قياسية مثل sort وstable_sort وbinary_search، أو إدراجه ضمن هياكل بيانات مثل set وإدارة الذاكرة ومصفوفة ارتباطية.

وفي هذا السياق، تُعد قوالب C++ آمنة تمامًا من حيث سلامة الأنماط أثناء وقت الترجمة. كمثال توضيحي، فإن النوع القياسي complex لا يعرّف العامل <، لأنه لا توجد علاقة ترتيب صارمة على الأعداد المركبة. لذلك، فإن استدعاء max(x, y) سيفشل بخطأ في الترجمة إذا كانت x وy من نوع complex. وبالمثل، لا يمكن تطبيق قوالب أخرى تعتمد على < على بيانات complex ما لم يتم توفير دالة مقارنة (على شكل دالة أو كائن دالة). مثلًا: لا يمكن استخدام complex كمفتاح في map ما لم تُوفر مقارنة. للأسف، غالبًا ما تُصدر المترجمات رسائل خطأ غامضة وغير مفيدة لهذا النوع من الأخطاء. ويمكن التخفيف من هذه المشكلة بضمان التزام الكائن ببروتوكول معين بروتوكول (اتصالات). كما أن اللغات التي تستعمل دالة compare بدلاً من العامل < يمكنها استخدام قيم complex كمفاتيح.

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

هاسكل العامة

في هذا الإطار، هاسكل العامة هي امتداد آخر لـ هاسكل، تم تطويره في جامعة أترخت في هولندا. توفر الامتدادات التالية:

كذلك، أنواع المؤشرات على النوع هي أنواع مؤشرة على منشئي الأنواع. يمكن استخدامها لإعطاء أنواع لقيم عامة أكثر تعقيدًا. يمكن تخصيص هذه الأنواع المؤشرة على النوع لأي نوع.

ومن ناحية أخرى، أنواع المؤشرات على النوع هي أنواع مؤشرة على الأنواع، تُعرف عبر إعطاء حالة لكل من * وk → k. يتم الحصول على المثيلات عن طريق تطبيق النوع المؤشر على النوع.

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

type Eq {[ * ]} t1 t2 = t1 -> t2 -> Bool

eq {| t :: k |} :: Eq {[ k ]} t t

كمثال، دالة التساوي في هاسكل العامة:

من جانب آخر، التجريد العام يتيح تعريف التعريفات العامة عبر تجريد معلمة النوع (من نوع معين).

من جهة ثانية، type Eq {[ k -> l ]} t1 t2 = forall u1 u2. Eq {[ k ]} u1 u2 -> Eq {[ l ]} (t1 u1) (t2 u2)

في هذا الإطار، يمكن استخدام التعريفات العامة عن طريق تطبيقها على نوع أو نوع مؤشر. يُسمى هذا بـ "التطبيق العام". النتيجة هي نوع أو قيمة، حسب نوع التعريف العام الذي يتم تطبيقه.

القيمة المؤشرة على النوع الناتجة يمكن تخصيصها لأي نوع.

قوالب سي++

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

-- إضافة `new_item` إلى نهاية القائمة

...

  • list_of_accounts: LIST [ACCOUNT]
  • -- قائمة الحسابات
  • list_of_deposits: LIST [DEPOSIT]

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

begin

  • if Comparer = nil then Comparer := TComparer.Default;
  • for I := Low(Arr) to High(Arr) do
  • if Comparer.Compare(Arr[I], Lowest) < 0 then
  • Arr[I] := Lowest;

مثال

مواصفة حزمة قالبية:

generic

قراءة إضافية

وفي هذا الصدد، Gabriel Dos Reis و Jaakko Järvi، ما هي البرمجة العامة؟ ، LCSD 2005 .

الوصلات الخارجية

كلين

وفي السياق ذاته، تقدم كلين البرمجة العامة عبر PolyP وهاسكل العامة كما يدعمها GHC ≥ 6.0. يتم برمجة القوالب باستخدام النوع، كما هو الحال في هاسكل، ولكنه يوفر التحميل الزائد .

ما رأيك في هذه المقالة؟

📝 هل في هذه المقالة خطأ؟

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