البرمجة العامة

البرمجة العامة هي أسلوب من أساليب برمجة الكمبيوتر حيث يتم كتابة الخوارزميات من حيث أنواع البيانات التي سيتم تحديدها لاحقًا والتي يتم إنشاؤها عند الحاجة لأنواع معينة يتم توفيرها كمعلمات . هذا النهج، الذي ابتكرته لغة برمجة التعلم الآلي في عام 1973، [1] [2] يسمح بكتابة وظائف أو أنواع مشتركة تختلف فقط في مجموعة الأنواع التي تعمل عليها عند استخدامها، وبالتالي تقليل الكود المكرر .

تم تقديم البرمجة العامة إلى التيار الرئيسي مع Ada في عام 1977. مع القوالب في C++ ، أصبحت البرمجة العامة جزءًا من ذخيرة تصميم المكتبات الاحترافية. تم تحسين التقنيات بشكل أكبر وتم تقديم الأنواع المعلمة في كتاب Design Patterns المؤثر لعام 1994. [3]

تم تقديم تقنيات جديدة بواسطة Andrei Alexandrescu في كتابه Modern C++ Design: Generic Programming and Design Patterns Applied الصادر عام 2001. بعد ذلك، قامت D بتنفيذ نفس الأفكار.

تُعرف مثل هذه الكيانات البرمجية باسم الكيانات العامة في Ada و C# و Delphi و Eiffel و F# و Java و Nim و Python و Go و Rust و Swift و TypeScript و Visual Basic .NET . وتُعرف أيضًا باسم تعدد الأشكال البارامترية في ML و Scala و Julia و Haskell . (تستخدم مصطلحات Haskell أيضًا مصطلح "عام" لمفهوم ذي صلة ولكنه مختلف إلى حد ما.)

تم صياغة مصطلح البرمجة العامة في الأصل بواسطة ديفيد موسر وألكسندر ستيبانوف [4] بمعنى أكثر تحديدًا من المعنى المذكور أعلاه، لوصف نموذج برمجة يتم فيه تجريد المتطلبات الأساسية لأنواع البيانات من أمثلة ملموسة من الخوارزميات وهياكل البيانات ورسميتها كمفاهيم ، مع تنفيذ وظائف عامة من حيث هذه المفاهيم، عادةً باستخدام آليات عمومية اللغة كما هو موضح أعلاه.

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

تم تعريف البرمجة العامة في Musser & Stepanov (1989) على النحو التالي،

تدور البرمجة العامة حول فكرة التجريد من الخوارزميات الملموسة والفعالة للحصول على خوارزميات عامة يمكن دمجها مع تمثيلات بيانات مختلفة لإنتاج مجموعة واسعة من البرامج المفيدة.

—  Musser, David R.; Stepanov, Alexander A., ​​البرمجة العامة [5]

نموذج "البرمجة العامة" هو نهج لتحليل البرمجيات حيث يتم تجريد المتطلبات الأساسية للأنواع من أمثلة ملموسة من الخوارزميات وهياكل البيانات وإضفاء الطابع الرسمي عليها كمفاهيم ، على نحو مماثل لتجريد النظريات الجبرية في الجبر المجرد . [6] تم تنفيذ الأمثلة المبكرة لهذا النهج البرمجي في Scheme وAda، [7] على الرغم من أن المثال الأكثر شهرة هو مكتبة القالب القياسي (STL)، [8] [9] التي طورت نظرية التكرارات التي تُستخدم لفصل هياكل بيانات التسلسل والخوارزميات العاملة عليها.

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

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

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

—  ألكسندر ستيبانوف، تاريخ موجز لـ STL [11] [12]

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

—  ألكسندر ستيبانوف، مقابلة مع أ. ستيبانوف [13]

وأشار بيارني ستروستروب ،

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

—  Bjarne Stroustrup، تطوير لغة في العالم الحقيقي ومن أجله: C++ 1991-2006 [12]

