برمجة عامة

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


```cpp
template<typename T>
class List {
  // محتوى الصنف
};

List<Animal> list_of_animals;
List<Car> list_of_cars;
```


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


```cpp
// "&" تعني تمرير بالمرجع
template<typename T>
void Swap(T& a, T& b) { // يوجد دالة مشابهة ولكن أكثر أمانًا وسرعة في مكتبة <utility>
  T temp = b;
  b = a;
  a = temp;
}

std::string world = "World!";
std::string hello = "Hello, ";
Swap(world, hello);
std::cout << world << hello << ‘\n’;  // الناتج هو "Hello, World!".
```


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

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

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

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

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

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

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


```ada
generic
    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;
                      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;
 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;
 end Stacks;
```


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


```ada
type Bookmark_Type is new Natural;
 -- يمثل موقعاً في مستند النص الجاري تعديله

 package Bookmark_Stacks is new Stacks (Max_Size => 20,
                                        Element_Type => Bookmark_Type);
 -- يسمح للمستخدم بالقفز بين المواقع المسجلة في المستند
```


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


```ada
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;
 begin
   -- تهيئة مكدس العلامات المرجعية:
   Bookmark_Stacks.Create (S => Document.Bookmarks, Initial_Size => 10);
   -- ثم فتح الملف Document_Name وقراءته...
 end Edit;
```


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


```ada
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. وعند استنساخ الوحدة، يجب على المبرمج تمرير نوع مصفوفة فعلي يحقق هذه القيود.

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

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

#### قوالب سي++

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

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


```cpp
template<typename T>
T max(T x, T y) {
  return x < y ? y : x;
}
```


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


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


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


```cpp
int max(int x, int y) {
  return x < y ? y : x;
}
```


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

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

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

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

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

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

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


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


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

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

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

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

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

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

#### القوالب في لغة دي
يدعم لغة دي القوالب التي تعتمد في تصميمها على سي++. معظم أساليب قوالب سي++ تعمل في دي دون تعديل، ولكن دي تضيف بعض الوظائف:
* معلمات القوالب في دي لا تقتصر فقط على الأنواع والقيم البدائية (كما كان الحال في C++ قبل C++20)، بل تسمح أيضًا بالقيم الزمنية التي تُحسب أثناء الترجمة (مثل السلاسل النصية والتمثيلات الهيكلية)، وأسماء مستعارة (aliases) لمعرفات عشوائية، بما في ذلك القوالب الأخرى أو التخصيصات القالبية.
* توفر قيود القوالب وعبارة `static if` بديلاً عن سي++ و`if constexpr` في C++.
* تعبير `is(...)` يسمح بإنشاء قوالب استكشافية للتحقق من سمات الكائن أثناء الترجمة.
* يسمح كل من الكلمة المفتاحية `auto` والتعبير `[[typeof]]` باستنتاج النوع للمتغيرات وقيم إرجاع الدوال، مما يسمح بوجود "أنواع فولدمورت" (أنواع لا تحمل اسمًا عالميًا).

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

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


```d
template isInputRange(R)
{
    enum bool isInputRange = is(typeof(
    (inout int = 0)
    {
        R r = R.init;     // يمكن تعريف كائن نطاق
        if (r.empty) {}   // يمكن اختبار إذا كان فارغًا
        r.popFront();     // يمكن استدعاء popFront()
        auto h = r.front; // يمكن الحصول على مقدمة النطاق
    }));
}
```


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


```d
auto fun(Range)(Range range)
    if (isInputRange!Range)
{
    // ...
}
```


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

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

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


```d
// استيراد محتويات example.htt كقيمة ثابتة نصية.
enum htmlTemplate = import("example.htt");

// تحويل قالب HTML إلى كود D.
enum htmlDCode = htmlTemplateToD(htmlTemplate);

// لصق محتويات htmlDCode ككود D.
mixin(htmlDCode);
```


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

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


```eiffel
class
    LIST [G]
            ...
feature   -- Access
    item: G
            -- العنصر الذي يشير إليه المؤشر حاليًا
            ...
feature   -- تغيير العنصر
    put (new_item: G)
            -- إضافة `new_item` إلى نهاية القائمة
            ...
```


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


```eiffel
list_of_accounts: LIST [ACCOUNT]
            -- قائمة الحسابات

    list_of_deposits: LIST [DEPOSIT]
            -- قائمة الودائع
```


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

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

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


```eiffel
class
    SORTED_LIST [G -> COMPARABLE]
