Quand une fonctionnalité est-elle considérée comme un «citoyen de première classe» dans un langage / une plate-forme de programmation?

61

J'ai vu à maintes reprises des déclarations telles que «Faites de cette fonctionnalité un citoyen de première classe dans telle ou telle langue / plate-forme». Par exemple, on parle d’énums en C # / .net. Alors, quand une fonctionnalité est-elle considérée comme un "citoyen de première classe" dans un langage / une plate-forme de programmation?

Gulshan
la source

Réponses:

40

Définition

Un objet est de première classe quand il:

  • peut être stocké dans des variables et des structures de données
  • peut être passé comme paramètre à un sous-programme
  • peut être retourné à la suite d'un sous-programme
  • peut être construit à l'exécution
  • a une identité intrinsèque (indépendante de tout prénom)

Le terme "objet" est utilisé ici de manière vague, ne faisant pas nécessairement référence aux objets dans la programmation orientée objet. Les types de données scalaires les plus simples, tels que les nombres entiers et les nombres à virgule flottante, sont presque toujours de première classe.

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

Waquo
la source
1
Alors, qu'est-ce qui rend un objet de deuxième classe enums dans .net / C #?
Gulshan
7
@Gulshan - vous pourriez argumenter sur le manque d'identité intrinsèque - les énumérations C # ne sont fondamentalement que du sucre syntaxique (c'est-à-dire un "prénom") pour une valeur entière. Comparez avec Java, où les enums sont des objets à part entière.
Mikera
@mikera, dans .NET, les enums sont des valeurs à part entière. Java n'a tout simplement aucune valeur, seulement des objets, c'est la seule différence.
SK-logic
@ mikera: Bien que cela empêche les enums de Java d'avoir quelques propriétés intéressantes telles que pouvoir représenter des champs de bits avec eux. Bien que leur implémentation soit probablement de première classe, la plupart de leurs API contiennent encore beaucoup de constantes entières (ou chaînes) et de nombreuses utilisations de celles-ci ne peuvent pas être facilement remplacées par des énumérations.
Joey
Je ne pense pas que des enums puissent être construits au moment de l'exécution en .Net, peuvent-ils? Je pensais qu'ils étaient toujours des constantes.
Travis
33

La notion de "citoyen de première classe" ou "élément de première classe" dans un langage de programmation a été introduite par l'informaticien britannique Christopher Strachey dans les années 1960 dans le contexte de fonctions de première classe. La formulation la plus célèbre de ce principe est probablement dans Structure et interprétation des programmes informatiques de Gerald Jay Sussman et Harry Abelson:

  • Ils peuvent être nommés par des variables.
  • Ils peuvent être transmis en tant qu'arguments aux procédures.
  • Ils peuvent être renvoyés à l'issue des procédures.
  • Ils peuvent être inclus dans les structures de données.

En gros, cela signifie que vous pouvez faire avec cet élément de langage de programmation tout ce que vous pouvez faire avec tous les autres éléments du langage de programmation.

Tout est une question "d'égalité des droits": vous pouvez faire tout ce qui précède, avec, par exemple, des nombres entiers, alors pourquoi une autre chose devrait-elle être différente?

La définition ci-dessus est un peu restrictive dans le sens où elle ne parle que de l'aspect de première classe en tant qu'objets du programme. Une définition plus générale serait qu'une chose est de première classe si vous pouvez tout faire avec elle, vous pouvez également faire avec d'autres choses du même genre.