تشمل أنماط البرمجة الأخرى التي تم وصفها بالبرمجة العامة البرمجة العامة لنوع البيانات كما هو موضح في "البرمجة العامة - مقدمة". [14] إن نهج Scrap your boilerplate هو نهج برمجة عامة خفيف الوزن لـ Haskell. [15]

في هذه المقالة، نميز بين أنماط البرمجة عالية المستوى للبرمجة العامة ، أعلاه، وآليات البرمجة العامة في لغات البرمجة منخفضة المستوى المستخدمة لتنفيذها (انظر دعم لغات البرمجة للبرمجة العامة). لمزيد من المناقشة والمقارنة بين أنماط البرمجة العامة، انظر. [16]

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

كانت مرافق العمومية موجودة في اللغات عالية المستوى منذ سبعينيات القرن العشرين على الأقل في لغات مثل ML و CLU و Ada ، وتم تبنيها لاحقًا من قبل العديد من اللغات القائمة على الكائنات والموجهة للكائنات ، بما في ذلك BETA و C++ و D و Eiffel و Java و Trellis-Owl التابعة لـ DEC والتي لم تعد موجودة الآن .

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

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

فيما يلي دراسة استقصائية واسعة النطاق لآليات التعميم في لغات البرمجة. لمراجعة محددة لمقارنة مدى ملاءمة الآليات للبرمجة العامة، انظر [17]

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

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

