3 Structure du langage

3.1 For

La structure est ‘for in endFor’. Si on est sur une ligne, le endFor est optionnel. On doit conserver la possibilité de faire des for sur des vecteurs, y compris des vecteurs d'objets complexes (comme un vecteur de fonction par exemple). La boucle for doit rester simple : pas de double déclaration de variable, pas d’incrémentation de plusieurs variable. Pour les choses trop compliqué, on passe sur du while. On peut déclarer la variable compteur directement dans la boucle. La variable est typée de la manière suivante : d’abord on type ce qu’elle doit parcourir à savoir "vecteur de XXX". La variable est du type XXX.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
> for i in 1:5 do
+    a <- a+i^2
+ endFor
> for i in 1:5 do a <- a+i^2

3.2 If else

La structure du if impose une fin de if sauf si le if tient sur une ligne.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
> if a==3 then
+     blabla
+ else 
+     blibli
+ endIf

> if a==3 then
+     blabla
+ endIf
Variante sur une ligne
> if a==3 then blabla
> if a==3 then blabla else blibli



3.3 Break et continu

Break doit pouvoir permettre de sortir de plusieurs boucles (ou structures) imbriquées. Une solution est de mettre un argument indiquant le nombre de break :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
> break(2) // sort de la premier boucle et de la deuxième
> break.continu // sort de la premier et continue la deuxième
> continu.break // n’a pas de sens => erreur
> break(2).continu // sort de deux boucles, continue la troisième.
[[[Est-ce qu’on conserve ce genre de chose ou est-ce un peu crade ? En tout cas, ca remplace bien les labels sous java.]]]



3.4 Appel des fonctions

Il faut donner le choix entre passage par valeur et par pointeur. Cela se fait dans la déclaration de la fonction. Le programmeur peut soit spécifier par valeur, soit par référence, soit ne rien spécifier du tout. S'il ne spécifie pas, c'est le compilateur qui décidera : si la variable est modifiée dans le corps de la fonction, alors la transmission était par valeur, si elle n'est pas modifié, elle était par référence.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
integer toto <- function (integer ref x, integer val y, integer z)
   z <- x+y
   return z
endFunction

integer titi <- function (integer ref x, integer val y, integer z)
   x <- z+y
   return x
endFunction
Dans cet exemple, z pour toto est passé par valeur, z pour titi est passé par référence.

3.5 Virgule finale (en vert, ce qui a été rendu obsolète par un autre point, ou par une réponse)

On autorise-t-on une virgule (ou point virgule si la virgule devient point virgule) après le dernier élément d’une énumération. Ca peut être pratique dans certains cas (quand on commente ou qu’on intervertir l’ordre) de ne pas avoir a ajouter ou supprimer cette virgule de la dernière ligne :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
switch
  case(x>3) : blabla
  case(x<1) : blabla
  case(x>2) : blabla
endSwitch




3.6 Virgule et plus

ATTENTION : la virgule doit avoir un sens unique. Dans R, elle sépare les arguments mais elle est aussi utilisée pour une liste. Ainsi mean(1,2) ne fonctionne pas car 2 est en fait le deuxième argument.
Il faut donc deux séparateurs distincts, un pour les arguments et un pour les listes. Cela pourrait être :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
> mean(1,2,3;na.rm=true)
> plot(1,2,3; col=2,4; ltype="l")
Dans cette optique, le ‘ ;’ n’est plus un séparateur d’instruction. Le séparateur d’instruction peut être ‘;;’. Rappel, dans tous les cas, le ‘ ;’ de fin de ligne n’est plus obligatoire.

L’autre solution serait de mettre les listes entre accolade ou parenthèses :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
> mean((1,3,2),na.rm=true)  // alternative

3.7 Operateur ‘?’

Code : Sélectionner tout - Visualiser dans une fenêtre à part
expression-booléenne ? valeur0 : valeur1
peut être généralisé à

Code : Sélectionner tout - Visualiser dans une fenêtre à part
expression-integer ? valeur0 : valeur1 : valeur2 : valeur3

3.8 Opérateur + (et autre)

Il faut pouvoir les redéfinir (contrairement à Java qui ne le permet pas).


3.9 Return

Impose-t-on le return en fin de fonction ? Impose-t-on return void pour les fonctions qui ne retournent aucun argument ?


3.10 Switch

Plusieurs version du switch. Le switch "classique" est :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
switch toto is 
   case "E" then blabla
   case "F" then blabla
   else blabla
