Pour faire suite à un fil de conversation
L'idée de distinguer des types génériques et des types plus précis me semble une idée intéressante. La question est de savoir quels types doivent être intégrés.
Parmi les candidats, je proposerai bien un type "entier long" (signé?) qui n'existe pas sous R. À l'inverse, on pourrait avoir un entier court, par exemple pour le stockage des variables nominales (factors). En pratique, il y a rarement plus d'une douzaine de niveaux à ces variables (et, généralement, c'est quand t'as oublié de mettre cette p*** d'option stringsAsFactors à FALSE :-)). La plus part de ces variables tiendraient à l'aise sur un octet !!!
Il faudrait aussi un types "byte" un peu plus pratique que le type "raw" actuellement disponible sous R.
Sinon, pour les réels, je propose d'adopter une appellation (genre flpoint ou autre) qui rappelle explicitement à l'utilisateur qu'il ne s'agit PAS de réels mais bien de flottants, ce qui est loin d'être la même chose.
Mais bon, multiplier les types a un coût. Les opérations sur des objets de types différents nécessite de les identifier, d'identifier si l'opération est permise et, le cas échéant, de procéder à des casts (float + int :=> float + (cast::float) int).
D'un autre côté, le typage statique implique que le type des opérandes sera connu à la compilation dans de nombreuses situations. Les opérations de dispatch pourraient alors avoir lieu dès la compilation.
Dans les cas où le type ne peut être établi à la compilation (cf. héritage), il me semble qu'il existe des techniques suffisamment efficaces de lookup (genre cache + tables de hashage) pour que cela n'impacte pas les performances.
De plus, différentes techniques d'optimisation comme le bytecode polymorphique pourraient être mobilisées. Par exemple, si les opérations doivent réalisées sur des vecteurs, on peut tirer profit du fait que tous les éléments ont le même type. Le type peut être déterminé à l'exécution et les instructions correspondantes modifiées à la volée avant la ou les itérations.
Mais avant de se lancer dans la définition des types, je crois qu'il serait nécessaire de lever un certain nombre d'ambiguïtés actuellement présentes dans R.
Types et structures de données
Un des problèmes de R est qu'il n'est pas toujours facile de savoir à quoi on a à faire concrètement. Pour vous en convaincre, regardez les subtiles différences des résultats de typeof(), mode(), storage.mode() et class() (et il y en a peut-être d'autres...) appliquées aux mêmes objets ou d'un objet à l'autre.
Donc, si tu veux le type de la structure de données il faut utiliser is.* (et éventuellement ajouter un switch). À moins qu'il existe un fonction build-in mais je l'ai pas trouvé.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 ## x <- 1:3 ## typeof(x) ## "integer" ## mode(x) ## "numeric" ## storage.mode( x ) ##"integer" ## class(x) ## "integer" ## is.vector(x) ## TRUE ## typeof( matrix(x) ) ## "integer" ## class( matrix(x)) ## "matrix" et non "integer" ## is.matrix( matrix(x) ) ## TRUE
Il me semble qu'une partie du problème vient de ce que types et structures de données ne sont pas clairement distingués (en plus des couches sédimentaires des différentes versions du langage). C'est d'ailleurs une ambivalence assez rependue.
L'idée serait de clairement distinguer :
- les types : entiers, flottants, chaînes de caractères, ... qui hériteraient tous d'un objet scalaire
- les structures : toutes les façons d'organiser les types (ou d'autres structures) comme les vecteurs, les matrices, les listes, les graphes,...
Cela permettrait d'abord de faciliter l'introspection mais aussi d'être plus plus stricte lors de la mise à jour de slots de classe s4.
Par exemple, mettons que l'on souhaite qu'un membre d'une classe soit absolument un scalaire (le type scalaire qui n'existe pas dans R, les scalaires sont en fait des vecteurs de longueur un).
Donc, non seulement, il faut faire une vérification manuelle mais la vérification ne se fait pas sur un membre mais sur l'ensemble. Trop pratique. Un type scalaire permettrait d'automatiser tout ça.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 ## setClass( "scalar:int" , representation( x = "integer" ) ) ## setValidity( "scalar:int" , function(object){ ## if ( length( object@x )>1 ) paste("x is not a scalar (length=", length( object@x ), ")", sep='' ) else TRUE } ) ## scalar <- new("scalar:int") ## scalar@x <- 1L ## validObject(scalar) ## Ne génère aucune erreur !!!! scalar@x <- vector("integer", length=3) ## Erreur validObject(scalar)
De façon plus générale, ajouter une interface permettant de valider les membres individuellement lors de leur mise à jour pourrait être bienvenue.
Bref, passons.
Ajouter un type scalaire permettrait de faire des choses actuellement difficiles à obtenir. Comme par exemple, à la façon de certains DBMS SQL comme PostgreSQL, mettre directement des objets définis par l'utilisateur dans un vecteur (ce qui est possible mais assez complexe et, à mon avis, inefficace dans R actuellement). En gros, un vecteur pourrait accueillir tout objet héritant de la classe scalaire.
Thomas
Partager