قالب < اسم النوع T > class List { // محتويات الفصل. }; 
  
  


قائمة < حيوان > قائمة_الحيوانات ؛ قائمة < سيارة > قائمة_السيارات ؛ 
 

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


// "&" يشير إلى قالب مرجعي < 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++ ولكن بتركيب نحوي مبسط. قدمت لغة البرمجة Java تسهيلات عامة نحويًا استنادًا إلى C++ منذ تقديم Java Platform, Standard Edition (J2SE) 5.0.

تحتوي لغات C# 2.0 و Oxygene 1.5 (Chrome سابقًا) و Visual Basic .NET 2005 على هياكل تستغل الدعم للأنواع العامة الموجودة في Microsoft .NET Framework منذ الإصدار 2.0.

الجنيسات في آدا

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

الوحدة العامة هي حزمة أو برنامج فرعي يأخذ معلمة رسمية عامة واحدة أو أكثر . [18]

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

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

مثال

مواصفات الحزمة العامة:

 عام 
    Max_Size  :  طبيعي ؛ --  نوع قيمة رسمي عام 
    Element_Type خاص ؛ -- نوع رسمي عام؛ يقبل أي حزمة نوع غير محدودة Stacks هو نوع Size_Type هو نطاق 0 .. Max_Size ؛ نوع Stack محدود خاص ؛ إجراء Create ( S : خارج Stack ؛ Initial_Size : في Size_Type := Max_Size إجراء Push ( Into : في خارج Stack ؛ Element : في Element_Type إجراء Pop ( From : في خارج Stack ؛ Element : خارج Element_Type Overflow : استثناء ؛ Underflow : استثناء ؛ نوع فرعي خاص Index_Type هو نطاق Size_Type 1 .. Max_Size ؛ نوع Vector هو مصفوفة ( نطاق Index_Type <>) من Element_Type ؛ نوع Stack ( Allocated_Size : Size_Type : = 0 ) هو سجل Top : Index_Type ؛ التخزين : Vector ( 1 .. Allocated_Size نهاية السجل ؛ نهاية Stacks ؛    
   
          
        
        
                          
            
            
      
      
 
           
            
           
         
            
    
  

إنشاء الحزمة العامة:

 نوع  Bookmark_Type  هو  طبيعي جديد  ؛ -- يسجل موقعًا في مستند النص الذي نقوم بتحريره
 

 الحزمة  Bookmark_Stacks  هي حزمة جديدة  من Stacks  ( Max_Size  => 20 ، 
                                        Element_Type  => Bookmark_Type 
 -- تسمح للمستخدم بالانتقال بين المواقع المسجلة في المستند

استخدام مثيل للحزمة العامة:

 نوع  Document_Type  هو  سجل 
    المحتويات  :  Ada.Strings.Unbounded.Unbounded_String ؛ الإشارات المرجعية : Bookmark_Stacks.Stack ؛ نهاية السجل ؛
      
 

 إجراء  تحرير  ( اسم المستند  : في  سلسلة )  هو 
   المستند  :  نوع المستند ؛ 
 البداية 
   - تهيئة كومة الإشارات المرجعية: 
   Bookmark_Stacks . إنشاء  ( S  =>  Document . Bookmarks ،  Initial_Size  =>  10 
   - الآن، افتح الملف Document_Name واقرأه في... 
 النهاية  تحرير ؛
المزايا والحدود

يسمح بناء الجملة اللغوية بتحديد دقيق للقيود المفروضة على المعلمات الرسمية العامة. على سبيل المثال، من الممكن تحديد أن النوع الرسمي العام سيقبل فقط نوعًا معياريًا كنوع فعلي. ومن الممكن أيضًا التعبير عن القيود بين المعلمات الرسمية العامة؛ على سبيل المثال:

 
    النوع  العام Index_Type  هو  (<>);  -- يجب أن يكون نوع منفصل. 
    نوع Element_Type خاص ؛  --  يمكن  أن يكون أي نوع غير محدود. نوع Array_Type هو مصفوفة ( نطاق Index_Type <>) من Element_Type ؛ 
            

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

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

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

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

القوالب في C++

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

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

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

قالب < اسم النوع T > T max ( T x ، T y ) { return x < y ؟ y : x ؛ } 
     
         

يمكن استدعاء التخصصات الخاصة بقالب الوظيفة هذا، والتمثيلات ذات الأنواع المحددة، تمامًا مثل الوظيفة العادية:

std :: cout << max ( 3 , 7 ); // مخرجات 7.     

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

int max ( int x ، int y ) { إرجاع x < y ؟ y : x ؛ }     
         

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

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

يمتد نوع آخر من القوالب، وهو قالب الفئة، إلى نفس المفهوم ليشمل الفئات. ويتخصص قالب الفئة في فئة. وغالبًا ما تُستخدم قوالب الفئة لإنشاء حاويات عامة. على سبيل المثال، تحتوي STL على حاوية قائمة مرتبطة . لإنشاء قائمة مرتبطة من الأعداد الصحيحة، يكتب المرء list<int>. ويرمز إلى قائمة السلاسل list<string>. تحتوي A listعلى مجموعة من الوظائف القياسية المرتبطة بها، والتي تعمل مع أي أنواع معلمات متوافقة.

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

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

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

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

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

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

#حدد الحد الأقصى (أ، ب) ((أ) < (ب)؟ (ب) : (أ))

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

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

هناك أربعة عيوب أساسية لاستخدام القوالب: الميزات المدعومة، ودعم المترجم، ورسائل الخطأ الرديئة (عادةً مع SFINAE قبل C++20 )، وتضخم الكود :

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

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

    —  Bjarne Stroustrup ، تصميم وتطور لغة C++، 1994 [20]
  5. قد تتطلب الفئات أو الوظائف النمطية تخصصًا صريحًا لفئة القالب، وهو ما يتطلب إعادة كتابة فئة بأكملها لمعلمات قالب محددة تستخدمها.

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

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

القوالب في D

تدعم لغة D القوالب المستندة إلى التصميم على لغة C++. تعمل معظم عبارات قوالب لغة C++ في لغة D دون أي تعديل، ولكن لغة D تضيف بعض الوظائف:

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

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

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

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 ; // يمكن الحصول على مقدمة النطاق })) ; } 

        
       
    
                
             
             
            
    

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

متعة تلقائية ( المدى ) ( المدى المدى ) إذا ( isInputRange ! Range ) { // ... }  
     

    

توليد الكود

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

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

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

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

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

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

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

التعددية في ايفل

كانت الفئات العامة جزءًا من لغة إيفل منذ التصميم الأصلي للطريقة واللغة. تستخدم المنشورات التأسيسية لـ إيفل، [22] [23] مصطلح العمومية لوصف إنشاء الفئات العامة واستخدامها.

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

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

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

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

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

    list_of_deposits : LIST [ DEPOSIT ] -- قائمة الإيداع  
            

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

عمومية مقيدة

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

الفئة 
SORTED_LIST [ G -> COMPARABLE ]       

الأنواع العامة في جافا

تمت إضافة دعم الكائنات العامة أو "حاويات النوع T" إلى لغة برمجة Java في عام 2004 كجزء من J2SE 5.0. في Java، يتم فحص الكائنات العامة فقط في وقت التجميع للتأكد من صحتها. ثم تتم إزالة معلومات النوع العام عبر عملية تسمى محو النوع ، للحفاظ على التوافق مع تطبيقات JVM القديمة ، مما يجعلها غير متاحة في وقت التشغيل. [24] على سبيل المثال، يتم تحويل a List<String>إلى النوع الخام List. يقوم المترجم بإدراج تحويلات النوع لتحويل العناصر إلى Stringالنوع عند استردادها من القائمة، مما يقلل الأداء مقارنة بالتطبيقات الأخرى مثل قوالب C++.

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

تمت إضافة الأنواع العامة كجزء من .NET Framework 2.0 في نوفمبر 2005، استنادًا إلى نموذج أولي بحثي من Microsoft Research بدأ في عام 1999. [25] على الرغم من تشابهها مع الأنواع العامة في Java، فإن الأنواع العامة في .NET لا تطبق محو النوع ، [26] : 208–209  ولكنها تنفذ الأنواع العامة كآلية من الدرجة الأولى في وقت التشغيل باستخدام التجسيد . يوفر اختيار التصميم هذا وظائف إضافية، مثل السماح بالانعكاس مع الحفاظ على الأنواع العامة، وتخفيف بعض حدود المحو (مثل عدم القدرة على إنشاء مصفوفات عامة). [27] [28] وهذا يعني أيضًا أنه لا يوجد تأثير على الأداء من عمليات الإرسال في وقت التشغيل وتحويلات الصناديق المكلفة عادةً . عند استخدام الأنواع البدائية وأنواع القيمة كحجج عامة، فإنها تحصل على تنفيذات متخصصة، مما يسمح بمجموعات وطرق عامة فعالة. كما هو الحال في C++ وJava، فإن الأنواع العامة المتداخلة مثل Dictionary<string, List<int>> هي أنواع صالحة، ومع ذلك ينصح بتجنبها لتوقيعات الأعضاء في قواعد تصميم تحليل الكود. [29]

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

استخدام النظام ؛ 

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

    void ثابت MakeAtLeast < T > ( قائمة T [] ، T الأدنى ) حيث T : IComparable < T >         
    {
        بالنسبة إلى ( int i = 0 ؛ i < list . Length ؛ i ++ )        
            إذا ( القائمة [ i ]. قارن بـ ( الأدنى ) < 0 )   
                القائمة [ i ] = الأدنى ؛  
    }
}

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

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

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

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

        // عضو بيانات 
خاص 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 = جديد GenTest < int > ( 1 ); GenTest < int > g11 = جديد GenTest < int > ( 11 ); GenTest < int > g111 = جديد GenTest < int > ( 111 ); GenTest < double > g2 = جديد GenTest < double > ( 1.0 );    
    
    
    

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

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

عينة البرنامج ؛ 

{$APPTYPE وحدة التحكم}

يستخدم 
Generics . الإعدادات الافتراضية ; //لـ IComparer<>   

نوع 
TUtils = فئة فئة الإجراء MakeAtLeast < T > ( Arr : TArray < T ثابت أدنى : T ؛ Comparer : IComparer < T > ) ؛ التحميل الزائد ؛ فئة الإجراء MakeAtLeast < T > ( Arr : TArray < T ثابت أدنى : T ) ؛ التحميل الزائد ؛ النهاية ؛    
          
        
           
  

إجراء الفئة 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 ;      
   

   

         
        
         
        


إجراء الفئة 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#: أي نوع قيمة، أي فئة، فئة أو واجهة محددة، وفئة مع منشئ بدون معلمات. تعمل القيود المتعددة كاتحاد إضافي.

العمومية في Free Pascal

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

مثال على Delphi و Free Pascal:


// وحدة نمط دلفي أ ؛ 

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


واجهة

نوع 
TGenericClass < T > = class function Foo ( const AValue : T ) : T ; نهاية ;    
        
  

تطبيق

دالة TGenericClass < T >. Foo ( const AValue : T ) : T ؛ البداية النتيجة := AValue + AValue ؛ النهاية ؛    

      


نهاية .


// وحدة نمط ObjFPC في Free Pascal B ؛ 

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


واجهة

النوع 
العام TGenericClass < T > = class function Foo ( const AValue : T ) : T ; end ;     
        
  

تطبيق

دالة TGenericClass.Foo ( const AValue : T ) : T ؛ البداية النتيجة : = AValue + AValue ؛ النهاية ؛    

      


نهاية .

// مثال للاستخدام، 
برنامج نمط دلفي TestGenDelphi ؛ 

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


يستخدم 
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 TestGenDelphi ؛ 

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


يستخدم 
A و B ؛  


// مطلوب في نوع 
ObjFPC 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 .     
     

   
   

    
    
   
   
  
  

اللغات الوظيفية

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

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

البيانات BinTree a = Leaf a | Node ( BinTree a ) a ( BinTree a ) مشتقة ( Eq , Show )            
        

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

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

بولي بي

كانت PolyP أول امتداد للغة برمجة عامة لـ Haskell . في PolyP، تسمى الوظائف العامة polytypic . تقدم اللغة بنية خاصة يمكن من خلالها تعريف مثل هذه الوظائف متعددة الأنواع من خلال الاستدلال الهيكلي على بنية دالة النمط لنوع بيانات عادي. تعد أنواع البيانات العادية في PolyP مجموعة فرعية من أنواع بيانات Haskell. يجب أن يكون نوع البيانات العادي t من النوع * → * ، وإذا كانت a هي وسيطة النوع الرسمي في التعريف، فيجب أن يكون لجميع الاستدعاءات المتكررة لـ t الشكل ta . تستبعد هذه القيود أنواع البيانات ذات النوع الأعلى وأنواع البيانات المتداخلة، حيث تكون الاستدعاءات المتكررة من شكل مختلف. يتم توفير دالة التسوية في PolyP هنا كمثال:

   تسطيح :: عادي d => d a -> [ a ] ​​تسطيح = cata fl        
      

   متعدد الأنماط fl :: f a [ a ] ​​-> [ a ] ​​حالة f من g + h -> إما 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 -> []       
       
           
               
           
           
           
              
            

   كاتا :: منتظم d => ( FunctorOf d a b -> b ) -> d a -> b               
هاسكل العامة

Generic Haskell هو امتداد آخر لـ Haskell ، تم تطويره في جامعة أوتريخت في هولندا . الامتدادات التي يوفرها هي:

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

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

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

على سبيل المثال، دالة المساواة في Generic Haskell: [31]

   النوع معادلة {[ * ]} t1 t2 = t1 -> t2 -> Bool النوع معادلة {[ k -> l ]} t1 t2 = لجميع u1 u2 . المعادلة {[ k ]} u1 u2 -> المعادلة {[ l ]} ( t1 u1 ) ( t2 u2 )            
                              

   eq { | t :: k | } :: Eq {[ k ]} t t eq { | Unit | } _ _ = 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 { | Int | } = ( == ) eq { | Char | } = ( == ) eq { | Bool | } = ( == )            
          
                
                
            
                      
        
        
        

ينظف

يقدم Clean برمجة عامة تعتمد على PolyP وGeneric Haskell كما يدعمها GHC ≥ 6.0. كما أنه يحدد المعلمات حسب النوع مثل تلك، ولكنه يوفر التحميل الزائد.

لغات أخرى

تدعم اللغات في عائلة ML البرمجة العامة من خلال تعدد الأشكال البارامترية والوحدات النمطية العامة التي تسمى الدوال. توفر كل من Standard ML و OCaml دوالًا تشبه قوالب الفئات والحزم العامة في Ada. ترتبط التجريدات النحوية للمخططات أيضًا بالتعميم - وهي في الواقع مجموعة فرعية من قوالب C++.

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

نظرًا لأن VHDL مشتقة من Ada، فإنها تتمتع أيضًا بقدرات عامة. [33]

يدعم C "التعبيرات العامة للنوع" باستخدام الكلمة _Genericالأساسية: [34]

#define cbrt(x) _Generic((x)، طويل مزدوج: cbrtl، \ 
                              الافتراضي: cbrt، \ 
                              float: cbrtf)(x)

انظر أيضا

مراجع

  1. ^ لي، كينت د. (15 ديسمبر 2008). لغات البرمجة: نهج التعلم النشط. سبرينغر ساينس آند بيزنس ميديا. ص 9-10. رقم ISBN  978-0-387-79422-8.
  2. ^ ميلنر، ر.؛ موريس، ل.؛ نيوي، م. (1975). "منطق الوظائف القابلة للحساب ذات الأنواع الانعكاسية والمتعددة الأشكال". وقائع مؤتمر إثبات وتحسين البرامج .
  3. ^ جاما، إيريش؛ هيلم، ريتشارد؛ جونسون، رالف؛ فليسيدس، جون (1994). أنماط التصميم . أديسون ويسلي. رقم ISBN  0-201-63361-2.
  4. ^ موسر و ستيبانوف 1989.
  5. ^ موسر، ديفيد ر.؛ ستيبانوف، ألكسندر أ. البرمجة العامة (PDF) .
  6. ^ ألكسندر ستيبانوف؛ بول ماكجونز (19 يونيو 2009). عناصر البرمجة . أديسون ويسلي بروفيشنال. ISBN 978-0-321-63537-2.
  7. ^ Musser, David R.; Stepanov, Alexander A. (1987). "A library of generic algorithms in Ada". Proceedings of the 1987 Annual ACM SIGAda international conference on Ada - SIGAda '87 . ص 216-225. CiteSeerX 10.1.1.588.7431 . doi :10.1145/317500.317529. ISBN  0897912438. S2CID  795406.
  8. ^ ألكسندر ستيبانوف ومينج لي: مكتبة القوالب القياسية. تقرير فني من HP Laboratories 95-11(R.1)، 14 نوفمبر 1995
  9. ^ ماثيو إتش أوسترن: البرمجة العامة وSTL: استخدام مكتبة القوالب القياسية C++ وتوسيعها. شركة أديسون ويسلي لونجمان للنشر، بوسطن، ماساتشوستس، الولايات المتحدة الأمريكية 1998
  10. ^ جيريمي جي سيك، لي كوان لي، أندرو لومسدين: مكتبة Boost Graph: دليل المستخدم ودليل مرجعي. أديسون ويسلي 2001
  11. ^ ستيبانوف، ألكسندر. تاريخ موجز لـ STL (PDF) .
  12. ^ ab Stroustrup, Bjarne. تطوير لغة في العالم الحقيقي ومن أجله: C++ 1991-2006 (PDF) . doi :10.1145/1238844.1238848. S2CID  7518369.
  13. ^ لو روسو، جرازيانو. "مقابلة مع أ. ستيبانوف".
  14. ^ البيت الخلفي ، رولاند. يانسون، باتريك؛ جيرنج، يوهان؛ ميرتنز، لامبرت (1999). البرمجة العامة – مقدمة (PDF) .
  15. ^ Lämmel, Ralf; Peyton Jones, Simon (January 2003). "Scrap Your Boilerplate: A Practical Design Pattern for Generic Programming" (PDF) . Microsoft . تم الاسترجاع في 16 أكتوبر 2016 .
  16. ^ Dos Reis, Gabriel; Järvi, Jaakko (2005). "ما هي البرمجة العامة؟ (طبعة أولية LCSD'05)" (PDF) . مؤرشف من الأصل (PDF) في 25 ديسمبر 2005.
  17. ^ R. Garcia; J. Järvi; A. Lumsdaine; J. Siek; J. Willcock (2005). "دراسة مقارنة موسعة لدعم اللغة للبرمجة العامة (نسخة أولية)". CiteSeerX 10.1.1.110.122 . 
  18. ^ "الوحدات العامة". www.adaic.org . تم الاسترجاع في 25 أبريل 2024 .
  19. ^ Stroustrup, Dos Reis (2003): المفاهيم - اختيارات التصميم للتحقق من وسيطة القالب
  20. ^ Stroustrup, Bjarne (1994). "15.5 Avoiding Code Replication". The Design and Evolution of C++ . Reading, Massachusetts: Addison-Wesley. pp. 346–348. Bibcode :1994dec..book.....S. ISBN 978-81-317-1608-3.
  21. ^ برايت، والتر. "أنواع فولدمورت في د". دكتور دوبس . تم الاسترجاع في 3 يونيو 2015 .
  22. ^ بناء البرمجيات الموجهة للكائنات، برنتيس هول، 1988، وبناء البرمجيات الموجهة للكائنات، الطبعة الثانية، برنتيس هول، 1997.
  23. ^ إيفل: اللغة، برنتيس هول، 1991.
  24. ^ Bloch 2018، ص 126، البند 28: تفضيل القوائم على المصفوفات.
  25. ^ تاريخ Generics .NET/C#: بعض الصور من فبراير 1999
  26. ^ البحري 2022.
  27. ^ C#: الأمس واليوم وغدًا: مقابلة مع أندرس هيلسبيرج
  28. ^ Generics في C# وJava وC++
  29. ^ تحليل الكود CA1006: لا تقم بتضمين الأنواع العامة في توقيعات الأعضاء
  30. ^ القيود المفروضة على معلمات النوع (دليل برمجة C#)
  31. ^ دليل المستخدم العام لـ Haskell
  32. ^ Verilog by Example, Section The Rest for Reference . Blaine C. Readler, Full Arc Press, 2011. ISBN 978-0-9834973-0-1 
  33. ^ https://www.ics.uci.edu/~jmoorkan/vhdlref/generics.html مرجع VHDL
  34. ^ مسودة لجنة WG14 N1516 — 4 أكتوبر 2010

مصادر

  • البحاري، يوسف (2022). C # 10 باختصار (الطبعة الأولى). أورايلي. رقم ISBN 978-1-098-12195-2.
  • بلوخ، جوشوا (2018). "جافا الفعّالة: دليل لغة البرمجة" (الطبعة الثالثة). أديسون ويسلي. رقم ISBN 978-0134685991.
  • Musser, DR ; Stepanov, AA (1989). "Generic programming". في P. Gianni (محرر). Symbolic and Algebraic Computation: International symposium ISSAC 1988. Lecture Notes in Computer Science. المجلد 358. ص. 13-25. doi :10.1007/3-540-51084-2_2. ISBN 978-3-540-51084-0.
  • Stroustrup, Bjarne (2007). تطوير لغة في العالم الحقيقي ومن أجله: C++ 1991-2006 (PDF) . ACM HOPL 2007.
  • جاما، إيريش؛ هيلم، ريتشارد؛ جونسون، رالف؛ فليسيدس، جون (1994). أنماط التصميم: عناصر البرمجيات الموجهة للكائنات القابلة لإعادة الاستخدام . أديسون ويسلي. رمز الكتاب : 1995dper.book.....G. ISBN 0-201-63361-2.

قراءة إضافية

  • غابرييل دوس ريس وجاكو جارفي، ما هي البرمجة العامة؟، LCSD 2005، أرشيف 28 أغسطس 2019 على موقع واي باك مشين .
  • جيبونز، جيريمي (2007). باكهاوس، ر.؛ جيبونز، ج.؛ هينز، ر.؛ جيورينج، ج. (المحررون). البرمجة حسب نوع البيانات . مدرسة الربيع للبرمجة حسب نوع البيانات 2006. مذكرات محاضرات في علوم الكمبيوتر. المجلد 4719. هايدلبرغ: سبرينغر. ص 1-71. CiteSeerX  10.1.1.159.1228 .
  • ماير، برتراند (1986). "التعميم مقابل الوراثة". وقائع مؤتمر حول أنظمة البرمجة الموجهة للكائنات واللغات والتطبيقات - OOPSLA '86 . ص 391-405. doi :10.1145/28697.28738. ISBN 0897912047. S2CID  285030.
  • generic-programming.org
  • ألكسندر أ. ستيبانوف، مجموعة أوراق ألكسندر أ. ستيبانوف (مؤسس مكتبة سانت لويس )
سي++، دي
  • والتر برايت، إعادة النظر في القوالب.
  • ديفيد فانديفورد، نيكولاي إم جوسوتيس، قوالب C++: الدليل الكامل ، 2003 أديسون ويسلي. ISBN 0-201-73484-2 
سي شارب، .نت
  • جيسون كلارك، "إدخال المصطلحات العامة في Microsoft CLR"، سبتمبر 2003، مجلة MSDN ، مايكروسوفت.
  • جيسون كلارك، "المزيد عن المنتجات العامة في Microsoft CLR"، أكتوبر 2003، مجلة MSDN ، مايكروسوفت.
  • السيد عامر مانيار، Generics.Net. مكتبة مفتوحة المصدر للبرمجيات العامة للغة C#.
دلفي، أوبجيكت باسكال
  • نيك هودجز، "دليل المراجعين لـDelphi 2009"، أكتوبر 2008، شبكة مطوري Embarcadero ، Embarcadero.
  • كريج ستونتز، "الأنواع العامة وقيود النوع في دلفي 2009"، أكتوبر 2008
  • دكتور بوب، "Delphi 2009 Generics"
  • Free Pascal : دليل مرجعي لبرنامج Free Pascal الفصل 8: Generics، مايكل فان كانيت، 2007
  • Delphi لنظام التشغيل Win32: Generics مع Delphi 2009 Win32، Sébastien DOERAENE، 2008
  • Delphi لـ .NET: Delphi Generics، Felix COLIBRI، 2008
ايفل
  • وثيقة مواصفات ايفل ISO/ECMA
هاسكل
  • يوهان جيورينج، وشون ليذر، وخوسيه بيدرو ماجالهايس، وأليكسي رودريجيز ياكوشيف. مكتبات البرمجة العامة في هاسكل. جامعة أوتريخت.
  • ديف كلارك، يوهان جيورينج وأندريس لوه، دليل المستخدم العام لـ Haskell
  • رالف هينز، "المصطلحات العامة للجماهير"، في وقائع مؤتمر ACM SIGPLAN الدولي حول البرمجة الوظيفية (ICFP)، 2004.
  • سيمون بيتون جونز ، محرر تقرير لغة هاسكل 98، المنقح عام 2002.
  • رالف لاميل وسايمون بيتون جونز ، "التخلص من القالب: نمط تصميم عملي للبرمجة العامة"، في وقائع ورشة عمل ACM SIGPLAN الدولية حول الأنواع في تصميم اللغة وتنفيذها (TLDI'03)، 2003. (انظر أيضًا الموقع الإلكتروني المخصص لهذا البحث)
  • أندريس لوه، استكشاف لغة هاسكل العامة، أطروحة دكتوراه، جامعة أوتريخت 2004. ISBN 90-393-3765-9 
  • Generic Haskell: لغة للبرمجة العامة
جافا
  • جيلاد براخا، الكائنات العامة في لغة البرمجة جافا، 2004.
  • موريس نفتالين وفيليب وادلر، Java Generics and Collections، 2006، O'Reilly Media, Inc. ISBN 0-596-52775-6 
  • بيتر سيستوفت، Java Precisely، الطبعة الثانية، 2005 MIT Press. ISBN 0-262-69325-9 
  • البرمجة العامة في جافا، 2004 Sun Microsystems, Inc.
  • أنجيليكا لانجر، الأسئلة الشائعة حول Java Generics
Retrieved from "https://en.wikipedia.org/w/index.php?title=Generic_programming&oldid=1241725683#Template_specialization"
Original text
Rate this translation
Your feedback will be used to help improve Google Translate