finSwitch
Pas besoin de finCase en fin de ligne (ou de break) car le ‘case’ suivant, ou le ‘default’ en fait office. Le fonctionnement de ce premier switch est le suivant : des que la valeur de toto correspond à un case, les instructions correspondantes sont exécutées, puis le switch se termine (comme s'il y avait un break en java).

On peut aussi supprimer l’argument de switch si on utilise que des case avec conditions complètes :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
switch 
   case toto=="E" then blabla
   case toto==”G” and titi>6 then bloblo
   case titi>3 then blibli
   else blublu
finSwitch
Deux autres switch sont disponibles :

  • SwitchAll est un switch ou toutes les conditions vraies sont exécutées. Dans le code précédent, si toto vaut "E" et titi vaut 5, alors blabla et bloblo seront exécutés.
  • SwitchCont est un switch ou si une condition est vraie, toutes suivantes sont exécutées.Dans le code précédent, si toto vaut "E", alors blabla, bloblo et blibli sont exécuté (mais pas le else)





3.11 Portée des variables

Interdiction de déclarer une variable déjà existante. Ainsi :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
> int i=2
i.m()
if(){
  float i=3.0
  i.m()
}else{}
n’est pas possible (contrairement à C ou le deuxième i cache le premier dans le block, puis disparait quand on en sort).

Note : le polymorphisme permet de déclarer la méthode m() sur des int mais également sur des float. Du coup, dans le code précédent, l’interprétation de i.m() est dynamique car elle dépend du type de i. Si on interdit d’utiliser i deux fois, alors le problème ne se pose plus :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
int i1=2
i1.m()
if(){
  float i2=3.0
  i2.m()
}else{}
i1.m() fera appel à la méthode m() pour int alors que i2.m() fera appel à la méthode m() pour float.

Pour les fonctions, le problème se pose :
int i=2
f <- function(){
float i=3.0
i.m()
}

Mais on pourrait décider qu’un pré-processeur recode les noms des variables en « nom-de-la-fonction_non-de-la-variable ». Dans notre cas, le code :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
i <- 2
i.m()
void f <- function(){
  i <- 3.0
  i.m()
}
serait transformé en :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
i <- 2
i.m()
void f <- function(){
  f_i <- 3.0
  f_i.m()
}


3.12 Egal

Pas de '=' en R++ (à moyen terme. Au départ, il sera accepté avec un Warning) sauf dans les appels de fonction.
  • L’affectation par copie (intuitive) se fera via ‘<-‘
  • L’affectation par référence (économique mais plus difficile à manipuler) se fera via ‘<<-‘
  • l’opérateur d’égalité sera ‘==’


On pourrait envisager de définir A<-*3 (ou A<* 3 ?) , B<-+5 (ou B<+ 5 ?) qui serait équivalent a A<-A*3 ou B<-B+5. Mais ce genre de notation rend le code moins lisible. Donc a priori, non.

Enfin, autorise-t-on les <- en cascade ?


3.13 Affectation

Il est important que l’affectation par défaut soit par copie. Sinon, on risque d’avoir :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
> y <- 3
> x <- 5
> y <- x # affectation par valeur
> x <- 8
> print(y)
[1] 8 # On veut 5 !!!
Par contre :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
> y <- 3
> z <- 2
> x <- 5
> y <- x  # affectation par référence
> z <<- x # affectation par valeur
> x <- 8
> print(y)
[1] 5     # car y est une variable différente de x
> print(z)
[1] 8     # car z est pointe la même chose que x
Concernant la comparaison ‘==’, elle renvoie généralement faux (en C, en R et en Java) si les champs sont égaux mais que les adresses des objets pointés sont différentes. Il serait mieux de faire l’inverse (c’est souvent ce que l’utilisateur veut quand il tape ==). Pour les égalités strictes, on définit l'opérateur ‘===’.

Au final :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
> y <- Toto(3) // y est de type Toto et contient 3
> x <- y       // x est de type Toto, contient 3 mais est différent de Y
> x==y         // égalité de contenu
[1] true
> x===y        // égalité stricte
[1] false

3.14 Fonctions

Il faut conserver la possibilité d’écrire des fonctions qui ne seront pas spécifiquement attacher à un objet et qui s'utiliseront comme des fonctions (c'est a dire f(toto) et non pas toto.f()). On pourrait décider que ces fonctions sont des méthodes de la classe Objet (la classe dont hérite toutes les classes).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
> numeric f <- function(numeric x) x^3+3x^2+5x-1
> plot(1:10,f(1:10))