Ընդհանրացված ծրագրավորում

**Ընդհանրացված ծրագրավորումը** (անգլ.՝ generic programming) ծրագրավորման պարադիգմ է, որը բաղկացած է տվյալների և ալգորիթմների նկարագրությունից, որոնք կարող են կիրառվել տարբեր տեսակի տվյալների վրա՝ առանց այդ նկարագրությունը փոխելու։ Այն այս կամ այն ​​ձևով աջակցվում է  տարբեր ծրագրավորման լեզուներով: Ընդհանրացված ծրագրավորման հնարավորությունները առաջին անգամ հայտնվեցին ջեներիկների(ընդհանրացված ֆունկցիաների) տեսքով 1970-ականներին Clu-ում և Ada-ում, այնուհետև պարամետրային պոլիմորֆիզմի տեսքով ML-ում և նրա հետնորդներում, այնուհետև շատ օբյեկտ կողմնորոշված լեզուներում, ինչպիսիք են C++, Python, Java, Object Pascal, D, Eiffel, լեզուներ .NET պլատֆորմի համար և այլն:

## Մեթոդաբանություն
Ընդհանրացված ծրագրավորումը դիտարկվում է որպես ծրագրավորման մեթոդաբանություն, որը հիմնված է տվյալների կառուցվածքների և ալգորիթմների տարանջատման վրա՝ պահանջների աբստրակտ նկարագրությունների կիրառմամբ: Աբստրակտ պահանջների նկարագրությունները աբստրակտ տվյալների տիպի հասկացության ընդլայնումն են: Մեկ տեսակ նկարագրելու փոխարեն ընդհանրացված ծրագրավորման մեջ օգտագործվում է տիպերի ընտանիքի նկարագրությունը, որոնք ունեն ընդհանուր ինտերֆեյս և իմաստային վարքագիծ ()։ Պահանջների ամբողջությունը, որոնք նկարագրում են ինտերֆեյսը և իմաստային վարքագիծը, կոչվում է կոնցեպցիա (): Այսպիսով, ընդհանրացված ոճով գրված ալգորիթմը կարող է օգտագործվել ցանկացած տիպի համար։ Այդպիսի հատկանիշը կոչվում է պոլիմորֆիզմ։

Ասում են, որ տիպը մոդելավորում է կոնցեպցիան (կոնցեպցիայի մոդել է), եթե այն բավարարում է դրա պահանջներին: Կոնցեպցիանը մեկ այլ կոնցեպցիայի հստակեցումն է, եթե այն լրացնում է վերջինս: Կոնցեպցիայի պահանջները պարունակում են հետևյալ տեղեկությունները

* Թույլատրելի արտահայտությունները () ծրագրավորման լեզուների արտահայտություններ են, որոնք պետք է հաջողությամբ կոմպիլյացվեն կոնցեպցիան մոդելավորող տիպերի համար:
* Ասոցիացված տիպեր (associated types) օժանդակ տիպեր են, որոնք որոշակի կապ ունեն կոնցեպցիան մոդելավորող տիպի հետ:
* Ինվարիանտները() տիպերի բնութագրիչներ են, որոնք միշտ պետք է ճշմարիտ լինեն կատարման ժամանակ: Սովորաբար արտահայտվում է նախապայմանների և հետպայմանների տեսքով։ Նախապայմանին չբավարարելը հանգեցնում է համապատասխան գործողության անկանխատեսելիության և կարող է հանգեցնել սխալների:
* Բարդության երաշխիքներ() թույլատրելի արտահայտության առավելագույն կատարման ժամանակն է

C++ լեզվում օբյեկտ կողմնորոշված ծրագրավորումը (ՕԿԾ) իրականացվում է վիրտուալ ֆունկցիաների և ժառանգման միջոցով, մինչդեռ ընդհանրացված ծրագրավորումը իրականացվում է դասի շաբլոնների և ֆունկցիաների միջոցով: Այնուամենայնիվ, երկու մեթոդաբանությունների էությունը միայն անուղղակիորեն է կապված կոնկրետ իրականացման տեխնոլոգիաների հետ: ՕԿԾ-ն հիմնված է ենթատիպային պոլիմորֆիզմի վրա, մինչդեռ ընդհանրացված ծրագրավորումը հիմնված է պարամետրային պոլիմորֆիզմի վրա: Այլ լեզուներում երկուսն էլ կարող են այլ կերպ իրականացվել: Օրինակ, CLOS-ում մուլտիմեթոդներն ունեն պարամետրային պոլիմորֆիզմի նման իմաստ։

Մասերը և Ստեպանովը առանձնացնում են ընդհանրացված ծրագրավորման մեթոդաբանության խնդրի լուծման հետևյալ փուլերը:

# Գտնել օգտակար և արդյունավետ ալգորիթմ:
# Սահմանել ընդհանրացված ներկայացում (պարամետրացնել ալգորիթմը ՝ նվազագույնի հասցնելով մշակվող տվյալների պահանջները:
# Նկարագրել մի շարք (նվազագույն) պահանջներ, որոնք բավարարելով, դուք դեռ կարող եք ստանալ արդյունավետ ալգորիթմներ:
# Ստեղծեք շրջանակ՝ հիմնված դասակարգված պահանջների վրա:

Նվազագույնի հասցնելը և շրջանակի ստեղծումը նպատակ ունեն ստեղծել այնպիսի կառուցվածք, որում ալգորիթմները կախված չեն տվյալների հատուկ տիպերից:Այս մոտեցումը արտացոլված է STL գրադարանի կառուցվածքում։

Ընդհանրացված ծրագրավորման սահմանման այլընտրանքային մոտեցում  է՝ տվյալների տիպի ընդհանրացված ծրագրավորումը (անգլ. *datatype generic programming*), որն առաջարկվել է Ռիչարդ Բիրդի և Լամբերտ Մերտենսի կողմից։ Դրանում տվյալների տիպի կառուցվածքները ընդհանրացված ծրագրերի պարամետրեր են: Դրա համար ծրագրավորման լեզվում ներդրվում է աբստրակցիայի նոր մակարդակ, այն է՝ պարամետրացում՝ կապված փոփոխականի գրելաձևով հանրահաշվական դասերի հետ։ Թեև երկու մոտեցումների տեսությունները կախված չեն ծրագրավորման լեզվից, Մասեր-Ստեպանովի մոտեցումը, որը շեշտը դնում է կոնցեպցիայի վերլուծության վրա, C++ ծրագրավորման լեզուն դարձրել է իր հիմնական հարթակը, մինչդեռ ընդհանրացված տվյալների տիպի ծրագրավորումն օգտագործում է գրեթե բացառապես Haskell-ը և դրա տարբերակները։

## Ընդհանուր մեխանիզմ
Ընդհանրացված ծրագրավորման գործիքներն իրականացվում են ծրագրավորման լեզուներում որոշակի շարահյուսական միջոցների տեսքով, որոնք հնարավորություն են տալիս նկարագրել տվյալները(տվյալների տեսակները) և ալգորիթմները (կոնցեպցիաներ, ֆունկցիաներ, մեթոդներ), որոնք պարամետրացվում են տվյալների տիպերի կողմից: Ֆունկցիան կամ տվյալների տիպը հստակ նկարագրում են ֆորմալ պարամետրերը՝ տիպերը: Այս նկարագրությունը ընդհանրացված է և չի կարող ուղղակիորեն օգտագործվել իր սկզբնական տեսքով:

Ծրագրի այն վայրերում, որտեղ օգտագործվում է ընդհանրացված տիպը կամ ֆունկցիան, ծրագրավորողը պետք է հստակ նշի իրական պարամետրը՝ նկարագրությունը բնութագրող տիպը: Օրինակ, երկու արժեքների վերադասավորման ընդհանրացված ֆունկցիան կարող է ունենալ պարամետր-տիպ, որը սահմանում է այն արժեքների տիպը, որը  այն փոխում է: Երբ ծրագրավորողը պետք է փոխի երկու ամբողջ արժեք, նա կանչում է «ամբողջ թիվ» տիպի պարամետրով ֆունկցիան և երկու պարամետրով՝ ամբողջ թվեր, երբ երկու տող՝  «տող» տիպի պարամետրով և երկու պարամետրով՝ տողերով: Տվյալների դեպքում ծրագրավորողը կարող է, օրինակ, նկարագրել «ցուցակ» ընդհանրացված տեսակը՝ տիպ պարամետրով, որը սահմանում է ցուցակում պահվող արժեքների տիպը: Այնուհետև իրական ցուցակները նկարագրելիս ծրագրավորողը պետք է նշի ընդհանրացված տիպը և պարամետր-տեսակը ՝ այդպիսով ստանալով ցանկացած ցանկալի ցուցակ ՝ օգտագործելով նույն նկարագրությունը:

Կոմպիլյատորը, հանդիպելով ընդհանրացված տիպին կամ ֆունկցիայի կանչին, կատարում է ստատիկ տիպի ստուգման անհրաժեշտ վերահսկողությունները, գնահատում է տվյալի կոնկրետացման հնարավորությունը և դրական գնահատման դեպքում գեներացնում է կոդ՝ փոխարինելով իրական տիպի պարամետրը ֆորմալ տիպի պարամետրին ընդհանրացված նկարագրության մեջ: Բնականաբար, ընդհանրացված նկարագրությունները հաջողությամբ օգտագործելու համար պետք է իրական պարամետրերի տիպերը բավարարեն որոշակի պայմաններին: Եթե ​​ընդհանրացված ֆունկցիան համեմատում է պարամետրի տիպի արժեքները, ապա դրա մեջ օգտագործվող ցանկացած տիպ պետք է աջակցի համեմատման ​​գործողություններին, եթե այն վերագրում է պարամետր-տիպի արժեքները փոփոխականներին, այն պետք է իրականացնի ճիշտ վերագրում:

## Ընդհանրացված ծրագրավորումը լեզուներում
### C++
C++ լեզվում ընդհանրացված ծրագրավորումը հիմնված է «շաբլոն» հասկացողության վրա, որը սկսվում է **template** բանալի բառով։  Լայնորեն կիրառվում է C++ շաբլոնների ստանդարտ գրադարանում, ինչպես նաև կողմնակի boost, Loki գրադարաններում։ Ալեքսանդր Ստեպանովը մեծ ներդրում ունեցավ C++ ծրագրավորման լեզվում ընդհանրացված ծրագրավորման զարգացման գործում։

Որպես օրինակ՝ բերենք ֆունկցիայի շաբլոն (ընդհանրացում), որը վերադարձնում է երկու արժեքներից մեծագույնը։

```cpp
// Շաբլոն ֆունկցիայի նկարագրություն
template <typename T> T max(T x, T y)
{
    if (x < y)
        return y;
    else
        return x;
}
...
// Շաբլոնով տրված ֆունկցիայի կիրառում

int a = max(10,15);
...
double f = max(123.11, 123.12);
...
```
կամ կապակցված ցուցակի դասի շաբլոն (ընդհանրացում).
```c++
template <class T>
 class List
 {
 /* ... */
 public:
   void Add( const T& Element );
   bool Find( const T& Element );
 /* ... */
 };
```


### Haskell
Haskell լեզուն ապահովում է տվյալների տիպերի ընդհանրացված ծրագրավորում: Հետևյալ օրինակում a-ն պարամետրային տիպի փոփոխական է:


```haskell
data List a = Nil | Cons a (List a)
length :: List a -> Int
length Nil = 0
length (Cons _ tl) = 1 + length tl
```


Հաշվարկի օրինակ․


```haskell
length (Cons 1 (Cons 2 Nil)) == 2
```


### Java
Java-ն տրամադրում է ընդհանրացված ծրագրավորման գործիքներ, որոնք շարահյուսորեն հիմնված են C++ լեզվի վրա՝ սկսած J2SE 5.0 տարբերակից։  Այս լեզվում կան **generics** կամ «T տիպի կոնտեյներներ»՝ ընդհանրացված ծրագրավորման ենթաբազմություն։

### .NET
. Net պլատֆորմում ընդհանրացված ծրագրավորման գործիքները հայտնվել են 2.0 տարբերակում։

```csharp
// Ընդհանրացված դասի հայտարարում
 public class GenericList<T>
 {
     void Add(T input) { }
 }
 class TestGenericList
 {
     private class ExampleClass { }
     static void Main()
     {
         GenericList<int> list1 = new GenericList<int>();
         GenericList<string> list2 = new GenericList<string>();
         GenericList<ExampleClass> list3 = new GenericList<ExampleClass>();
     }
 }
```


### Օրինակ [[C Sharp|C# լեզվում]]

```csharp
interface IPerson 
{
  string GetFirstName();
  string GetLastName();
}

class Speaker 
{
  public void SpeakTo<T>(T person) where T : IPerson 
  {
    string name = person.GetFirstName();
    this.say("Hello, " + name);
  }
}
```


### D
D լեզվի շաբլոնների վրա հիմնված ռեկուրսիվ գեներացիայի օրինակ.


```d
// http://digitalmars.com/d/2.0/template.html
template Foo(T, R...) // T - тип, R - набор типов
{
    void Foo(T t, R r)
    {
	writeln(t);
	static if (r.length)	// if more arguments
	    Foo(r);		// do the rest of the arguments
    }
}

void main()
{
    Foo(1, 'a', 6.8);
}

/+++++++++++++++
 prints:
 1
 a
 6.8
 +++++++++++++++/
```


### Object Pascal
Free Pascal կոմպիլյատորում ընդհանրացված ծրագրավորման աջակցությունը հայտնվել է 2007 թվականի 2.2 տարբերակից սկսած: Դելֆիում՝ 2008 թվականի հոկտեմբերից։ Ընդհանրացված դասի աջակցությունն առաջին անգամ հայտնվեց Delphi 2007 .NET-ում 2006 թվականին, բայց այն ազդեց միայն .NET Framework-ի վրա: Ավելի ամբողջական աջակցություն  ընդհանրացված ծրագրավորմանը ավելացվել է  Delphi 2009-ում։ Ընդհանրացված դասերը նույնպես աջակցվում են Object Pascal-ում PascalABC.NET համակարգում:

### Nim

```nim
import typetraits

proc getType[T](x: T): string =
  return x.type.name

echo getType(21)       # կարտածի int
echo getType(21.12)    # կարտածի float64
echo getType("string") # կարտածի string
```


## Ծանոթագրություններ

## Հղումներ
* generic-programming.org 
* Gabriel Dos Reis and Jaakko Järvi, ''What is Generic Programming?
* Обобщённое программирование в Delphi

## Գրականություն
* 
* 

Կատեգորիա:Ծրագրավորում
Կատեգորիա:Ծրագրեր ըստ տեսակի