Из Википедии, бесплатной энциклопедии
Перейти к навигации Перейти к поиску

Обобщенное программирование - это стиль компьютерного программирования, в котором алгоритмы записываются в терминах типов, которые будут определены позже , которые затем создаются, когда это необходимо для определенных типов, предоставленных в качестве параметров . Этот подход, впервые примененный в языке программирования ML в 1973 году [1] [2], позволяет писать общие функции или типы, которые отличаются только набором типов, с которыми они работают при использовании, тем самым уменьшая дублирование . Такие программные объекты известны как дженерики в Ada , C #., Delphi , Eiffel , F # , Java , Nim , Python , Rust , Swift , TypeScript и Visual Basic .NET . Они известны как параметрический полиморфизм в ML , Scala , Julia и Haskell (сообщество Haskell также использует термин «общий» для родственной, но несколько иной концепции); шаблоны на C ++ и D ; и параметризованные типы во влиятельной книге 1994 г.Шаблоны проектирования . [3]

Термин «общее программирование» был первоначально введен Дэвидом Массером и Александром Степановым [4] в более конкретном смысле, чем приведенный выше, для описания парадигмы программирования, посредством которой фундаментальные требования к типам абстрагируются от конкретных примеров алгоритмов и структур данных и формализуются. как концепции , с универсальными функциями, реализованными в терминах этих концепций, обычно с использованием механизмов универсальности языка, как описано выше.

Степанов – Массер и другие общие парадигмы программирования [ править ]

Общее программирование определяется в Musser & Stepanov (1989) следующим образом:

В основе универсального программирования лежит идея абстрагирования от конкретных эффективных алгоритмов для получения универсальных алгоритмов, которые можно комбинировать с различными представлениями данных для создания широкого спектра полезного программного обеспечения.

-  Мюссер, Дэвид Р .; Степанов, Александр А., Общее программирование [5]

Парадигма «общего программирования» - это подход к декомпозиции программного обеспечения, при котором фундаментальные требования к типам абстрагируются от конкретных примеров алгоритмов и структур данных и формализуются как концепции , аналогично абстракции алгебраических теорий в абстрактной алгебре . [6] Ранние примеры этого подхода к программированию были реализованы в Scheme и Ada, [7] хотя наиболее известным примером является Стандартная библиотека шаблонов (STL), [8] [9], которая разработала теорию итераторов, которая используется для разделения структуры данных последовательности и алгоритмы, работающие с ними.

Например, учитывая N структур данных последовательностей, например, односвязный список, вектор и т. Д., И M алгоритмов для работы с ними, например find, sortи т. Д., Прямой подход будет реализовывать каждый алгоритм специально для каждой структуры данных, давая N × M комбинаций для осуществлять. Однако в универсальном подходе к программированию каждая структура данных возвращает модель концепции итератора (простой тип значения, который можно разыменовать, чтобы получить текущее значение, или изменить, чтобы указать на другое значение в последовательности), и вместо этого записывается каждый алгоритм обычно с аргументами таких итераторов, например парой итераторов, указывающих на начало и конец подпоследовательности или диапазонаобрабатывать. Таким образом, необходимо реализовать только N + M комбинаций структура данных-алгоритм. В STL указано несколько концепций итераторов, каждая из которых представляет собой уточнение более ограничительных концепций, например, прямые итераторы обеспечивают перемещение только к следующему значению в последовательности (например, подходит для односвязного списка или потока входных данных), тогда как случайный доступ iterator также обеспечивает прямой постоянный доступ к любому элементу последовательности (например, подходящему для вектора). Важным моментом является то, что структура данных будет возвращать модель самой общей концепции, которая может быть эффективно реализована, - вычислительной сложности.требования явным образом являются частью определения концепции. Это ограничивает структуры данных, к которым может применяться данный алгоритм, и такие требования к сложности являются основным фактором, определяющим выбор структуры данных. Обобщенное программирование аналогично применялось и в других областях, например, в алгоритмах графов. [10]

Обратите внимание, что хотя этот подход часто использует языковые особенности универсальности / шаблонов времени компиляции , на самом деле он не зависит от конкретных технических деталей языка. Пионер универсального программирования Александр Степанов писал:

Общее программирование - это абстрагирование и классификация алгоритмов и структур данных. Он черпает вдохновение из Кнута, а не из теории типов. Его цель - постепенное создание систематических каталогов полезных, эффективных и абстрактных алгоритмов и структур данных. Такое начинание пока остается мечтой.

-  Александр Степанов, Краткая история STL [11] [12]

Я считаю, что теории итераторов так же важны для информатики, как теории колец или банаховых пространств - для математики.

-  Александр Степанов, Интервью с А. Степановым [13]

Бьярне Страуструп отметил:

Следуя Степанову, мы можем определять обобщенное программирование, не упоминая особенности языка: поднимать алгоритмы и структуры данных от конкретных примеров до их наиболее общей и абстрактной формы.

-  Бьярн Страуструп, Развитие языка в реальном мире и для него: C ++ 1991-2006 [12]

Другие парадигмы программирования, которые были описаны как универсальное программирование, включают универсальное программирование типа данных, как описано в разделе «Общее программирование - введение». [14] Подход « Избавьтесь от своего шаблона» - это облегченный общий подход к программированию для Haskell. [15]

В этой статье мы отделяем вышеприведенные парадигмы универсального программирования высокого уровня от механизмов универсальности языка программирования нижнего уровня, используемых для их реализации (см. Раздел «Поддержка универсального языка программирования» ). Для дальнейшего обсуждения и сравнения общих парадигм программирования см. [16]

Поддержка языка программирования для универсальности [ править ]

Средства универсальности существовали в языках высокого уровня по крайней мере с 1970-х годов в таких языках, как ML , CLU и Ada , и впоследствии были приняты многими объектно-ориентированными и объектно-ориентированными языками, включая BETA , C ++ , D , Eiffel , Java , и ныне несуществующий язык DEC Trellis-Owl .

Универсальность реализована и поддерживается по-разному на разных языках программирования; термин «общий» также по-разному использовался в различных контекстах программирования. Например, в Forth компилятор может выполнить код при компиляции и можно создавать новые ключевые слова , компилятор и новые реализации для этих слов на лету. В нем есть несколько слов, которые раскрывают поведение компилятора и поэтому, естественно, предлагает возможности универсальности, которые, однако, не упоминаются как таковые в большинстве текстов Forth. Точно так же языки с динамической типизацией, особенно интерпретируемые, обычно предлагают универсальность.по умолчанию, поскольку и передача значений функциям, и присвоение значений не зависят от типа, и такое поведение часто используется для абстракции или краткости кода, однако это обычно не называют универсальностью, поскольку это прямое следствие системы динамической типизации, используемой языком. [ необходима цитата ] Этот термин использовался в функциональном программировании , особенно в языках типа Haskell , в которых используется система структурных типов, в которой типы всегда параметрически, а фактический код этих типов является универсальным. Эти способы использования по-прежнему служат одной и той же цели сохранения кода и визуализации абстракции.

