Articulo de referencia

Tipo de unidad

En el ámbito de la lógica matemática y la informática conocido como teoría de tipos , un tipo unitario es un tipo que admite un único valor (y, por lo tanto, no puede contener i...

En el ámbito de la lógica matemática y la informática conocido como teoría de tipos , un tipo unitario es un tipo que admite un único valor (y, por lo tanto, no puede contener información). El conjunto subyacente asociado a un tipo unitario puede ser cualquier conjunto singleton . Existe un isomorfismo entre dos conjuntos cualesquiera de este tipo, por lo que es habitual hablar del tipo unitario e ignorar los detalles de su valor. También se puede considerar el tipo unitario como el tipo de las 0- tuplas , es decir, el producto de ningún tipo.

El tipo de unidad es el objeto terminal en la categoría de tipos y funciones tipadas. No debe confundirse con el tipo cero o vacío , que no admite valores y es el objeto inicial en esta categoría. De manera similar, el tipo booleano es el que admite dos valores.

El tipo de unidad se implementa en la mayoría de los lenguajes de programación funcional . El tipo void , utilizado en algunos lenguajes de programación imperativos, cumple algunas de sus funciones, pero debido a que su conjunto portador está vacío, presenta ciertas limitaciones (como se detalla a continuación).

En lenguajes de programación

Varios lenguajes de programación informática proporcionan un tipo de unidad para especificar el tipo de resultado de una función cuyo único propósito es causar un efecto secundario , y el tipo de argumento de una función que no requiere argumentos.

  • En Haskell , Rust y Elm , el tipo de unidad se llama ()y su único valor también es (), lo que refleja la interpretación de la tupla 0.
  • En los descendientes de ML (incluidos OCaml , Standard ML y F# ), el tipo se llama unitpero el valor se escribe como ().
  • En Scala , el tipo de unidad se llama Unity su único valor se escribe como ().
  • En Common Lisp, el tipo llamado NULL es un tipo de unidad que tiene un solo valor, a saber, el símbolo NIL . Esto no debe confundirse con el tipo NIL , que es el tipo inferior .
  • En Python , existe un tipo llamado NoneTypeque permite el valor único de None. En las anotaciones de tipo estático opcionales de Python, este tipo se representa como None. [ 1 ]
  • En Swift , el tipo de unidad se llama Voido ()y su único valor también es (), lo que refleja la interpretación de la tupla 0.
  • En Java , el tipo de unidad se llama Voidy su único valor es null. No se puede instanciar. Se utiliza en genéricos para denotar los tipos de retorno de void.
  • En Go , el tipo de unidad se escribe struct{}y su valor es struct{}{}.
  • En PHP , el tipo de unidad se llama null, cuyo único valor es NULL.
  • En JavaScript , tanto Null(su único valor es null) como Undefined(su único valor es undefined) son tipos de unidades integrados.
  • En Kotlin , Unites un singleton con un solo valor: el Unitobjeto.
  • En Ruby , niles la única instancia de la NilClassclase.
  • En C++ , el std::monostatetipo de unidad se agregó en C++17 . Antes de eso, es posible definir un tipo de unidad personalizado usando una estructura vacía como struct Empty {}.
  • En Dart , tanto Nullcomo el registro vacío ( (), desde Dart 3) tienen un único valor posible, respectivamente, nully ().

Tipo vacío como tipo de unidad

En C , C++ , C# , D y PHP , voidse utiliza para designar una función que no devuelve nada útil, o una función que no acepta argumentos. El tipo de unidad en C es conceptualmente similar a una estructura vacía struct, pero una estructura sin miembros no está permitida en la especificación del lenguaje C (esto sí está permitido en C++). En su lugar, voidse utiliza de una manera que simula algunas, pero no todas, las propiedades del tipo de unidad, como se detalla a continuación. Como la mayoría de los lenguajes imperativos, C permite funciones que no devuelven un valor; estas se especifican con el tipo de retorno void. Dichas funciones se denominan procedimientos en otros lenguajes imperativos como Pascal , donde se hace una distinción sintáctica, en lugar de una distinción del sistema de tipos, entre funciones y procedimientos.

Diferencia en la convención de llamadas

La primera diferencia notable entre un tipo de unidad verdadero y un tipo vacío es que el tipo de unidad siempre puede ser el tipo del argumento de una función, pero el tipo vacío no puede ser el tipo de un argumento en C, a pesar de que pueda aparecer como el único argumento en la lista. Este problema se ilustra mejor con el siguiente programa, que es un error de compilación en C:

void f ( void ) {} void g ( void ) {}int main ( void ) { f ( g ()); // error de compilación aquí return 0 ; }

Este problema no se presenta en la mayoría de las prácticas de programación en C, ya que, al voidno contener información, resulta inútil pasarlo; pero puede surgir en la programación genérica , como en las plantillas de C++ , donde voiddebe tratarse de forma diferente a otros tipos. Sin embargo, en C++ se permiten clases vacías, por lo que es posible implementar un tipo de unidad real; el ejemplo anterior se compila de la siguiente manera:

clase UnitType {}; constexpr UnitType UNIT ;UnitType f ( UnitType ) noexcept { return UNIT ; }UnitType g ( UnitType ) noexcept { return UNIT ; }int main () { f ( g ( UNIT )); return 0 ; }

Para mayor brevedad, UNITno se implementa como un singleton ; consulte el patrón singleton para obtener más información sobre las unidades singleton.

Diferencia en el almacenamiento

La segunda diferencia notable es que el tipo void es especial y nunca se puede almacenar en un tipo de registro , es decir, en una estructura o una clase en C/C++. En cambio, el tipo de unidad se puede almacenar en registros en lenguajes de programación funcional, es decir, puede aparecer como el tipo de un campo; la implementación anterior del tipo de unidad en C++ también se puede almacenar. Si bien esto puede parecer una característica inútil, permite, por ejemplo, implementar elegantemente un conjunto como un mapa al tipo de unidad; en ausencia de un tipo de unidad, aún se puede implementar un conjunto de esta manera almacenando algún valor ficticio de otro tipo para cada clave.

En genéricos

En Java Generics, los parámetros de tipo deben ser tipos de referencia. El tipo contenedor Voidse usa a menudo cuando se necesita un parámetro de tipo unidad.

importar java.util.concurrent.* ;ExecutorService executorService = Executors . newFixedThreadPool ( 2 );CompletableFuture < Void > future = CompletableFuture . runAsync (() -> { try { // Simular algún trabajo System . out . println ( "Tarea iniciada." ); Thread . sleep ( 2000 ); // Simular una tarea de 2 segundos System . out . println ( "Tarea completada." ); } catch ( InterruptedException e ) { System . err . println ( "La tarea fue interrumpida." ); } }, executorService );

Aunque el Voidtipo nunca puede tener instancias, sí tiene un valor null(como todos los demás tipos de referencia), por lo que actúa como un tipo unitario. En la práctica, cualquier otro tipo no instanciable, por ejemplo Math, también puede usarse para este propósito, ya que también tienen exactamente un valor null.

public static Void f ( Void x ) { return null ; }public static Void g ( Void x ) { return null ; }public static void main ( String [] args ) { f ( g ( null )); }

Tipo nulo

Los lenguajes de tipado estático asignan un tipo a cada expresión posible. Necesitan asociar un tipo a la nullexpresión. Se definirá un tipo para nully solo tendrá ese valor.

Por ejemplo, en D, es posible declarar funciones que solo pueden devolver null(de hecho, typeof(null)es void):

typeof ( null ) returnThatSpecialThing () { return null ; }void writeTypeOfNull () { writeln ( typeof ( null )); // imprime: void }

nulles el único valor que typeof(null)puede tener , un tipo de unidad.

Véase también

Notas

  1. van Rossum, Guido; Levkivskyi, Ivan. "PEP 483 - Using None" . Python Enhancement Proposals . Python Software Foundation . Consultado el 2 de marzo de 2024 .

Referencias