```


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

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

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


```csharp
using System;

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

    static void MakeAtLeast<T>(T[] list, T lowest) where T : IComparable<T>
    {
        for (int i = 0; i < list.Length; i++)
            if (list[i].CompareTo(lowest) < 0)
                list[i] = lowest;
    }
}
```


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

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

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


```csharp
// فئة عامة
    public class GenTest<T>
    {
        // متغير ثابت - سيتم إنشاؤه لكل نوع عند الانعكاس
        static CountedInstances OnePerType = new CountedInstances();

        // عضو بيانات
        private T _t;

        // مُنشئ بسيط
        public GenTest(T t)
        {
            _t = t;
        }
    }

    // فئة
    public class CountedInstances
    {
        // متغير ثابت - سيتم زيادته مرة واحدة لكل مثيل
        public static int Counter;

        // مُنشئ بسيط
        public CountedInstances()
        {
            // زيادة العداد بمقدار واحد عند إنشاء الكائن
            CountedInstances.Counter++;
        }
    }

 // نقطة الدخول للرمز الرئيسي
 // في نهاية التنفيذ، سيكون CountedInstances.Counter = 2
GenTest<int> g1 = new GenTest<int>(1);
GenTest<int> g11 = new GenTest<int>(11);
GenTest<int> g111 = new GenTest<int>(111);
GenTest<double> g2 = new GenTest<double>(1.0);
```


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

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


```delphi
program Sample;

{$APPTYPE CONSOLE}

uses
  Generics.Defaults; // لاستخدام IComparer<>

type
  TUtils = class
    class procedure MakeAtLeast<T>(Arr: TArray<T>; const Lowest: T;
      Comparer: IComparer<T>); overload;
    class procedure MakeAtLeast<T>(Arr: TArray<T>; const Lowest: T); overload;
  end;

class procedure TUtils.MakeAtLeast<T>(Arr: TArray<T>; const Lowest: T;
  Comparer: IComparer<T>);
var
  I: Integer;
begin
  if Comparer = nil then Comparer := TComparer<T>.Default;
  for I := Low(Arr) to High(Arr) do
    if Comparer.Compare(Arr[I], Lowest) < 0 then
      Arr[I] := Lowest;
end;

class procedure TUtils.MakeAtLeast<T>(Arr: TArray<T>; const Lowest: T);
begin
  MakeAtLeast<T>(Arr, Lowest, nil);
end;

var
  Ints: TArray<Integer>;
  Value: Integer;
begin
  Ints := TArray<Integer>.Create(0, 1, 2, 3);
  TUtils.MakeAtLeast<Integer>(Ints, 2);
  for Value in Ints do
    WriteLn(Value);
  ReadLn;
end.
```


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

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

مثال دلفي وفري باسكال:

```delphi
// أسلوب دلفي
unit A;

{$ifdef fpc}
  {$mode delphi}
{$endif}

interface

type
  TGenericClass<T> = class
    function Foo(const AValue: T): T;
  end;

implementation

function TGenericClass<T>.Foo(const AValue: T): T;
begin
  Result := AValue + AValue;
end;

end.

// أسلوب فري باسكال ObjFPC
unit B;

{$ifdef fpc}
  {$mode objfpc}
{$endif}

interface

type
  generic TGenericClass<T> = class
    function Foo(const AValue: T): T;
  end;

implementation

function TGenericClass.Foo(const AValue: T): T;
begin
  Result := AValue + AValue;
end;

end.

// مثال للاستخدام بأسلوب دلفي
program TestGenDelphi;

{$ifdef fpc}
  {$mode delphi}
{$endif}

uses
  A,B;

var
  GC1: A.TGenericClass<Integer>;
  GC2: B.TGenericClass<String>;
begin
  GC1 := A.TGenericClass<Integer>.Create;
  GC2 := B.TGenericClass<String>.Create;
  WriteLn(GC1.Foo(100)); // 200
  WriteLn(GC2.Foo('hello')); // hellohello
  GC1.Free;
  GC2.Free;
end.

// مثال للاستخدام بأسلوب ObjFPC
program TestGenDelphi;

{$ifdef fpc}
  {$mode objfpc}
{$endif}

uses
  A,B;

// مطلوب في ObjFPC
type
  TAGenericClassInt = specialize A.TGenericClass<Integer>;
  TBGenericClassString = specialize B.TGenericClass<String>;
var
  GC1: TAGenericClassInt;
  GC2: TBGenericClassString;
begin
  GC1 := TAGenericClassInt.Create;
  GC2 := TBGenericClassString.Create;
  WriteLn(GC1.Foo(100)); // 200
  WriteLn(GC2.Foo('hello')); // hellohello
  GC1.Free;
  GC2.Free;
end.
```


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


```haskell
data BinTree a = Leaf a | Node (BinTree a) a (BinTree a)
      deriving (Eq, Show)
```


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

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

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


```haskell
flatten :: Regular d => d a -> [a]
   flatten = cata fl

   polytypic fl :: f a [a] -> [a]
     case f of
       g+h -> either fl fl
       g*h -> \(x,y) -> fl x ++ fl y
       () -> \x -> []
       Par -> \x -> [x]
       Rec -> \x -> x
       d@g -> concat . flatten . pmap fl
       Con t -> \x -> []

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


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

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


