¿Cuándo una característica se considera un "ciudadano de primera clase" en un lenguaje / plataforma de programación?

61

He visto muchas veces declaraciones como: "Por favor, convierta esta característica en un ciudadano de primera clase en un lenguaje / plataforma". Por ejemplo, se dice acerca de las enumeraciones en C # /. Net. Entonces, ¿cuándo una característica se considera un "ciudadano de primera clase" en un lenguaje / plataforma de programación?

Gulshan
fuente

Respuestas:

40

Definición

Un objeto es de primera clase cuando:

  • se puede almacenar en variables y estructuras de datos
  • se puede pasar como parámetro a una subrutina
  • se puede devolver como resultado de una subrutina
  • se puede construir en tiempo de ejecución
  • tiene identidad intrínseca (independiente de cualquier nombre de pila)

El término "objeto" se usa libremente aquí, no necesariamente refiriéndose a objetos en la programación orientada a objetos. Los tipos de datos escalares más simples, como los números enteros y de coma flotante, son casi siempre de primera clase.

http://en.wikipedia.org/wiki/First_class_object

Waquo
fuente
1
Entonces, ¿qué hace que las enumeraciones sean objetos de segunda clase en .net / C #?
Gulshan
77
@Gulshan: se podría argumentar la falta de identidad intrínseca: las enumeraciones de C # son básicamente azúcar sintáctico (es decir, un "nombre de pila") para un valor entero. Compare con Java, donde las enumeraciones son objetos por derecho propio.
mikera
@mikera, en .NET las enumeraciones son valores por derecho propio. Java simplemente no tiene ningún valor, solo objetos, esa es la única diferencia.
SK-logic
@mikera: aunque eso evita que las enumeraciones de Java tengan algunas propiedades agradables, como poder representar campos de bits con ellas. Si bien su implementación es probablemente más de primera clase, la mayoría de sus API todavía tienen muchas constantes enteras (o cadenas) y muchos de sus usos no se pueden reemplazar fácilmente con enumeraciones.
Joey
No creo que se puedan construir enumeraciones en tiempo de ejecución en .Net, ¿verdad? Pensé que siempre eran constantes.
travis
33

La noción de "ciudadano de primera clase" o "elemento de primera clase" en un lenguaje de programación fue introducida por el científico informático británico Christopher Strachey en la década de 1960 en el contexto de funciones de primera clase. La formulación más famosa de este principio se encuentra probablemente en Estructura e interpretación de programas de computadora por Gerald Jay Sussman y Harry Abelson:

  • Pueden ser nombrados por variables.
  • Se pueden pasar como argumentos a los procedimientos.
  • Pueden ser devueltos como resultado de los procedimientos.
  • Pueden incluirse en estructuras de datos.

Básicamente, significa que puede hacer con este elemento del lenguaje de programación todo lo que puede hacer con todos los demás elementos del lenguaje de programación.

Se trata de "igualdad de derechos": puede hacer todo lo anterior con, digamos, números enteros, entonces, ¿por qué debería ser diferente cualquier otra cosa?

La definición anterior es un poco restrictiva en el sentido de que solo habla realmente sobre el aspecto de primera clase en relación con ser objetos del programa. Una definición más general sería que una cosa es de primera clase si puedes hacer todo con ella, también puedes hacer otras cosas similares.

Por ejemplo, los operadores de Java y los métodos de Java son de tipo similar. Puede definir nuevos métodos, puede (de alguna manera) elegir libremente los nombres de sus propios métodos, puede anular los métodos, puede sobrecargar los métodos. James Gosling también puede hacer todo eso con los operadores, pero usted y yo no podemos. Es decir, contrariamente a la creencia popular, Java hace la sobrecarga de operadores de apoyo: por ejemplo, el +operador está sobrecargado para byte, short, int, long, float, doubley String, y IIRC en Java 7 también para BigIntegere BigDecimal(y probablemente un par me olvidó), es sólo que seno tengo ninguna influencia sobre eso. Eso claramente hace que los operadores sean de segunda clase de acuerdo con esta segunda definición. Sin embargo, tenga en cuenta que los métodos todavía no son objetos de primera clase según la primera definición. (¿Eso hace que los operadores sean de tercera clase?)