Массивы и структуры можно рассматривать как предопределенные универсальные типы. Каждое использование типа массива или структуры создает экземпляр нового конкретного типа или повторно использует ранее созданный тип. Типы элементов массива и типы элементов структуры являются параметризованными типами, которые используются для создания экземпляра соответствующего универсального типа. Все это обычно встроено в компилятор, а синтаксис отличается от других универсальных конструкций. Некоторые расширяемые языки программирования пытаются унифицировать встроенные и определяемые пользователем универсальные типы.

Далее следует широкий обзор механизмов универсальности в языках программирования. Для конкретного обзора, сравнивающего пригодность механизмов для универсального программирования, см. [17]

В объектно-ориентированных языках [ править ]

При создании контейнерных классов на статически типизированных языках неудобно писать конкретные реализации для каждого содержащегося типа данных, особенно если код для каждого типа данных практически идентичен. Например, в C ++ это дублирование кода можно обойти, определив шаблон класса:

template  < typename  T > class  List  {  // Содержимое класса. };Список < Животное >  list_of_animals ; Список < Автомобиль >  list_of_cars ;

Выше T- заполнитель для любого типа, указанного при создании списка. Эти «контейнеры типа T», обычно называемые шаблонами , позволяют повторно использовать класс с разными типами данных, пока сохраняются определенные контракты, такие как подтипы и подпись . Этот механизм универсальности не следует путать с полиморфизмом включения , который представляет собой алгоритмическое использование заменяемых подклассов: например, список объектов типа, Moving_Objectсодержащий объекты типа Animalи Car. Шаблоны также можно использовать для функций, не зависящих от типа, как в Swapпримере ниже:

// "&" передает параметры по ссылочному шаблону  < typename  T > void  Swap ( T &  a ,  T &  b )  {  T  temp  =  b ;  б  =  а ;  а  =  темп ; }std :: string  hello  =  "Мир!" ; std :: string  world  =  "Привет," ; Своп ( мир ,  привет ); std :: cout  <<  привет  <<  мир  <<  std :: endl ;  // Вывод - «Hello, World!».

Конструкция C ++, templateиспользованная выше, широко цитируется [ необходима цитата ] как конструкция универсальности, которая популяризовала это понятие среди программистов и разработчиков языков и поддерживает множество общих идиом программирования. Язык программирования D также предлагает полностью универсальные шаблоны, основанные на прецеденте C ++, но с упрощенным синтаксисом. С момента появления J2SE 5.0 язык программирования Java предоставляет средства универсальности, синтаксически основанные на C ++ .

В C # 2.0, Oxygene 1.5 (также известном как Chrome) и Visual Basic .NET 2005 есть конструкции, которые используют преимущества поддержки универсальных шаблонов, присутствующих в Microsoft .NET Framework начиная с версии 2.0.

Дженерики в Аде [ править ]

У Ады есть дженерики с момента его первой разработки в 1977–1980 годах. Стандартная библиотека использует универсальные шаблоны для предоставления множества услуг. В Ada 2005 к стандартной библиотеке добавлена ​​обширная универсальная библиотека контейнеров, вдохновленная стандартной библиотекой шаблонов C ++ .

Общий блок представляет собой пакет или подпрограмма , которая принимает один или более общие формальные параметры .

Общий формальный параметр представляет собой значение, переменная, константа, тип, подпрограмма, или даже экземпляр других, обозначенный, общий блок. Для универсальных формальных типов в синтаксисе различаются дискретные типы, типы с плавающей запятой, с фиксированной запятой, типы доступа (указатели) и т. Д. Некоторые формальные параметры могут иметь значения по умолчанию.

Чтобы создать экземпляр универсального модуля, программист передает фактические параметры для каждого формального элемента . В этом случае общий экземпляр ведет себя так же, как и любой другой модуль. Можно создать экземпляры универсальных модулей во время выполнения , например, внутри цикла.

Пример [ править ]

Спецификация универсального пакета:

 общий  Max_Size  :  Natural ;  - общий  тип  формального значения Element_Type  является  частным ;  - общий формальный тип; принимает любой неограниченный  пакет  типа Stacks  - это  тип  Size_Type  -  диапазон  0  ..  Max_Size ;  типа  Stack  является  ограниченным  частным ;  Процедура  Создание  ( S  : из  стека ;  Initial_Size  : в  size_type  : =  max_size );  процедура Нажмите  ( Into  : в  из  стека ;  элемент  : в  ELEMENT_TYPE );  процедура  Pop  ( From  : in  out  Stack ;  Element  : out  Element_Type );  Переполнение  :  исключение ;  Незаполнение  :  исключение ;  частный  подтип  Index_Type  -  Size_Type  диапазон  1  ..  Max_Size ;  тип  Vector  - это  массив ( Диапазон Index_Type  <>) из Element_Type ; type Stack ( Allocated_Size : Size_Type : = 0 ) - это запись Top : Index_Type ; Память : Вектор ( 1 .. Allocated_Size ); конец записи ; конец стеки ;                       

Создание экземпляра универсального пакета:

 тип  Bookmark_Type  является  новым  природным ;  - записывает местоположение в текстовом документе, который мы редактируем пакет  Bookmark_Stacks  - это новые  стеки  ( Max_Size  => 20 ,  Element_Type  => Bookmark_Type );  - Позволяет пользователю переключаться между записанными местоположениями в документе.

Используя экземпляр универсального пакета:

 Тип  Document_Type  - это  запись  Содержание  :  Ada . Струны . Безграничный . Unbounded_String ;  Закладки  :  Bookmark_Stacks . Стек ;  конец записи ;  Редактировать  процедуру ( Document_Name  : in  String )  -  Document  :  Document_Type ;  begin  - Инициализировать стопку закладок:  Bookmark_Stacks . Создать  ( S  =>  Документ . Закладки ,  Initial_Size  =>  10 );  - Теперь откройте файл Document_Name и прочтите его ...  end  Edit ;
Преимущества и ограничения [ править ]

Синтаксис языка позволяет точно определять ограничения на общие формальные параметры. Например, можно указать, что общий формальный тип будет принимать только модульный тип в качестве фактического. Также возможно выразить ограничения между универсальными формальными параметрами; Например:

 универсальный  тип  Index_Type  -  (<>);  - должен быть дискретного  типа.  Element_Type  является  частным ;  - может быть любым nonlimited типа  типа  array_type  является  массив  ( Index_Type  диапазоном  <>)  из  ELEMENT_TYPE ;

В этом примере Array_Type ограничен как Index_Type, так и Element_Type. При создании экземпляра модуля программист должен передать фактический тип массива, который удовлетворяет этим ограничениям.

Недостатком этого детализированного элемента управления является сложный синтаксис, но, поскольку все общие формальные параметры полностью определены в спецификации, компилятор может создавать экземпляры универсальных шаблонов, не глядя на тело универсального.

В отличие от C ++, Ada не позволяет использовать специализированные универсальные экземпляры и требует, чтобы все универсальные экземпляры создавались явно. Эти правила имеют несколько последствий:

  • компилятор может реализовывать общие универсальные шаблоны : объектный код универсального модуля может использоваться всеми экземплярами (если, конечно, программист не требует встраивания подпрограмм). В качестве дальнейших последствий:
    • нет возможности раздувания кода (раздувание кода распространено в C ++ и требует особой осторожности, как описано ниже).
    • можно создавать экземпляры универсальных шаблонов во время выполнения, а также во время компиляции, поскольку для нового экземпляра не требуется новый объектный код.
    • фактические объекты, соответствующие универсальному формальному объекту, всегда считаются нестатическими внутри универсального; подробности и последствия см. в общих формальных объектах в Викиучебнике.
  • все экземпляры универсального кода абсолютно одинаковы, поэтому легче просматривать и понимать программы, написанные другими; нет никаких «особых случаев», которые нужно принимать во внимание.
  • все экземпляры являются явными, нет скрытых экземпляров, которые могли бы затруднить понимание программы.
  • Ада не допускает «метапрограммирования шаблонов», потому что не допускает специализаций.

Шаблоны на C ++ [ править ]

C ++ использует шаблоны для включения общих методов программирования. Стандартная библиотека C ++ включает стандартную библиотеку шаблонов или STL, которая предоставляет структуру шаблонов для общих структур данных и алгоритмов. Шаблоны в C ++ также могут использоваться для метапрограммирования шаблонов , что является способом предварительной оценки некоторой части кода во время компиляции, а не во время выполнения . Используя специализацию шаблонов, шаблоны C ++ считаются завершенными по Тьюрингу .

Технический обзор [ править ]

Есть два типа шаблонов: шаблоны функций и шаблоны классов. Шаблон функции является шаблоном для создания обычных функций , основанных на типах параметрирования , поставляемых , когда экземпляр. Например, Стандартная библиотека шаблонов C ++ содержит шаблон функции, max(x, y)который создает функции, возвращающие либо x, либо y, в зависимости от того , что больше. max()можно определить так:

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

Специализации этого шаблона функции, экземпляры с определенными типами, могут вызываться как обычная функция:

std :: cout  <<  max ( 3 ,  7 );  // Выводит 7.

Компилятор проверяет аргументы, используемые для вызова, maxи определяет, что это вызов max(int, int). Затем он конкретизирует версию функции , когда тип параметрирования Tявляется int, что делает эквивалент следующей функции:

int  max ( int  x ,  int  y )  {  return  x  <  y  ?  у  :  х ; }

Это работает независимо от того, являются ли аргументы xи yцелыми числами, строками или любым другим типом, для которого выражение x < yявляется разумным, или, более конкретно, для любого типа, для которого operator<определено. Общее наследование не требуется для набора типов, которые можно использовать, и поэтому оно очень похоже на утиную типизацию . Программа, определяющая пользовательский тип данных, может использовать перегрузку оператора для определения значения <этого типа, что позволяет использовать его с max()шаблоном функции. Хотя в этом изолированном примере это может показаться незначительным преимуществом, в контексте всеобъемлющей библиотеки, такой как STL, он позволяет программисту получить обширную функциональность для нового типа данных, просто определив для него несколько операторов. Просто определение<позволяет типу , которые будут использоваться со стандартом sort(), stable_sort()и binary_search()алгоритмы или быть помещены внутрь структур данных , такие как setS, отвалы и ассоциативные массивы .

Шаблоны C ++ полностью безопасны по типу во время компиляции. В качестве демонстрации стандартный тип complexне определяет <оператор, потому что нет строгого порядка для комплексных чисел . Следовательно, max(x, y)произойдет сбой с ошибкой компиляции, если x и y являются complexзначениями. Точно так же другие шаблоны, которые полагаются, <не могут быть применены к complexданным, если не предусмотрено сравнение (в форме функтора или функции). Например: A complexнельзя использовать в качестве ключа для a, mapесли не указано сравнение. К сожалению, компиляторы исторически генерируют несколько скрытые, длинные и бесполезные сообщения об ошибках такого рода. Обеспечение соответствия определенного объектапротокол метода может решить эту проблему. Языки, которые используют compareвместо, <также могут использовать complexзначения в качестве ключей.

Второй тип шаблона, шаблон класса, расширяет ту же концепцию на классы. Специализация шаблона класса - это класс. Шаблоны классов часто используются для создания универсальных контейнеров. Например, в STL есть контейнер связанного списка . Чтобы составить связанный список целых чисел, пишут list<int>. Обозначается список строк list<string>. С A listсвязан набор стандартных функций, которые работают с любыми совместимыми типами параметризации.

Специализация шаблона [ править ]

Мощной особенностью шаблонов C ++ является их специализация . Это позволяет предоставлять альтернативные реализации на основе определенных характеристик параметризованного типа, экземпляр которого создается. Специализация шаблонов преследует две цели: разрешить определенные формы оптимизации и уменьшить раздувание кода.

Например, рассмотрим sort()шаблонная функция. Одно из основных действий, выполняемых такой функцией, - это перестановка или обмен значений в двух позициях контейнера. Если значения большие (с точки зрения количества байтов, необходимых для хранения каждого из них), то часто бывает быстрее сначала создать отдельный список указателей на объекты, отсортировать эти указатели, а затем построить окончательную отсортированную последовательность. . Однако, если значения довольно малы, обычно быстрее всего просто поменять местами значения на месте по мере необходимости. Более того, если параметризованный тип уже относится к некоторому типу указателя, тогда нет необходимости создавать отдельный массив указателей. Специализация шаблона позволяет создателю шаблона писать различные реализации и указывать характеристики, которые параметризованные типы должны иметь для каждой используемой реализации.

В отличие от шаблонов функций, шаблоны классов могут быть частично специализированными . Это означает, что может быть предоставлена ​​альтернативная версия кода шаблона класса, когда известны некоторые параметры шаблона, а другие параметры шаблона оставлены общими. Это можно использовать, например, для создания реализации по умолчанию ( первичная специализация ), которая предполагает, что копирование параметризационного типа является дорогостоящим, а затем создает частичные специализации для типов, которые дешево копировать, тем самым повышая общую эффективность. Клиенты такого шаблона класса просто используют его специализации, не зная, использовал ли компилятор первичную специализацию или некоторую частичную специализацию в каждом случае. Шаблоны классов также могут быть полностью специализированными, это означает, что может быть предоставлена ​​альтернативная реализация, когда известны все типы параметризации.

Преимущества и недостатки [ править ]

Некоторые варианты использования шаблонов, например max()функции, ранее были заполнены макросами препроцессора, подобными функциям (наследие языка программирования C ). Например, вот возможный макрос:max()

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

Макросы расширяются препроцессором перед компиляцией; шаблоны раскрываются во время компиляции. Макросы всегда разворачиваются встроенно; шаблоны также могут быть расширены как встроенные функции, когда компилятор сочтет это целесообразным. Таким образом, как макросы, подобные функциям, так и шаблоны функций не имеют накладных расходов во время выполнения.

Однако для этих целей шаблоны обычно считаются улучшением макросов. Шаблоны безопасны по типу. Шаблоны позволяют избежать некоторых распространенных ошибок, обнаруживаемых в коде, который интенсивно использует макросы, подобные функциям, например, двойная оценка параметров с побочными эффектами. Возможно, самое главное, шаблоны были разработаны для решения гораздо более серьезных проблем, чем макросы.

У использования шаблонов есть четыре основных недостатка: поддерживаемые функции, поддержка компилятора, плохие сообщения об ошибках и раздувание кода :

  1. В шаблонах C ++ отсутствуют многие функции, что часто делает невозможным их реализацию и использование простым способом. Вместо этого программистам приходится полагаться на сложные приемы, которые приводят к раздутому, трудному для понимания и сложному в сопровождении коду. Текущие разработки стандартов C ++ усугубляют эту проблему, активно используя эти приемы и создавая множество новых функций для шаблонов на их основе или с их учетом.
  2. Многие компиляторы исторически плохо поддерживают шаблоны, поэтому использование шаблонов может сделать код менее переносимым. Поддержка также может быть плохой, когда компилятор C ++ используется с компоновщиком , не поддерживающим C ++, или при попытке использовать шаблоны через границы разделяемой библиотеки . Однако большинство современных компиляторов теперь имеют довольно надежную и стандартную поддержку шаблонов, а новый стандарт C ++ , C ++ 11 , дополнительно решает эти проблемы.
  3. Почти все компиляторы выдают запутанные, длинные или иногда бесполезные сообщения об ошибках при обнаружении ошибок в коде, использующем шаблоны. [18] Это может затруднить разработку шаблонов.
  4. Наконец, использование шаблонов требует, чтобы компилятор создавал отдельный экземпляр шаблонного класса или функции для каждой перестановки параметров типа, используемых с ним. (Это необходимо, потому что типы в C ++ не имеют одинакового размера, а размеры полей данных важны для того, как работают классы.) Таким образом, неизбирательное использование шаблонов может привести к раздуванию кода , что приведет к чрезмерно большим исполняемым файлам. Однако разумное использование специализации и деривации шаблонов может в некоторых случаях значительно уменьшить такой раздувание кода:

Итак, можно ли использовать деривацию для уменьшения проблемы репликации кода из-за использования шаблонов? Это потребует создания шаблона из обычного класса. Этот метод оказался успешным в сдерживании раздувания кода при реальном использовании. Люди, не использующие подобную технику, обнаружили, что реплицированный код может стоить мегабайты кодового пространства даже в программах среднего размера.

-  Бьярн Страуструп , Дизайн и эволюция C ++, 1994 [19]

Дополнительные экземпляры, сгенерированные шаблонами, также могут вызвать затруднения при правильной работе отладчиков с шаблонами. Например, установка точки останова отладки в шаблоне из исходного файла может либо пропустить установку точки останова в фактическом желаемом экземпляре, либо может установить точку останова в каждом месте, где создается экземпляр шаблона.

Кроме того, поскольку компилятору необходимо выполнять макроподобные расширения шаблонов и генерировать различные их экземпляры во время компиляции, исходный код реализации для шаблонного класса или функции должен быть доступен (например, включен в заголовок) для кода, использующего его. Шаблонные классы или функции, включая большую часть стандартной библиотеки шаблонов (STL), если они не включены в файлы заголовков, не могут быть скомпилированы. (В этом отличие от не шаблонного кода, который может быть скомпилирован в двоичный файл, предоставляя только файл заголовка объявлений для кода, использующего его.) Это может быть недостатком, поскольку раскрывает реализующий код, который удаляет некоторые абстракции и может ограничивать его использование в проектах с закрытым кодом. [ необходима цитата ]

Шаблоны в D [ править ]

Язык программирования D поддерживает шаблоны, основанные на дизайне на C ++. Большинство идиом шаблонов C ++ будут перенесены в D без изменений, но D добавляет некоторые дополнительные функции:

  • Параметры шаблона в D не ограничиваются только типами и примитивными значениями, но также допускают произвольные значения времени компиляции (такие как строки и структурные литералы) и псевдонимы для произвольных идентификаторов, включая другие шаблоны или экземпляры шаблонов.
  • Ограничения шаблона и static ifоператор представляют собой альтернативу механизму подстановки "отказ не является ошибкой" C ++ (SFINAE), аналогичный концепциям C ++ .
  • is(...)Выражение позволяет спекулятивная конкретизации проверить черты объекта во время компиляции.
  • autoКлючевое слово и typeofвыражение позволяет вывод типа для объявления переменных и возвращаемых значений функций, которые , в свою очередь , позволяет «типы Волдеморт» (типы , которые не имеют глобальное имя). [20]

Шаблоны в D использовать другой синтаксис , чем в C ++: в то время как параметры шаблона C ++ обернуты в угловых скобках ( Template<param1, param2>), D использует знак восклицательный и круглые скобки: Template!(param1, param2). Это позволяет избежать трудностей синтаксического анализа C ++ из-за неоднозначности операторов сравнения. Если параметр только один, скобки можно опустить.

Традиционно D объединяет вышеупомянутые функции для обеспечения полиморфизма во время компиляции с использованием универсального программирования на основе признаков. Например, диапазон ввода определяется как любой тип, который удовлетворяет выполняемым проверкам isInputRange, который определяется следующим образом:

Шаблон  isInputRange ( R ) {  перечисление  BOOL  isInputRange  =  это ( TypeOf (  ( INOUT  INT  =  0 )  {  R  г  =  R . инициализации ;  // может определить объект диапазона ,  если  ( т . пустой )  {}  // можно проверить на пустой  г . popFront ();  // может вызывать popFront ()  auto  h  =  r . front ; // можно получить начало диапазона  })); }

Функция, которая принимает только входные диапазоны, может затем использовать указанный выше шаблон в ограничении шаблона:

auto  fun ( Range ) ( Range  range )  if  ( isInputRange ! Range ) {  // ... }
Генерация кода [ править ]

Помимо метапрограммирования шаблонов, D также предоставляет несколько функций, позволяющих генерировать код во время компиляции:

  • importВыражение позволяет считывать файл с диска и использовать его содержимое в виде строкового выражения.
  • Отражение во время компиляции позволяет перечислять и проверять объявления и их члены во время компиляции.
  • Определяемые пользователем атрибуты позволяют пользователям присоединять к объявлениям произвольные идентификаторы, которые затем можно перечислить с помощью отражения во время компиляции.
  • Выполнение функции во время компиляции (CTFE) позволяет интерпретировать подмножество D (ограниченное безопасными операциями) во время компиляции.
  • Строковые миксины позволяют оценивать и компилировать содержимое строкового выражения как D-код, который становится частью программы.

Комбинирование вышеуказанного позволяет сгенерировать код на основе существующих объявлений. Например, платформы сериализации D могут перечислять члены типа и генерировать специализированные функции для каждого сериализованного типа для выполнения сериализации и десериализации. Определяемые пользователем атрибуты могут дополнительно указывать на правила сериализации.

importВыражение и выполнение функции времени компиляций позволяют эффективно реализации языков домена специфических . Например, учитывая функцию, которая принимает строку, содержащую шаблон HTML, и возвращает эквивалентный исходный код D, ее можно использовать следующим образом:

// Импортируем содержимое example.htt как строковую константу манифеста. enum  htmlTemplate  =  import ( "example.htt" );// Транспонируем HTML-шаблон в D-код. перечисление  htmlDCode  =  htmlTemplateToD ( htmlTemplate );// Вставляем содержимое htmlDCode как код D. Mixin ( htmlDCode );

Genericity в Eiffel [ править ]

Общие классы были частью Eiffel с момента создания оригинального метода и языка. В фундаментальных публикациях Eiffel [21] [22] термин универсальность используется для описания создания и использования универсальных классов.

Базовая / неограниченная универсальность [ править ]

Универсальные классы объявляются с их именем и списком из одного или нескольких формальных универсальных параметров . В следующем коде у класса LISTесть один формальный универсальный параметрG

class  LIST  [ G ]  ... feature  -  Элемент доступа :  G  - Элемент, на который в данный момент указывает курсор  ... feature  - Изменение элемента  put  ( new_item :  G )  - Добавить `new_item 'в конец списка  ...

Формальные универсальные параметры являются заполнителями для произвольных имен классов, которые будут предоставлены при объявлении универсального класса, как показано в двух общих производных ниже, где ACCOUNTи DEPOSIT- другие имена классов. ACCOUNTи DEPOSITсчитаются фактическими общими параметрами, поскольку они предоставляют реальные имена классов для замены при Gфактическом использовании.

 list_of_accounts :  LIST  [ ACCOUNT ]  - список учетных записей list_of_deposits :  СПИСОК  [ ДЕПОЗИТ ]  - Список депозитов

В системе типов Эйфеля, хотя класс LIST [G]считается классом, он не считается типом. Однако родовое происхождение LIST [G]таких как LIST [ACCOUNT]считается типом.

Ограниченная универсальность [ править ]

Для класса списка, показанного выше, фактическим универсальным параметром, заменяющим его, Gможет быть любой другой доступный класс. Чтобы ограничить набор классов, из которых могут быть выбраны действительные фактические общие параметры, можно указать общее ограничение . В объявлении класса SORTED_LISTниже общее ограничение диктует, что любой действительный фактический универсальный параметр будет классом, наследуемым от класса COMPARABLE. Общее ограничение гарантирует, что элементы a SORTED_LISTфактически могут быть отсортированы.

класс  SORTED_LIST  [ G  ->  COMPARABLE ]

Дженерики в Java [ править ]

Поддержка универсальных шаблонов или «контейнеров типа T» была добавлена ​​в язык программирования Java в 2004 году как часть J2SE 5.0. В Java универсальные шаблоны проверяются только во время компиляции на правильность типа. Затем информация об общем типе удаляется с помощью процесса, называемого стиранием типа , для обеспечения совместимости со старыми реализациями JVM, что делает его недоступным во время выполнения. Например, a List<String>преобразуется в исходный тип List. Компилятор вставляет приведение типов для преобразования элементов в Stringтип, когда они извлекаются из списка, что снижает производительность по сравнению с другими реализациями, такими как шаблоны C ++.

Универсальность в .NET [C #, VB.NET] [ править ]

Универсальные шаблоны были добавлены как часть .NET Framework 2.0 в ноябре 2005 года на основе исследовательского прототипа Microsoft Research, начатого в 1999 году. [23] Несмотря на то, что универсальные шаблоны в Java похожи на универсальные шаблоны в Java, универсальные шаблоны .NET не применяют стирание типов , а реализуют универсальные шаблоны как первоклассный механизм во время выполнения с использованием реификации . Этот вариант дизайна обеспечивает дополнительные функциональные возможности, такие как разрешение отражения с сохранением универсальных типов, а также устранение некоторых ограничений стирания (например, невозможности создания универсальных массивов). [24] [25] Это также означает, что приведение типов времени выполнения не снижает производительности и обычно требует больших затрат.боксерские конверсии . Когда примитивные типы и типы значений используются в качестве универсальных аргументов, они получают специализированные реализации, позволяющие создавать эффективные универсальные коллекции и методы. Как и в C ++ и Java, вложенные универсальные типы, такие как Dictionary <string, List <int>>, являются допустимыми типами, однако их не рекомендуется использовать для подписей членов в правилах разработки анализа кода. [26]

.NET допускает шесть разновидностей ограничений универсального типа с использованием whereключевого слова, включая ограничение универсальных типов как типов значений, как классов, наличия конструкторов и реализации интерфейсов. [27] Ниже приведен пример ограничения интерфейса:

используя  Систему ;класс  Sample{ статическая  пустота  Main () { int []  массив  =  {  0 ,  1 ,  2 ,  3  }; MakeAtLeast < int > ( массив ,  2 );  // Меняем массив на {2, 2, 2, 3} foreach  ( int  i  в  массиве ) Консоль . WriteLine ( i );  // Распечатать результаты. Консоль . ReadKey ( истина ); } static  void  MakeAtLeast < T > ( T []  список ,  T  самый низкий ),  где  T  :  IComparable < T > { for  ( int  i  =  0 ;  i  <  list . Length ;  i ++) если  ( список [ i ]. CompareTo ( самый низкий )  <  0 ) список [ я ]  =  самый низкий ; }}

MakeAtLeast()Метод позволяет работать с массивами, с элементами универсального типа T. Ограничение типа метода указывает, что метод применим к любому типу T, реализующему универсальный IComparable<T>интерфейс. Это гарантирует ошибку времени компиляции , если метод вызывается, если тип не поддерживает сравнение. Интерфейс предоставляет общий метод CompareTo(T).

Вышеупомянутый метод также можно было бы написать без универсальных типов, просто используя неуниверсальный Arrayтип. Однако, поскольку массивы контравариантны , приведение типов не будет безопасным для типов , и компилятор не сможет найти определенные возможные ошибки, которые в противном случае были бы обнаружены при использовании универсальных типов. Кроме того, методу потребуется доступ к элементам массива как objects, а также потребуется приведение типов для сравнения двух элементов. (Для типов значений , например таких типов, как intэто требует бокс преобразования, хотя это можно обойти , используя Comparer<T>класс, как это делается в стандартных классах коллекции.)

Примечательным поведением статических членов в универсальном классе .NET является создание экземпляров статических членов для каждого типа времени выполнения (см. Пример ниже).

 // Общий класс  public  class  GenTest < T >  {  // Статическая переменная - будет создана для каждого типа при отражении  static  CountedInstances  OnePerType  =  new  CountedInstances (); // член данных  private  T  mT ; // простой конструктор  public  GenTest ( T  pT )  {  mT  =  pT ;  }  } // класс  public  class  CountedInstances  {  // Статическая переменная - она ​​будет увеличиваться один раз для каждого экземпляра  public  static  int  Counter ; // простой конструктор  public  CountedInstances ()  {  // увеличиваем счетчик на единицу во время создания экземпляра объекта  CountedInstances . Счетчик ++;  }  } // точка входа в основной код  // в конце выполнения CountedInstances.Counter = 2  GenTest < int >  g1  =  new  GenTest < int > ( 1 );  GenTest < int >  g11  =  новый  GenTest < int > ( 11 );  GenTest < int >  g111  =  новый  GenTest < int > ( 111 );  GenTest < двойной >  g2  =  новый  GenTest< двойной > ( 1.0 );

Универсальность в Delphi [ править ]

Диалект Delphi Object Pascal приобрел общие черты в выпуске Delphi 2007, первоначально только с компилятором .NET (который сейчас прекращен) перед добавлением в собственный код в выпуске Delphi 2009. Семантика и возможности универсальных шаблонов Delphi в значительной степени смоделированы на основе универсальных шаблонов в .NET 2.0, хотя реализация по необходимости совершенно иная. Вот более или менее прямой перевод первого примера C #, показанного выше:

 образец программы ;{$ КОНСОЛЬ APPTYPE}использует  Generics . По умолчанию ;  // для IComparer <>type  TUtils  =  class  class  procedure  MakeAtLeast < T > ( Arr :  TArray < T >;  const  Lowest :  T ;  Comparer :  IComparer < T > ) ;  перегрузка ;  процедура класса  MakeAtLeast < T > ( Arr : TArray < T >; const Lowest : T ) ; перегрузка      ;  конец ; процедура  класса TUtils . MakeAtLeast < T > ( Arr :  TArray < T >;  const  Lowest :  T ;  Comparer :  IComparer < T > ) ; var  I :  целое число ; начать,  если  Comparer  =  nil,  затем  Comparer  : =  TComparer < T >. По умолчанию ;  для  I  : =  Low ( Arr)  в  высокий ( Arr )  делать,  если  Comparer . Сравните ( Arr [ I ] ,  Lowest )  <  0,  затем  Arr [ I ]  : =  Lowest ; конец ; процедура  класса TUtils . MakeAtLeast < T > ( Arr :  TArray < T >;  const  Lowest :  T ) ; begin  MakeAtLeast < T > ( Arr ,  Lowest ,  nil ) ; конец ;var  Ints :  TArray < Целое число >;  Значение :  целое число ; begin  Ints  : =  TArray < Целое число >. Создать ( 0 ,  1 ,  2 ,  3 ) ;  TUtils . MakeAtLeast < Целое число > ( Интс ,  2 ) ;  для  значения  в  Ints  do  WriteLn ( Value ) ;  ReadLn ; конец.

Как и в C #, методы, а также целые типы могут иметь один или несколько параметров типа. В этом примере TArray является универсальным типом (определяемым языком), а MakeAtLeast - универсальным методом. Доступные ограничения очень похожи на доступные ограничения в C #: любой тип значения, любой класс, определенный класс или интерфейс и класс с конструктором без параметров. Множественные ограничения действуют как аддитивное объединение.

Универсальность в Free Pascal [ править ]

Free Pascal реализовал универсальные шаблоны до Delphi и с другим синтаксисом и семантикой. Однако, начиная с версии 2.6.0 FPC, синтаксис в стиле Delphi доступен при использовании языкового режима {$ mode Delphi}. Таким образом, программисты Free Pascal могут использовать дженерики в любом стиле, который они предпочитают.

Пример Delphi и Free Pascal:

// Единица в  стиле Delphi A ;{$ ifdef fpc}  {$ mode delphi} {$ endif}интерфейстип  TGenericClass < T >  =  функция класса  Foo ( const AValue : T ) : T ; конец ;     выполнениефункция  TGenericClass < T >. Foo ( const  AValue :  T ) :  T ; begin  Результат  : =  AValue  +  AValue ; конец ;конец .// Free Pascal в стиле ObjFPC unit  B ;{$ ifdef fpc}  {$ mode objfpc} {$ endif}интерфейстип  универсального  TGenericClass < T >  =  class  function  Foo ( const  AValue :  T ) :  T ;  конец ;выполнениефункция  TGenericClass . Foo ( const  AValue :  T ) :  T ; begin  Результат  : =  AValue  +  AValue ; конец ;конец .// пример использования, программа в  стиле Delphi TestGenDelphi ;{$ ifdef fpc}  {$ mode delphi} {$ endif}использует  A , B ;вар  GC1 :  . TGenericClass < Целое число >; GC2 : B . TGenericClass < String >; начать GC1 : = A . TGenericClass < Целое число >. Создать ; С2 : = B . TGenericClass < Строка >. Создать ; WriteLn ( GC1 . Foo ( 100 )) ; // 200 WriteLn ( GC2 .           Foo ( 'привет' )) ;  // привет, привет  GC1 . Бесплатно ;  GC2 . Бесплатно ; конец .// пример использования, программа в  стиле ObjFPC TestGenDelphi ;{$ ifdef fpc}  {$ mode objfpc} {$ endif}использует  A , B ;// требуется в ObjFPC типа  TAGenericClassInt  =  специализироваться  A . TGenericClass < Целое число >;  TBGenericClassString  =  специализируется  B . TGenericClass < String >; var  GC1 :  TAGenericClassInt ;  GC2 :  TBGenericClassString ; begin  GC1  : =  TAGenericClassInt . Создать ;  GC2  : =  TBGenericClassString . Создать ;  WriteLn ( GC1. Foo ( 100 )) ;  // 200  WriteLn ( GC2 . Foo ( 'hello' )) ;  // привет, привет  GC1 . Бесплатно ;  GC2 . Бесплатно ; конец .

Функциональные языки [ править ]

Универсальность в Haskell [ править ]

Механизм классов типов в Haskell поддерживает универсальное программирование. Шесть из предопределенных классов типов в Haskell (включая Eqтипы, которые можно сравнивать на равенство, и Showтипы, значения которых могут быть отображены как строки) имеют специальное свойство поддержки производных экземпляров. Это означает, что программист, определяющий новый тип, может заявить, что этот тип должен быть экземпляром одного из этих специальных классов типов, без предоставления реализаций методов класса, которые обычно необходимы при объявлении экземпляров класса. Все необходимые методы будут «производными», то есть построенными автоматически, на основе структуры типа. Например, следующее объявление типа двоичных деревьевзаявляет, что это должен быть экземпляр классов Eqи Show:

data  BinTree  a  =  Leaf  a  |  Узел  ( BinTree  ) ( BinTree ) получения ( Eq , Show )      

Это приводит к тому, что функция равенства ( ==) и функция строкового представления ( show) автоматически определяются для любого типа формы BinTree Tпри условии, что она Tсама поддерживает эти операции.

Поддержка производных экземпляров Eqи Showделает их методы ==и showуниверсальными качественно отличными от параметрически полиморфных функций: эти «функции» (точнее, семейства функций с индексированными типами) могут применяться к значениям различных типов, и хотя они ведут себя по-разному для каждого типа аргумента, требуется небольшая работа, чтобы добавить поддержку нового типа. Ральф Хинце (2004) показал, что подобный эффект может быть достигнут для классов типов, определяемых пользователем, с помощью определенных методов программирования. Другие исследователи предложили подходы к этому и другим видам универсальности в контексте Haskell и расширений Haskell (обсуждаемых ниже).

PolyP [ править ]

PolyP был первым расширением общего языка программирования для Haskell . В PolyP общие функции называются политипическими . В языке представлена ​​специальная конструкция, в которой такие разнотипные функции могут быть определены посредством структурной индукции по структуре функтора шаблона обычного типа данных. Обычные типы данных в PolyP - это подмножество типов данных Haskell. Обычный тип данных t должен иметь вид * → * , и если a является аргументом формального типа в определении, то все рекурсивные вызовы t должны иметь форму ta. Эти ограничения исключают типы данных более высокого порядка, а также вложенные типы данных, где рекурсивные вызовы имеют другую форму. Функция сглаживания в PolyP здесь представлена ​​в качестве примера:

 flatten  ::  Regular  d  =>  d  a  ->  [ a ]  flatten  =  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  .  сплющить  .  pmap  fl  Con  t  ->  \ x  ->  [] cata  ::  Regular  d  =>  ( FunctorOf  d  a  b  ->  b )  ->  d  a  ->  b
Общий Haskell [ править ]

Generic Haskell - это еще одно расширение Haskell , разработанное в Утрехтском университете в Нидерландах . Он предоставляет следующие расширения:

  • Значения с индексированием типа определяются как значение, индексированное по различным конструкторам типов Haskell (единицы измерения, примитивные типы, суммы, продукты и конструкторы определяемых пользователем типов). Кроме того, мы также можем указать поведение значений, индексированных по типу, для конкретного конструктора, используя кейсы конструктора , и повторно использовать одно общее определение в другом, используя кейсы по умолчанию .

Результирующее значение с индексированием типа может быть специализировано для любого типа.

  • Типы с индексированием по типу - это типы, индексированные по типам, определяемые указанием случая для * и k → k ' . Экземпляры получаются путем применения индексированного типа к типу.
  • Общие определения можно использовать, применяя их к типу или виду. Это называется универсальным приложением . Результатом является тип или значение, в зависимости от того, какой тип общего определения применяется.
  • Общая абстракция позволяет определять общие определения путем абстрагирования параметра типа (данного типа).
  • Типы с индексированием типа - это типы, которые индексируются по конструкторам типов. Их можно использовать для присвоения типов более сложных универсальных значений. Результирующие типы с индексированными типами могут быть специализированы для любого типа.

Например, функция равенства в Generic Haskell: [28]

 введите  Eq  {[  *  ]}  t1  t2  =  t1  ->  t2  ->  Тип Bool  Eq {[ k -> l ]} t1 t2 = forall u1 u2 . Eq {[ k ]} u1 u2 -> Eq {[ l ]} ( t1 u1 ) ( t2 u2 )                            eq  { |  t  ::  k  | }  ::  Eq  {[  k  ]}  t  t  eq  { |  Единица  | }  _  _  =  True  eq  { |  : +:  | }  ВОК  eqB  ( Inl  a1 )  ( Inl  а2 )  =  ВКИ  а1  а2  э  { |  : +:  | }  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 и универсальный Haskell, поддерживаемый GHC> = 6.0. Он параметризуется по виду как таковой, но предлагает перегрузку.

Другие языки [ править ]

ML Семейство языков программирования поддержки общего программирования на основе параметрического полиморфизма и общих модулей , называемых функторы. И Standard ML, и OCaml предоставляют функторы, похожие на шаблоны классов и общие пакеты Ada. Синтаксические абстракции схемы также связаны с универсальностью - на самом деле это надмножество шаблонов в стиле C ++.

Модуль Verilog может принимать один или несколько параметров, которым присваиваются их фактические значения при создании экземпляра модуля. Одним из примеров является общий массив регистров, в котором ширина массива задается через параметр. Такой массив в сочетании с универсальным вектором проводов может создать универсальный буфер или модуль памяти с произвольной разрядностью из реализации одного модуля. [29]

VHDL , производный от Ada, также имеет общие возможности.

См. Также [ править ]

  • Концепция (общее программирование)
  • Частичная оценка
  • Метапрограммирование шаблона
  • Полиморфизм типов

Ссылки [ править ]

  1. ^ Ли, Кент Д. (15 декабря 2008 г.). Языки программирования: подход к активному обучению . Springer Science & Business Media. С. 9–10. ISBN 978-0-387-79422-8.
  2. ^ Milner, R .; Morris, L .; Ньюи, М. (1975). «Логика вычислимых функций с рефлексивными и полиморфными типами». Материалы конференции по проверке и совершенствованию программ .
  3. ^ Гамма, Эрих; Хелм, Ричард; Джонсон, Ральф; Влиссидес, Джон (1994). Шаблоны проектирования . Эддисон-Уэсли. ISBN 0-201-63361-2.
  4. ^ Массер & Степанов 1989 .
  5. ^ Musser, Дэвид R .; Степанов, Александр А. Общее программирование (PDF) .
  6. ^ Александр Степанов; Пол МакДжонс (19 июня 2009 г.). Элементы программирования . Эддисон-Уэсли Профессионал. ISBN 978-0-321-63537-2.
  7. ^ Musser, Дэвид R .; Степанов, Александр А. (1987). «Библиотека общих алгоритмов на Аде». Труды Ежегодной Международной конференции ACM SIGAda 1987 по Ада : 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 ++. Addison-Wesley Longman Publishing Co., Inc. Бостон, Массачусетс, США, 1998 г.
  10. ^ Джереми Г. Зик, Ли-Куан Ли, Эндрю Ламсдейн: Библиотека графов ускорения: руководство пользователя и справочное руководство. Эддисон-Уэсли 2001
  11. Степанов, Александр. Краткая история STL (PDF) .
  12. ^ a b Страуструп, Бьярн. Развитие языка в реальном мире и для него: C ++ 1991-2006 (PDF) . DOI : 10.1145 / 1238844.1238848 . S2CID 7518369 .  
  13. ^ Ло Руссо, Грациано. «Интервью с А. Степановым» .
  14. ^ Роланд Бэкхаус; Патрик Янссон; Йохан Джеуринг; Ламберт Меертенс (1999). Общее программирование - введение (PDF) .
  15. ^ Лэммель, Ральф; Пейтон Джонс, Саймон. «Отбросьте шаблонную табличку: практический шаблон проектирования для общего программирования» (PDF) . Microsoft . Проверено 16 октября +2016 .
  16. Габриэль дос Рейс; Яакко Ярви (2005). «Что такое универсальное программирование? (Препринт LCSD'05)» (PDF) . Архивировано из оригинального (PDF) 25 декабря 2005 года.
  17. ^ Р. Гарсия; J. Ja rvi; А. Ламсдайн; Дж. Зик; Дж. Уиллкок (2005). «Расширенное сравнительное исследование языковой поддержки универсального программирования (препринт)». CiteSeerX 10.1.1.110.122 .  Cite journal requires |journal= (help)
  18. ^ Страуструп, Дос Рейс (2003): Концепции - Выбор дизайна для проверки аргументов шаблона
  19. ^ Страуструп, Бьярне (1994). «15.5 Как избежать репликации кода». Дизайн и эволюция C ++ . Ридинг, Массачусетс: Эддисон-Уэсли. С. 346–348. Bibcode : 1994dec..book ..... S . ISBN 978-81-317-1608-3.
  20. Яркий, Уолтер. «Типы Волан-де-Морта в D» . Доктор Доббс . Дата обращения 3 июня 2015 .
  21. ^ Построение объектно-ориентированного программного обеспечения, Prentice Hall, 1988, и Object-Oriented Software Construction, второе издание, Prentice Hall, 1997.
  22. Перейти ↑ Eiffel: The Language, Prentice Hall, 1991.
  23. ^ История .NET / C # Generics: некоторые фотографии с февраля 1999 г.
  24. ^ C #: вчера, сегодня и завтра: интервью с Андерсом Хейлсбергом
  25. ^ Обобщения в C #, Java и C ++
  26. ^ Анализ кода CA1006: не вкладывать универсальные типы в подписи участников
  27. ^ Ограничения для параметров типа (Руководство по программированию на C #)
  28. ^ Руководство пользователя Generic Haskell
  29. ^ Verilog на примере, раздел Остальное для справки . Блейн К. Ридлер, Full Arc Press, 2011. ISBN 978-0-9834973-0-1 

Источники [ править ]

  • Musser, DR ; Степанов, А.А. (1989). «Общее программирование». В П. Джанни (ред.). Символьные и алгебраические вычисления: Международный симпозиум ISSAC 1988 . Конспект лекций по информатике. 358 . С. 13–25. DOI : 10.1007 / 3-540-51084-2_2 . ISBN 978-3-540-51084-0.
  • Страуструп, Бьярн (2007). Развитие языка в реальном мире и для него: C ++ 1991-2006 (PDF) . ACM HOPL 2007.
  • Гамма, Эрих; Хелм, Ричард; Джонсон, Ральф; Влиссидес, Джон (1994). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Эддисон-Уэсли. Bibcode : 1995dper.book ..... G . ISBN 0-201-63361-2.

Дальнейшее чтение [ править ]

  • Габриэль Дос Рейс и Яакко Ярви, Что такое универсальное программирование? , LCSD 2005 .
  • Гиббонс, Джереми (2007). Backhouse, R .; Гиббонс, Дж .; Hinze, R .; Jeuring, J. (ред.). Типовое программирование . Весенняя школа по программированию типов данных 2006. Конспект лекций по информатике. 4719 . Гейдельберг: Springer. С. 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 ++ / D
  • Уолтер Брайт, « Возвращение к шаблонам» .
  • Дэвид Вандевурд, Николай М. Джозаттис, Шаблоны C ++: полное руководство , 2003 г., Эддисон-Уэсли. ISBN 0-201-73484-2 
C # /. NET
  • Джейсон Кларк, « Введение в универсальные шаблоны в Microsoft CLR », сентябрь 2003 г., MSDN Magazine , Microsoft.
  • Джейсон Кларк, « Подробнее об универсальных шаблонах в Microsoft CLR », октябрь 2003 г., MSDN Magazine , Microsoft.
  • М. Аамир Маниар, Generics.Net . Библиотека универсальных шаблонов с открытым исходным кодом для C #.
Delphi / Object Pascal
  • Ник Ходжес, « Руководство обозревателя Delphi 2009 », октябрь 2008 г., Embarcadero Developer Network , Embarcadero.
  • Крейг Стунц, « Обобщения и ограничения типов Delphi 2009 », октябрь 2008 г.
  • Д-р Боб, " Дженерики Delphi 2009 "
  • Free Pascal : Справочное руководство Free Pascal Глава 8: Обобщения , Микаэль Ван Каннейт, 2007 г.
  • Delphi для Win32: Generics с Delphi 2009 Win32 , Sébastien DOERAENE, 2008
  • Delphi для .NET: Generics Delphi , Феликс КОЛИБРИ, 2008 г.
Эйфелева
  • Документ спецификации Eiffel ISO / ECMA
Haskell
  • Йохан Джеуринг, Шон Лезер, Хосе Педро Магальяйнс и Алексей Родригес Якушев. Библиотеки для общего программирования на Haskell . Утрехтский университет.
  • Дав Кларк, Йохан Джеуринг и Андрес Лё, Руководство пользователя Generic Haskell
  • Ральф Хинце, « Обобщения для широких масс », в материалах Международной конференции ACM SIGPLAN по функциональному программированию (ICFP), 2004 г.
  • Саймон Пейтон Джонс , редактор, The Haskell 98 Language Report , Revised 2002.
  • Ральф Лэммель и Саймон Пейтон Джонс , «Scrap Your Boilerplate: A Practical Design Pattern for Generic Programming», в материалах Международного семинара ACM SIGPLAN по типам в дизайне и реализации языков (TLDI'03), 2003 г. (См. Также посвященный веб-сайт к этому исследованию )
  • Андрес Лё, Изучение универсального Haskell , докторская диссертация, Утрехтский университет , 2004 год . ISBN 90-393-3765-9 
  • Generic Haskell: язык общего программирования
Ява
  • Гилад Браха, Обобщения на языке программирования Java , 2004.
  • Морис Нафталин и Филип Уодлер, Java Generics and Collections, 2006, O'Reilly Media, Inc. ISBN 0-596-52775-6 
  • Питер Сестофт, Точно Java, второе издание, 2005 MIT Press. ISBN 0-262-69325-9 
  • Общее программирование на Java , 2004 Sun Microsystems, Inc.
  • Анжелика Лангер, Часто задаваемые вопросы по Java Generics