Une chose qui m'est venue à l'esprit l'autre jour, ce sont des types spécifiques encore nécessaires ou un héritage qui nous retient. Ce que je veux dire, c'est: avons-nous vraiment besoin de court, int, long, bigint, etc., etc.
Je comprends le raisonnement, les variables / objets sont conservés en mémoire, la mémoire doit être allouée et donc nous devons savoir quelle taille peut avoir une variable. Mais vraiment, un langage de programmation moderne ne devrait-il pas être capable de gérer des "types adaptatifs", c'est-à-dire que si quelque chose n'est alloué que dans la plage courte, il utilise moins d'octets et si quelque chose est soudainement alloué à un très grand nombre, la mémoire est allouée conformément à ce cas particulier.
Float, real et double's sont un peu plus délicats car le type dépend de la précision dont vous avez besoin. Les chaînes devraient cependant être en mesure de prendre upp moins de mémoire dans de nombreux cas (en .Net) où la plupart du temps ascii est utilisé, mais les chaînes buth occupent toujours le double de la mémoire en raison du codage Unicode.
Un argument pour des types spécifiques pourrait être qu'il fait partie de la spécification, c'est-à-dire par exemple qu'une variable ne devrait pas pouvoir être plus grande qu'une certaine valeur, nous la définissons donc en shortint. Mais pourquoi ne pas avoir à la place des contraintes de type? Il serait beaucoup plus flexible et puissant de pouvoir définir des plages et des valeurs autorisées sur des variables (et des propriétés).
Je me rends compte de l'immense problème de refonte de l'architecture de type car elle est si étroitement intégrée au matériel sous-jacent et des choses comme la sérialisation pourraient devenir délicates. Mais du point de vue de la programmation, ça devrait être super non?
type hour is range 0 .. 23;
Réponses:
Je crois totalement que c'est le cas. Les contraintes sémantiques valent plus que les contraintes d'implémentation. S'inquiéter de la taille de quelque chose revient à s'inquiéter de la vitesse de quelque chose lors de la programmation orientée objet.
Il n'a pas remplacé la programmation essentielle aux performances. Cela a simplement rendu la programmation critique non liée aux performances plus productive.
la source
Les types adaptatifs signifient la logique pour faire l'adaptation, signifie travailler au moment de l'exécution pour exécuter cette logique (les modèles et la compilation nécessiteraient un type spécifique, l' inférence de type étant un cas spécial où vous obtenez le meilleur des deux mondes). Ce travail supplémentaire pourrait être acceptable dans des environnements où les performances ne sont pas critiques et où le système conserve une taille raisonnable. Dans d'autres environnements, ce n'est pas le cas (les systèmes intégrés en sont un, où vous devez parfois utiliser des types entiers 32/64 bits pour les performances du processeur et des types entiers 8/16 bits pour l'optimisation de la sauvegarde de la mémoire statique).
Même les langages à usage général qui prenaient en charge la liaison tardive (résolution des types au moment de l'exécution, comme VB6) ont tendance à promouvoir un typage fort maintenant (VB.NET), en raison des performances qui se produisaient auparavant lorsque la liaison tardive était abusive, et parce que vous souvent se retrouver avec du code laid lorsque les types ne sont pas explicites ( refactoring de référence / professionnel en Visual Basic - Danijel Arsenovski ).
la source
Simplicité, mémoire et vitesse Lorsque je déclare une variable, la mémoire de cette variable est allouée dans un bloc. Afin de prendre en charge une variable à croissance dynamique, je devrais ajouter le concept de mémoire non contiguë à cette variable (que ce soit ou réserver le plus grand bloc que la variable peut représenter). La mémoire non contiguë réduirait les performances lors de l'affectation / récupération. Allouer le plus grand possible serait un gaspillage dans le scénario où je n'ai besoin que d'un octet mais le système réserve longtemps.
Pensez aux compromis entre un tableau et un vecteur (ou une liste liée). Avec un tableau, la recherche d'une position spécifique consiste simplement à obtenir la position de départ et à déplacer le pointeur de mémoire x espaces pour localiser cette nouvelle position dans la mémoire. Considérez un entier comme un bit [32] la lecture d'un entier implique de parcourir ce tableau pour obtenir toutes les valeurs de bits.
Pour créer un type de nombre dynamique, vous devez le changer d'un tableau de bits en un vecteur de bits. La lecture de votre numéro dynamique implique d'aller en tête, d'obtenir ce bit, de demander où se trouve le bit suivant, de se déplacer vers cet emplacement, d'obtenir ce bit, etc. Pour chaque bit du numéro dynamique, vous effectuez trois opérations de lecture ( actuel), lire (adresse du suivant), déplacer (suivant). Imaginez lire les valeurs d'un million de nombres. C'est un million d'opérations supplémentaires. Cela peut sembler insignifiant. Mais pensez aux systèmes (comme les finances) où chaque milliseconde compte.
Il a été décidé que le fardeau du développeur de vérifier la taille et de valider est un petit compromis par rapport à la performance du système.
la source
Des types spécifiques sont requis pour les langages et projets centrés sur le matériel. Un exemple est les protocoles de réseau sur le fil.
Mais créons - pour le plaisir - un type varint dans un langage comme C ++. Construisez-le à partir d'un
new
tableau de dts.Il n'est pas difficile d'implémenter l'ajout: il suffit de xor les octets ensemble et de vérifier les bits élevés: s'il y a une opération de report,
new
dans un nouvel octet supérieur et de reporter le bit. La soustraction suit trivialement dans la représentation du complément à 2. (Ceci est également connu comme un additionneur de report d'ondulation).La multiplication suit de la même manière; utiliser l'ajout / décalage itératif. Comme toujours, la vraie torsion dans votre queue est la division [*].
Mais qu'avez-vous perdu quand cela se produit?
Temps déterministe. Vous avez un syscall (
new
) qui peut se déclencher à des points qui ne sont pas nécessairement contrôlables.Espace déterministe.
Les mathématiques semi-logicielles sont lentes.
Si vous devez utiliser un langage de couche matérielle et devez également fonctionner à un niveau élevé (lent) et que vous ne souhaitez pas intégrer de moteur de script,
varint
cela a beaucoup de sens. C'est probablement écrit quelque part.[*] Cf algorithmes mathématiques matériels pour des moyens plus rapides de le faire - généralement, l'astuce consiste à effectuer des opérations parallèles.
la source
C'est une bonne question. Il explique pourquoi un langage tel que Python n'a pas besoin de "short, int, long, bigint etc.": les entiers sont, eh bien, des entiers (il existe un seul type d'entier en Python 3), et n'ont pas de taille limite (au-delà de celle de la mémoire de l'ordinateur, bien sûr).
Quant à Unicode, le codage UTF-8 (qui fait partie d'Unicode) n'utilise qu'un seul caractère pour les caractères ASCII, donc ce n'est pas si mal.
Plus généralement, les langages dynamiques semblent aller dans le sens que vous mentionnez. Cependant, pour des raisons d'efficacité, des types plus contraints sont utiles dans certains cas (comme les programmes qui doivent s'exécuter rapidement). Je ne vois pas beaucoup de changements dans un avenir prévisible, car les processeurs organisent les données en octets (ou 2, 4, 8, etc. octets).
la source
Sur une base de théorie du langage, vous avez raison. Les types doivent être basés sur un ensemble d'états légaux, les transformations disponibles pour ces états et les opérations exécutables sur ces états.
C'est à peu près ce que vous offre la programmation OOP dans sa forme typique. En fait, en Java, vous parlez effectivement des classes
BigInteger
etBigDecimal
, qui allouent de l'espace en fonction de la quantité requise pour stocker l'objet. (Comme l'a noté FrustratedWithFormsDesigner, de nombreux langages de type scripting sont encore plus loin sur ce chemin et ne nécessitent même pas de déclaration de type et stockent tout ce que vous leur donnez.)Cependant, les performances sont toujours pertinentes, et comme il est coûteux de changer de type au moment de l'exécution et que les compilateurs ne peuvent pas garantir la taille maximale d'une variable au moment de la compilation, nous avons toujours des variables de taille statique pour les types simples dans de nombreux langages.
la source
int
ou undouble
, et si ce n'est pas le cas, ils en sont conscients, donc le dimensionnement dynamique de la valeur est une fonctionnalité pour laquelle ils n'ont pas besoin de payer.Cela dépend de la langue. Pour les langages de niveau supérieur comme Python, Ruby, Erlang, etc., vous n'avez que le concept de nombres entiers et décimaux.
Cependant, pour une certaine classe de langues, ces types sont très importants. Lorsque vous écrivez du code pour lire et écrire des formats binaires comme PNG, JPeg, etc., vous devez savoir précisément combien d'informations sont lues à la fois. Idem pour l'écriture des noyaux du système d'exploitation et des pilotes de périphérique. Tout le monde ne le fait pas, et dans les langages de niveau supérieur, ils utilisent les bibliothèques C pour faire le gros du travail détaillé.
Dans
short
, il y a encore une place pour les types plus spécifiques, mais de nombreux problèmes de développement ne nécessitent pas cette précision.la source
J'ai récemment créé un éditeur de logique à relais et un runtime et j'ai décidé d'être très limité avec les types:
Je crois que cela l'a rendu plus intuitif pour l'utilisateur. C'est un changement radical par rapport à la plupart des automates programmables qui ont toute la gamme "normale" de types que vous verriez dans une langue comme C.
la source
Les langages de programmation ont évolué dans cette direction. Prenez des chaînes par exemple. Dans les anciennes langues, vous devez déclarer la taille de la chaîne, comme
PIC X(42)
dans COBOL,DIM A$(42)
dans certaines versions de BASIC, ou [VAR
]CHAR(42)
dans SQL. Dans les langues modernes, vous n'en avez qu'un alloué dynamiquementstring
type et vous n'avez pas besoin de penser à la taille.Les entiers sont cependant différents:
Jetez un oeil à Python. Il faisait la distinction entre les entiers de taille machine (
int
) et de taille arbitraire (long
). Dans 3.x l'ancien est parti (l'ancienlong
est le nouveauint
) et personne ne le manque.Mais il existe toujours un type spécialisé pour les séquences d'entiers 8 bits sous la forme de
bytes
etbytearray
. Pourquoi ne pas utiliser respectivement untuple
oulist
des entiers? Certes,bytes
il existe des méthodes de type chaîne supplémentaires quituple
ne le font pas, mais l'efficacité a certainement beaucoup à voir avec cela.Pas vraiment. L'approche «tout est double précision» est très courante.
la source
unum64 += ring32a-ring32b
donnera toujours le comportement correct, que le type entier par défaut soit 16 bits ou 64 [notez que l'utilisation de+=
est essentielle; une expression commeunum64a = unum64b + (ring32a-ring32b);
devrait être rejetée comme ambiguë.]Je comprends le raisonnement, les variables / objets sont conservés en mémoire, la mémoire doit être allouée et donc nous devons savoir quelle taille peut avoir une variable. Mais vraiment, un langage de programmation moderne ne devrait-il pas être capable de gérer des "types adaptatifs", c'est-à-dire que si quelque chose n'est alloué que dans la plage courte, il utilise moins d'octets et si quelque chose est soudainement alloué à un très grand nombre, la mémoire est allouée conformément à ce cas particulier.
Float, real et double's sont un peu plus délicats car le type dépend de la précision dont vous avez besoin. Les chaînes devraient cependant être en mesure de prendre upp moins de mémoire dans de nombreux cas (en .Net) où la plupart du temps ascii est utilisé, mais les chaînes buth occupent toujours le double de la mémoire en raison du codage Unicode.
Fortran a eu quelque chose de similaire (je ne sais pas si c'est exactement ce que vous voulez dire, car je vois vraiment deux questions). Par exemple, dans F90 vers le haut, vous n'avez pas besoin de définir explicitement une taille de type , pour ainsi dire. Ce qui est bien, non seulement car il vous donne une place centrale pour définir vos types de données, mais aussi une manière portable de les définir. REAL * 4 n'est pas le même dans toutes les implémentations sur tous les processeurs (et par processeur je veux dire CPU + compilateur), pas par un longhot.
selected_real_kind (p, r) renvoie la valeur de type d'un type de données réel avec une précision décimale supérieure d'au moins p chiffres et une plage d'exposants supérieure d'au moins r.
Vous partez donc, par exemple;
(Je pense que c'est un exemple assez explicite).
Je ne sais toujours pas si j'ai bien compris votre question, et c'est ce que vous mentionnez.
la source