Jörg W Mittag
fuente
6

Por lo general, esto se refiere a una construcción que es aceptable como parámetro, se puede definir como un tipo de retorno de una función o se le puede asignar un valor. Normalmente necesitas poder construirlos en tiempo de ejecución. Por ejemplo, una instancia de una clase sería un ciudadano de primera clase en c ++ o java, pero una función en C no lo sería.

Pemdas
fuente
¿Qué hace que una clase sea un ciudadano de primera clase en c ++?
Bjarke Freund-Hansen
2
@bjarkef: Parece que eso ya fue respondido por su correspondencia con la descripción ofrecida en las oraciones anteriores.
doppelgreener
@ Jonathan: Sí, lo siento, leí mal el "construirlos en tiempo de ejecución". Sí, puede construir una instancia de una clase en tiempo de ejecución (un objeto), pero no la clase en sí. Eso es lo que me confundió.
Bjarke Freund-Hansen
1
Pasar por parámetro todavía no es suficiente. En C / C ++ todavía consideraría las funciones como ciudadanos de segunda clase. Se pueden pasar como parámetros, devolverse como resultados colocados dentro de otros objetos. Pero no pueden manipularse sin la ayuda de otras construcciones (como std :: bind es necesario para vincular parámetros a una función).
Martin York
@ Martin Nunca dije que las funciones fueran ciudadanos de primera clase en C / C ++.
Pemdas
1

Yo diría que una característica es un ciudadano de primera clase si se implementa únicamente por el idioma.
es decir, no requiere características de múltiples idiomas o una biblioteca estándar para implementar esa característica.

Ejemplo:

En C / C ++ no considero que las funciones sean ciudadanos de primera clase (otros pueden).
Esto se debe a que hay formas de manipular funciones que son compatibles directamente con el lenguaje pero que requieren el uso de otras características del lenguaje. Los parámetros de enlace a una función no se admiten directamente y debe crear un functor para implementar esta función.

Martin York
fuente
1
¿No haría eso que las funciones vinculadas (o "cierres") no fueran de primera clase, mientras que las funciones mismas sí lo son? ¿Cómo influye el soporte de 0x para cierres en su análisis?
Fred Nurk
@ Fred Nurk: Todo depende del idioma. En algunos idiomas, los cierres son sistemas de primera clase. En otros no. Todavía no estoy lo suficientemente familiarizado con C ++ 0x para hacer un comentario explícito.
Martin York
Digamos que el lenguaje es C o C ++ (pero no 0x), como en su respuesta. ¿Su definición de "primera clase" no hace que las funciones vinculadas (o "cierres") no sean de primera clase, mientras que las funciones sí lo son?
Fred Nurk
@ Fred Nurk: si limitas lo único que puedes hacer con una función es cerrarlos, entonces seguro. Pero para mí eso es como decir si su plataforma admite la suma de enteros solo importando una biblioteca. Entonces los enteros son ciudadanos de primera clase, pero no se considera la adición de enteros. En mi opinión, el cierre es una operación que se puede realizar en una función que devuelve efectivamente una nueva función (pero depende de cómo la defina). Pero el cierre y la unión son solo dos operaciones, ¿cuántas otras estamos excluyendo de la discusión? (No estoy seguro de que fuera una pregunta).
Martin York
@ Martin: No debo explicarme claramente. Dado que "una característica es un ciudadano de primera clase si se implementa únicamente por el lenguaje", las funciones en C y C ++ se implementan únicamente por el lenguaje y, por lo tanto, serían de primera clase. Las funciones enlazadas (que también pueden llamarse "cierres") son de lo que estás hablando con los parámetros de enlace, etc., pero esa es una característica diferente.
Fred Nurk
-1

Para agregar un ejemplo a las respuestas ya proporcionadas:

En WCF / C #, actualmente tiene que marcar un objeto de clase con un atributo de contrato de servicio para que funcione como un servicio. No hay tal cosa como:

public **service** MyService (in relation public **class** MyClass). 

Una clase es un ciudadano de primera clase en c #, donde un servicio no lo es.

Espero que esto ayude

Syg
fuente