```haskell
type Eq {[ * ]} t1 t2 = t1 -> t2 -> Bool
   type Eq {[ k -> l ]} t1 t2 = forall u1 u2. Eq {[ k ]} u1 u2 -> Eq {[ l ]} (t1 u1) (t2 u2)

   eq  :: Eq {[ k ]} t t
   eq  _ _ = True
   eq  eqA eqB (Inl a1) (Inl a2) = eqA a1 a2
   eq  eqA eqB (Inr b1) (Inr b2) = eqB b1 b2
   eq  eqA eqB _ _ = False
   eq  eqA eqB (a1 :*: b1) (a2 :*: b2) = eqA a1 a2 && eqB b1 b2
   eq  = (==)
   eq  = (==)
   eq  = (==)
```


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

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

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

يشتمل في إتش دي إل، المشتق من آدا، أيضًا على قدرات عامة.

تدعم سي "التعبيرات العامة المرتبطة بالنوع" باستخدام الكلمة المفتاحية `_Generic`


```c
#define cbrt(x) _Generic((x), long double: cbrtl, \
                              default: cbrt, \
                              float: cbrtf)(x)
```


## انظر أيضًا
* تعددية الأشكال

## المراجع

## المصادر

* 
* 
* 
* 
* 

## قراءة إضافية
* Gabriel Dos Reis و Jaakko Järvi، *[https://www.elegantcoding.com/2012/04/what-is-generic-programming.html ما هي البرمجة العامة؟]*، LCSD 2005 .
* 
* 

## الوصلات الخارجية
* generic-programming.org
* Alexander A. Stepanov، مجموعة أوراق ألكسندر أ. ستبانوف (مؤسس مكتبة القوالب المعيارية)

;سي++, دي
* Walter Bright، *[https://www.digitalmars.com/d/templates-revisited.html القوالب المعاد النظر فيها].*
* David Vandevoorde، Nicolai M Josuttis، *قوالب C++: الدليل الكامل*، 2003 Addison-Wesley. 

;سي#, .نيت
* Jason Clark، "تقديم القوالب في CLR الخاص بشركة Microsoft"، سبتمبر 2003، *مجلة MSDN*، Microsoft.
* Jason Clark، "المزيد عن القوالب في CLR الخاص بشركة Microsoft"، أكتوبر 2003، *مجلة MSDN*، Microsoft.
* M. Aamir Maniar، Generics.Net. مكتبة قوالب مفتوحة المصدر لـ C#.

;دلفي، أوبجكت باسكال
* 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

;هاسكل
* Johan Jeuring، Sean Leather، José Pedro Magalhães، وAlexey Rodriguez Yakushev. ''المكتبات للبرمجة العامة في هاسكل''. جامعة أوترخت.
* Dæv Clarke، Johan Jeuring وAndres Löh، دليل المستخدم لـ Generic Haskell
* Ralf Hinze، "القوالب من أجل الجميع"، في *إجراءات [[جمعية آلات الحوسبة]] [[SIGPLAN]] [[المؤتمر الدولي للبرمجة الوظيفية]] (ICFP)،* 2004.
* سيمون بيتن جونز، محرر، *[https://haskell.org/onlinereport/index.html تقرير لغة هاسكل 98]*، المنقح 2002.
* Ralf Lämmel وسيمون بيتن جونز، "تخلص من الرتابة: نمط تصميم عملي للبرمجة العامة"، في *إجراءات ورشة العمل الدولية لـ [[جمعية آلات الحوسبة]] [[SIGPLAN]] حول الأنواع في تصميم وتنفيذ اللغات (TLDI'03)،* 2003. (انظر أيضًا الموقع المخصص لهذا البحث)
* Andres Löh، *[https://web.archive.org/web/20050404015900/https://www.cs.uu.nl/~andres/ExploringGH.pdf استكشاف Generic Haskell]*, أطروحة دكتوراه، 2004 جامعة أترخت. 
* Generic Haskell: لغة للبرمجة العامة

;جافا
* Gilad Bracha، *[https://www.oracle.com/technetwork/java/javase/generics-tutorial-159168.pdf القوالب في لغة البرمجة جافا]*, 2004.
* Maurice Naftalin و Philip Wadler، *Java Generics and Collections*، 2006، O'Reilly Media, Inc. 
* Peter Sestoft، *Java Precisely, الطبعة الثانية*، 2005 MIT Press. 
* ، 2004 Sun Microsystems, Inc.
* Angelika Langer، أسئلة شائعة حول قوالب جافا

*
تصنيف:مقارنة بين لغات البرمجة