En programación genérica , un concepto es una descripción de las operaciones admitidas sobre un tipo , incluyendo su sintaxis y semántica. De esta forma, los conceptos se relacionan con tipos abstractos , pero no requieren una relación de subtipo.
Uso del lenguaje
El término se utilizaba ya en 1998 para STL , [ 1 ] ya que esta fue una de las primeras bibliotecas que utilizó plantillas de forma extensiva. El concepto del término (y su popularización) se atribuye a Alexander Stepanov , [ 2 ] [ 3 ] el diseñador principal de STL.
En el estándar C++ 1998, el término Concept se introdujo para nombrar una simple descripción de los requisitos para un tipo particular, generalmente un parámetro de plantilla. No estaba codificado explícitamente en el lenguaje: el concepto se expresaba solo por las operaciones que se intentaban en objetos de ese tipo y lo que se esperaba que funcionara (es decir, que compilara correctamente). Hubo una propuesta para agregar conceptos como una característica explícita del lenguaje en C++11 , aunque fue rechazada por "no estar lista". C++20 finalmente aceptó el diseño refinado del concepto, aunque era una versión reducida de su propuesta anterior. [ 4 ] Los conceptos son un ejemplo de tipado estructural .
Dado que los genéricos en Java y C# tienen algunas similitudes con las plantillas de C++ , el papel de los conceptos allí lo desempeñan las interfaces . Sin embargo, existe una diferencia importante entre conceptos e interfaces: cuando se requiere que un parámetro de plantilla implemente una interfaz particular, el tipo correspondiente solo puede ser una clase que implemente (explícitamente) esa interfaz. Esto se conoce como tipado nominal . Los conceptos aportan mayor flexibilidad porque pueden satisfacerse de dos maneras:
- Se define explícitamente como satisfecho mediante el uso de un mapa conceptual (definido por separado del tipo en sí, a diferencia de las interfaces).
- definido implícitamente para "autoconceptos", que también se pueden usar para tipos integrados y otros tipos que no fueron predestinados para este uso.
Pero el lenguaje C# tiene varias construcciones donde el tipo utilizado no necesita implementar explícitamente una interfaz definida, solo se requiere que coincida con el patrón correspondiente (sin embargo, estos patrones no se denominan conceptos ). Por ejemplo, la foreachinstrucción de iteración permite que el objeto iterado sea de cualquier tipo, siempre que implemente un GetEnumeratormétodo apropiado. [ 5 ] (Compárese con la usinginstrucción que requiere que el recurso implemente la System.IDisposableinterfaz. [ 6 ] )
El lenguaje de programación Nim implementa conceptos como una serie de predicados booleanos arbitrarios en tiempo de compilación. [ 7 ]
Otro lenguaje que implementa conceptos muy similares es Haskell , donde la característica se llama clases de tipos .
En el lenguaje de programación Go , las interfaces son el equivalente a los conceptos de C++, que definen un conjunto de firmas de métodos. A diferencia de las interfaces de Java/C#, donde las clases deben declarar que implementan la interfaz, los tipos que satisfacen estas firmas implementan la interfaz (implícitamente). [ 8 ]
Ejemplos
Pedido total
El concepto de ordenación total describe la semántica del <operador. Un tipo está totalmente ordenado cuando <es un predicado binario y satisface las siguientes propiedades: [ 9 ] [ 10 ]
- antirreflexivo:
!(a < a)para cualquier valora. - transitivo: Si
a < byb < centoncesa < c. - antisimétrico: Si
a < bentonces!(b < a). - total: Si entonces o .
a != ba < bb < a
Muchos algoritmos dependen de estas propiedades para funcionar correctamente. Por ejemplo, la minfunción se puede definir de forma segura en tipos totalmente ordenados:
importar std ;usando std :: totalmente_ordenado ;plantilla < totally_ordered T > [[ nodiscard ]] constexpr T min ( T a , T b ) noexcept { return ( b < a ) ? b : a ; }O bien, en lugar del concepto , se puede usar typenameuna cláusula. Una cláusula solo es necesaria cuando las restricciones son demasiado complejas para describirlas directamente en la declaración. También se pueden usar cláusulas finales.requiresrequirestypenamerequires
template < typename T > requires totally_ordered < T > [[ nodiscard ]] constexpr T min ( T a , T b ) noexcept { return ( b < a ) ? b : a ; }Iterador
Si un tipo Itersatisface el concepto de iterador trivial en C++ y ies de tipo Iter, las siguientes son expresiones válidas con la semántica correspondiente: [ 11 ]
Iter iConstrucción predeterminada.*idebe ser convertible a algún tipoT.i->mes válido si(*i).mlo es.
Véase también
Referencias
- ↑ Austern, MH. Programación genérica y la STL: uso y extensión de la biblioteca de plantillas estándar de C++ . 1998. págs. 17-18.
- ↑ Un poco de información básica sobre conceptos y C++17 — Bjarne Stroustrup , por Bjarne Stroustrup | 26 de febrero de 2016
- ↑ Alex Stepanov , por Bjarne Stroustrup | 21 de enero de 2016
- ↑ Andrew Sutton (24 de febrero de 2013). "Conceptos Lite: Restricción de plantillas con predicados" . isocpp.org.
- ↑ Borrador de especificación de C# 6.0 , La instrucción foreach
- ↑ Borrador de especificación de C# 6.0 , La instrucción using
- ↑ "Características experimentales de Nim" . nim-lang.org . Consultado el 19 de junio de 2023 .
- ↑ Los autores de Go. "Un recorrido por las interfaces de Go" . go.dev . Los autores de Go . Consultado el 5 de mayo de 2026 .
- ↑ Stepanov, Alexander (2009). Elementos de programación . Addison-Wesley Professional. pág. 49. ISBN 9780321635372.
- ↑ Pedidos totales: programación eficiente con componentes
- ↑ Iterador trivial
Enlaces externos
- Mejora las técnicas de programación genéricas
- Douglas Gregor y otros. Conceptos: Soporte lingüístico para la programación genérica en C++.
- Charla de Doug Gregor sobre conceptos en Google (vídeo)
- Comparación de conceptos de C++ y clases de tipos de Haskell. Archivado el 9 de agosto de 2017 en Wayback Machine.
- Programación genérica