Par exemple, les opérateurs et les méthodes Java sont du même type. Vous pouvez définir de nouvelles méthodes, vous pouvez (un peu) choisir librement les noms de vos propres méthodes, vous pouvez remplacer des méthodes, vous pouvez surcharger des méthodes. James Gosling peut également faire tout cela avec des opérateurs, mais vous et moi ne le pouvons pas. Je veux dire, contrairement à la croyance populaire, Java ne surcharge d'opérateur de support: par exemple, l' +opérateur est surchargé pour byte, short, int, long, float, doubleet String, et IIRC en Java 7 aussi BigIntegeret BigDecimal(et probablement deux ou trois j'ai oublié), il est juste que vousne pas avoir d'influence sur elle. Cela place clairement les opérateurs de deuxième classe selon cette deuxième définition. Notez que les méthodes ne sont toujours pas des objets de première classe selon la première définition. (Cela fait-il des opérateurs de troisième classe?)

Jörg W Mittag
la source
6

Il s’agit généralement d’une construction qui peut être passée comme paramètre, qui peut être définie comme un type de retour d’une fonction ou à laquelle une valeur peut être affectée. Normalement, vous devez être capable de les construire au moment de l'exécution. Par exemple, une instance de classe serait un citoyen de première classe en c ++ ou java, mais pas une fonction en C.

Pemdas
la source
Qu'est-ce qui fait qu'une classe est un citoyen de première classe en c ++?
Bjarke Freund-Hansen
2
@bjarkef: On dirait que cela a déjà été répondu en faisant correspondre la description proposée dans les phrases précédentes.
Doppelgreener
@ Jonathan: Oui, désolé, j'ai mal interprété le "les construire au moment de l'exécution". Oui, vous pouvez construire une instance d'une classe au moment de l'exécution (un objet), mais pas la classe elle-même. C'est ce qui m'a confondu.
Bjarke Freund-Hansen
1
Passer par paramètre n'est toujours pas suffisant. En C / C ++, je considérerais toujours les fonctions comme des citoyens de seconde classe. Ils peuvent être passés sous forme de paramètres, retournés sous forme de résultats placés à l'intérieur d'autres objets. Mais ils ne peuvent pas être manipulés sans l'aide d'autres constructions (comme std :: bind est requis pour lier des paramètres à une fonction).
Martin York
@ Martin Je n'ai jamais dit que les fonctions étaient des citoyens de première classe en C / C ++.
Pemdas
1

Je dirais qu'une fonctionnalité est un citoyen de première classe si elle est mise en œuvre uniquement par la langue.
c'est-à-dire qu'il ne nécessite pas de fonctionnalités multilingues ou une bibliothèque standard pour implémenter cette fonctionnalité.

Exemple:

En C / C ++, je ne considère pas les fonctions comme des citoyens de première classe (d’autres le peuvent).
En effet, il existe des moyens de manipuler des fonctions directement prises en charge par le langage mais nécessitant l’utilisation d’autres fonctionnalités. La liaison de paramètres à une fonction n'est pas directement prise en charge et vous devez créer un foncteur pour implémenter cette fonctionnalité.

Martin York
la source
1
Cela ne ferait-il pas en sorte que les fonctions liées (ou "fermetures") ne soient pas de première classe, alors que les fonctions elles-mêmes le sont? Comment le soutien de 0x aux fermetures prend-il en compte dans votre analyse?
Fred Nurk
@ Fred Nurk: Tout dépend de la langue. Dans certaines langues, les fermetures sont des systèmes de première classe. Dans d'autres pas. Je ne suis pas encore assez familiarisé avec C ++ 0x pour faire un commentaire explicite.
Martin York
Disons que le langage est C ou C ++ (mais pas 0x), comme dans votre réponse. Votre définition de "première classe" ne ferait-elle pas que les fonctions liées (ou "fermetures") ne soient pas de première classe, alors que les fonctions elles-mêmes le sont?
Fred Nurk
@ Fred Nurk: Si vous limitez la seule chose que vous puissiez faire avec une fonction est de leur faire une fermeture, alors bien sûr. Mais pour moi, cela revient à dire que si votre plate-forme prend en charge l’ajout d’entiers uniquement en important une bibliothèque. Alors les entiers sont des citoyens de première classe mais l’addition d’entiers n’est pas envisagée. À mon avis, la fermeture est une opération qui peut être effectuée sur une fonction qui renvoie effectivement une nouvelle fonction (mais cela dépend de la définition que vous en donnez). Mais la fermeture et la reliure ne sont que deux opérations parmi les autres que nous excluons de la discussion (je ne suis pas sûr que ce soit une question).
Martin York
@ Martin: Je ne dois pas m'expliquer clairement. Etant donné qu'une caractéristique est un citoyen de première classe si elle est implémentée uniquement par le langage, les fonctions à la fois en C et en C ++ sont implémentées uniquement par le langage et seraient donc de première classe. Les fonctions liées (que l'on peut aussi appeler "fermetures") sont ce dont vous parlez avec les paramètres de liaison, etc., mais c'est une caractéristique différente.
Fred Nurk
-1

Pour ajouter un exemple aux réponses déjà fournies:

Dans WCF / C #, vous devez actuellement marquer un objet de classe avec un attribut de contrat de service pour le faire fonctionner en tant que service. Il n'y a pas une telle chose comme:

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

Une classe est un citoyen de première classe en c #, alors qu'un service ne l'est pas.

J'espère que cela t'aides

Syg
la source