• Non ci sono risultati.

Petit Manuel de S4

N/A
N/A
Protected

Academic year: 2021

Condividi "Petit Manuel de S4"

Copied!
100
0
0

Testo completo

(1)

Petit Manuel de S4

Programmation Orient´ e Objet sous R

Christophe Genolini

(2)

2

(3)

3

Qu’allez-vous trouver dans ce manuel ?

Ce livre est un guide ` a la programmation objet sous R (ou S4). Il ne n´ ecessite pas de connaˆıtre la programmation orient´ ee objet. Par contre, un minimum de connaissances sur R et sur la programmation en g´ en´ eral est requis. Pour ceux qui sont totalement d´ ebutants en R, nous vous recommandons “R pour les D´ ebutants”, d’Emmanuel Paradis [4].

Le pr´ esent manuel est d´ ecoup´ e en quatre parties. Apr` es une introduction g´ en´ erale sur la programmation objet (section 1) et une d´ efinition un peu plus formelle (section 2), un exemple est pr´ esent´ e (section 3). Grave probl` eme que celui du choix de l’exemple : les exemples r´ eels sont trop compliqu´ es. Les artificiels sont inint´ eressants. Nous allons donc utiliser une simplification d’un probl` eme r´ eel ayant donn´ e lieu ` a la construction d’un package (package kml). Il nous accompagnera tout au long de ce livre pour finir sous forme d’un package appel´ e miniKml disponible sur le site du CRAN.

La deuxi` eme partie pr´ esente les bases de la programmation objet. Chaque ´ el´ ement nouvellement introduit est ajout´ e aux pr´ ec´ edents et permet au package de prendre corps.

C’est l` a que sont pr´ esent´ es les ´ el´ ements fondamentaux de la programmation S4. Cette partie est simple, r´ edig´ ee pour les d´ ebutants, mais indispensable pour comprendre la programmation objet en S. Les sections 4, 5, 6, 7 doivent se lire pr´ ef´ erentiellement dans l’ordre.

Dans la troisi` eme partie sont abord´ es des sujets plus subtils, comme les signatures complexes (section 8), l’h´ eritable (section 9) ou la super assignation pour modification interne d’un objet (section 10). Elles ne sont pas indispensables ` a la programmation objet, on peut lire l’une sans l’autre et surtout les omettre en premi` ere lecture. Cela d´ epend ensuite des besoins de chacun.

En esp´ erant que ce livre fera naitre de nombreux package S4,

bonne lecture !

(4)

4

(5)

Table des mati` eres

I Pr´ eliminaires 9

1 Introduction 11

1.1 Qu’est-ce que “S4”? . . . . 11

1.2 Qu’est-ce que la programmation objet ? . . . . 11

1.3 Pourquoi faire de l’objet ? . . . . 11

1.3.1 Programmation classique . . . . 12

1.3.2 Programmation objet . . . . 13

1.4 Pour r´ esumer . . . . 15

1.5 Devez-vous vous mettre ` a l’objet ? . . . . 15

1.6 Le cˆ ot´ e obscur de la programmation . . . . 16

1.6.1 D’accord, pas d’accord . . . . 16

1.6.2 Les fus´ ees, la bourse, les bugs... et les coupables ! . . . . 16

1.6.3 R, langage propre ? . . . . 17

2 G´ en´ eralit´ es sur les objets 19 2.1 D´ efinition formelle . . . . 19

2.1.1 Les attributs . . . . 19

2.1.2 Les m´ ethodes . . . . 19

2.2 Dessiner, c’est gagner ! . . . . 20

3 Exemple de travail 21 3.1 Analyse du probl` eme . . . . 22

3.2 L’objet Trajectoires . . . . 22

3.3 L’objet Partition . . . . 23

3.4 L’objet TrajDecoupees . . . . 23

3.5 Plan d’analyse . . . . 24

3.6 Application ` a R . . . . 25

II Les bases de l’objet 27 4 D´ eclaration des classes 29 4.1 D´ efinition des attributs . . . . 29

5

(6)

6 TABLE DES MATI ` ERES

4.2 Constructeur par d´ efaut . . . . 30

4.3 Acc´ eder aux attributs . . . . 31

4.4 Valeurs par d´ efaut . . . . 32

4.5 Supprimer un objet . . . . 32

4.6 L’objet vide . . . . 33

4.7 Voir l’objet . . . . 34

5 Les m´ ethodes 35 5.1 setMethod . . . . 35

5.2 show et print . . . . 37

5.3 setGeneric . . . . 39

5.3.1 G´ en´ erique versus Sp´ ecifique . . . . 39

5.3.2 D´ efinition formelle . . . . 40

5.3.3 lockBinding . . . . 40

5.3.4 D´ eclaration des g´ en´ eriques . . . . 41

5.4 Voir les m´ ethodes . . . . 41

6 Construction 43 6.1 V´ erificateur . . . . 43

6.2 L’initiateur . . . . 45

6.3 Constructeur grand public . . . . 48

6.4 Petit bilan . . . . 50

7 Accesseur 53 7.1 Les getteurs . . . . 53

7.2 Les setteurs . . . . 55

7.3 Les op´ erateurs [ et [<- . . . . 56

7.4 [, @ ou get ? . . . . 58

III Pour aller plus loin 59 8 M´ ethodes utilisant plusieurs arguments 63 8.1 Le probl` eme . . . . 63

8.2 signature . . . . 64

8.3 missing . . . . 67

8.4 Nombre d’arguments d’une signature . . . . 68

8.5 ANY . . . . 68

9 H´ eritage 69 9.1 Principe . . . . 69

9.2 P` ere, grand-p` ere et ANY . . . . 70

9.3 contains . . . . 70

9.4 unclass . . . . 71

(7)

TABLE DES MATI ` ERES 7

9.5 Arbre d’h´ eritage . . . . 72

9.6 Voir la m´ ethode en autorisant l’h´ eritage . . . . 72

9.7 callNextMethod . . . . 75

9.8 is, as et as<- . . . . 77

9.9 setIs . . . . 78

9.10 Les classes virtuelles . . . . 80

9.11 Pour les dyslexiques... . . . 82

10 Modification interne d’un objet 83 10.1 Fonctionnement interne de R : les environnements . . . . 83

10.2 M´ ethode pour modifier un attribut . . . . 84

IV Annexes 87 A Remerciements 89 A.1 Nous vivons une ´ epoque formidable . . . . 89

A.2 Ceux par qui ce tutorial existe... . . . . 89

B M´ emo 91 B.1 Cr´ eation . . . . 91

B.2 Validation . . . . 91

B.3 Accesseur . . . . 92

B.4 M´ ethodes . . . . 92

B.5 Quelques fonctions incontournables . . . . 92

B.6 Voir la structure des objets . . . . 92

C Pour aller plus loin 95

Liste des tables et figures 96

Bibliographie 97

Index 98

(8)

8 TABLE DES MATI ` ERES

(9)

Premi` ere partie

Pr´ eliminaires

9

(10)
(11)

Chapitre 1

Introduction

1.1 Qu’est-ce que “S4”?

S4 est la quatri` eme version de S. S est un langage qui a deux impl´ ementations : S-plus est commerciale, R est gratuite. La particularit´ e de S4 par rapport au S3 est l’apparition de fonctions qui permettent de consid´ erer S-plus comme un langage objet 1 . Par extension, S4 d´ esigne la programmation orient´ ee objet sous S. Et donc sous R et sous S-plus.

1.2 Qu’est-ce que la programmation objet ?

Un objet est un ensemble de variables et de fonctions qui concernent toutes le mˆ eme th` eme : l’objet lui-mˆ eme. Pas tr` es clair ? Prenons un exemple : un objet image contien- dra :

– Les variables qui permettent de d´ efinir une image (comme la taille de l’image, son mode de compression, l’image proprement dite) ;

– les fonctions utilis´ ees pour la manipulation de l’image (comme noirEtBlanc() ou redimentionner()).

Si vous ˆ etes compl` etement d´ ebutant en objet et que tout ¸ ca n’est pas limpide, ne vous inqui´ etez pas, de nombreux exemples vont suivre.

1.3 Pourquoi faire de l’objet ?

Pour le n´ eophyte, la programmation objet est quelque chose de lourd et les avantages ne semblent pas ´ evidents : il faut penser son programme ` a l’avance, mod´ eliser le probl` eme, choisir ses types, penser aux liens qui lieront les objets entre eux... Que des inconv´ enients.

D’o` u la question l´ egitime : pourquoi faire de l’objet ?

1. permettent de consid´ erer et non pas transforment en. En tout ´ etat de cause, R N’est PAS un langage objet, il reste un langage interpr´ et´ e classique avec une surcouche possible. A quand R++ ?

11

(12)

12 CHAPITRE 1. INTRODUCTION 1.3.1 Programmation classique

Le plus simple est de prendre un exemple et de comparer la programmation classique ` a la programmation objet. L’IMC, l’Indice de Masse Corporelle est une mesure de maigreur ou d’ob´ esit´ e. On le calcule en divisant le poids (en kilo) par la taille au carr´ e. Ensuite, on conclut :

– 20 < IMC < 25 : tout roule pour vous – 25 < IMC < 30 : Nounours

– 30 < IMC < 40 : Nounours confortable

– 40 < IMC : M´ ega nounours, avec effet double douceur, mais qui devrait tout de mˆ eme aller voir un m´ edecin tr` es vite...

– 18 < IMC < 20 : Barbie

– 16 < IMC < 18 : Barbie mannequin

– IMC < 16 : Barbie squelette, mˆ eme diagnostic que le M´ ega nounours, attention danger...

On veut donc calculer l’IMC. En programmation classique, rien de plus simple :

> # ## P r o g r a m m a t i o n c l a s s i q u e , IMC

> p o i d s < - 85

> t a i l l e <- 1.8 4

> ( IMC <- p o i d s / t a i l l e ^2) [1] 2 5 . 1 0 6 3 3

Jusqu’` a l` a, rien de tr` es myst´ erieux. Si vous voulez calculer pour deux personnes Moi et Elle, vous aurez

> # ## P r o g r a m m a t i o n c l a s s i q u e , mon IMC

> p o i d s M o i < - 85

> t a i l l e M o i <- 1. 84

> ( I M C m o i <- p o i d s M o i / t a i l l e M o i ^2) [1] 2 5 . 1 0 6 3 3

> # ## P r o g r a m m a t i o n c l a s s i q u e , son IMC

> p o i d s E l l e <- 62

> t a i l l e E l l e < - 1 .60

> ( I M C e l l e < - p o i d s M o i / t a i l l e E l l e ^2) [1] 3 3 . 2 0 3 1 2

¸

Ca marche... sauf qu’Elle est qualifi´ ee de “Nounours confortable” (ou “Nounoursette”

dans son cas) alors que son poids ne parait pas sp´ ecialement excessif. Un petit coup d’oeil

au code r´ ev` ele assez vite une erreur : le calcul de IMCelle est faux, nous avons divis´ e

poidsMoi par tailleElle au lieu de poidsElle par tailleElle. Naturellement, R n’a

pas d´ etect´ e d’erreur : de son point de vue, il a juste effectu´ e une division entre deux

numeric.

(13)

1.3. POURQUOI FAIRE DE L’OBJET ? 13 1.3.2 Programmation objet

. En langage objet, la d´ emarche est tout autre. Il faut commencer par d´ efinir un objet IMC qui contiendra deux valeurs, poids et taille. Ensuite, il faut d´ efinir la fonction print qui affichera l’IMC 2

> # ## D ´ e f i n i t i o n d ' un objet IMC

> s e t C l a s s ( " IMC " , r e p r e s e n t a t i o n ( p o i d s = " n u m e r i c " , t a i l l e = " n u m e r i c " )) [1] " IMC "

> setMethod( " s how " , " IMC " ,

+ fu ncti on ( object ){

+ cat ( " IMC = " , o b j e c t @ p o i d s / ( o b j e c t @ t a i l l e ^2) , " \ n " )

+ }

+ )

[1] " s how "

Le code ´ equivalent ` a ce qui a ´ et´ e fait dans la section 1.3.1 page 12 est alors :

> # ## C r ´ e a t i o n d ' un objet pour moi , et affichage de mon IMC

> ( m o n I M C <- new( " IMC " , p o i d s =85 , t a i l l e = 1 . 8 4 ) ) IMC = 2 5 . 1 0 6 3 3

> # ## C r ´ e a t i o n d ' un objet pour elle , et affichage de son IMC

> ( s o n I M C <- new( " IMC " , p o i d s =62 , t a i l l e = 1 . 6 0 ) ) IMC = 2 4 . 2 1 8 7 5

A partir du moment o` ´ u l’initialisation est correcte (probl` eme qui se posait ´ egalement dans la programmation classique), il n’y a plus d’erreur possible. L` a est toute la force de l’objet : la conception mˆ eme du programme interdit un certain nombre de bug.

Typage : l’objet prot` ege ´ egalement des erreurs de typage, c’est ` a dire les erreurs qui consistent ` a utiliser un type l` a o` u il faudrait en utiliser un autre. Une erreur de typage, c’est un peu comme additionner des pommes et des kilom` etres au lieu d’additionner des pommes et des pommes.

Concr` etement, une variable nomm´ ee poids est con¸cue pour contenir un poids, c’est

`

a dire un nombre, et non une chaˆıne de caract` eres. En programmation classique (pas de typage), poids peut contenir n’importe quoi :

> # ## P r o g r a m m a t i o n c l a s s i q u e , pas de t y p a g e

> ( p o i d s <- " B o n j o u r " ) [1] " B o n j o u r "

2. Pour que notre exemple illustratif soit reproductible imm´ ediatement, nous avons besoin de d´ efinir

ici un objet. Nous le faisons sans explication, mais naturellement, tout cela sera repris ensuite avec moults

d´ etails.

(14)

14 CHAPITRE 1. INTRODUCTION En programmation objet, affecter "bonjour" ` a une variable qui devrait contenir un nombre provoquera une erreur :

> new( " IMC " , p o i d s = " B o n j o u r " , t a i l l e = 1 . 8 4 ) E r r o r in v a l i d O b j e c t (. O b j e c t ) :

i n v a l i d c l a s s " IMC " o b j e c t :

i n v a l i d o b j e c t for slo t " p o i d s " in c l a s s " IMC " : got c l a s s

" c h a r a c t e r " , s h o u l d be or e x t e n d c l a s s " n u m e r i c "

V´ erificateurs : L’objet permet de construire des v´ erificateurs de coh´ erence pour, par exemple, interdire certaines valeurs. En programmation classique, une taille peut ˆ etre n´ egative :

> # ## P r o g r a m m a t i o n c l a s s i q u e , pas de c o n t r ^ o l e

> ( T a i l l e M o i < - -1.84)

[1] -1.84

En programmation objet, on peut pr´ eciser que les tailles n´ egatives n’existent pas :

> # ## P r o g r a m m a t i o n objet , c o n t r ^ o l e

> s e t V a l i d i t y ( " IMC " ,

+ fu ncti on ( object ){

+ i f ( object@taille <0){

+ return ( " Taille n ´ e g a t i v e " )

+ } e l s e {

+ return (TRUE)

+ }

+ }

+ )

C l a s s " IMC " [ in " . G l o b a l E n v " ] S l o t s :

Na me : p o i d s t a i l l e C l a s s : n u m e r i c n u m e r i c

> new( " IMC " , p o i d s =85 , t a i l l e = -1.84) E r r o r in v a l i d O b j e c t (. O b j e c t ) :

i n v a l i d c l a s s " IMC " o b j e c t : T a i l l e n ´ e g a t i v e

H´ eritage : la programmation objet permet de d´ efinir un objet comme h´ eritier des

propri´ et´ es d’un autre objet, devenant ainsi son fils. L’objet fils b´ en´ eficie ainsi de tout

ce qui existe pour l’objet . Par exemple, on souhaite affiner un peu nos diagnostics en

fonction du sexe de la personne. Nous allons donc d´ efinir un nouvel objet, IMCplus, qui

contiendra trois valeurs : poids, taille et sexe. Les deux premi` eres variables sont les

(15)

1.4. POUR R ´ ESUMER 15 mˆ emes que celle de l’objet IMC. Nous allons donc d´ efinir l’objet IMCplus comme h´ eritier de l’objet IMC. Il pourra ainsi b´ en´ eficier de la fonction show telle que nous l’avons d´ efinie pour IMC et cela, sans aucun travail suppl´ ementaire, puisque IMCplus h´ erite de IMC :

> # ## D ´ e f i n i t i o n de l ' h´eritier

> s e t C l a s s ( " I M C p l u s " ,

+ r e p r e s e n t a t i o n ( sexe = " c h a r a c t e r " ) , + contains = " IMC "

+ )

[1] " I M C p l u s "

> # ## C r ´ e a t i o n d ' un objet

> lui < - new( " I M C p l u s " , t a i l l e =1.76 , p o i d s =84 , s exe = " H o m m e " )

> # ## A f f i c h a g e qui u t i l i s e ce qui a ´ et´ e d ´ e f i n i po ur `IMC '

> lui

IMC = 2 7 . 1 1 7 7 7

La puissance de cette caract´ eristique apparaitra plus clairement section 9 page 69.

Encapsulation : enfin, la programmation objet permet de d´ efinir tous les outils composant un objet et de les enfermer dans une boite, puis de ne plus avoir ` a s’en occuper.

Cela s’appelle l’encapsulation. Les voitures fournissent un bon exemple d’encapsulation : une fois le capot referm´ e, on n’a plus besoin de connaˆıtre les d´ etails de la m´ ecanique pour rouler. De mˆ eme, une fois l’objet termin´ e et referm´ e, un utilisateur n’a pas ` a s’inqui´ eter de son fonctionnement interne. Mieux, concernant les voitures, il n’est pas possible de se tromper et de mettre de l’essence dans le radiateur puisque le radiateur n’est pas accessible. De mˆ eme, l’encapsulation permet de prot´ eger ce qui doit l’ˆ etre en ne laissant accessible que ce qui ne risque rien.

1.4 Pour r´ esumer

La programmation objet “force” le programmeur ` a avoir une r´ eflexion pr´ eliminaire.

On a moins la possibilit´ e de programmer “` a la va-vite”; un plan de programme est quasi indispensable. En particulier :

– Les objets doivent ˆ etre d´ eclar´ es et typ´ es.

– Des m´ ecanismes de contrˆ ole permettent de v´ erifier la coh´ erence interne des objets.

– Un objet peut h´ eriter des propri´ et´ es qui ont ´ et´ e d´ efinies pour un autre objet.

– Enfin, l’objet permet une encapsulation du programme : une fois qu’on a d´ efini un objet et les fonctions qui s’y rattachent, on n’a plus besoin de s’occuper de la cuisine interne de l’objet.

1.5 Devez-vous vous mettre ` a l’objet ?

Nous venons de le voir, la programmation objet a des avantages, mais elle a aussi

des inconv´ enients. En premier lieu, elle n’est pas facile ` a apprendre et on trouve assez

(16)

16 CHAPITRE 1. INTRODUCTION peu de tutoriaux disponibles (c’est d’ailleurs ce vide qui a donn´ e naissance au pr´ esent ouvrage). Ensuite, la mise en route d’un projet est passablement plus lourde ` a g´ erer qu’en programmation classique o` u tout peut se faire petit ` a petit. Se pose donc la l´ egitime question : doit-on ou ne doit-on pas faire de l’objet ?

– Pour la petite programmation de tous les jours, un nettoyage des donn´ ees, une analyse univari´ ee/bivari´ ee, une r´ egression, tous les outils existent d´ ej` a, pas besoin de S4.

– Pour les projets un peu plus importants, quand vous travaillez sur un nouveau concept, sur des donn´ ees complexes d´ epassant le simple cadre du numeric et fac- tor, alors l’objet devient une force : plus difficile au d´ epart, mais bien moins buggu´ e et plus facilement manipulable ` a l’arriv´ ee.

– Enfin, la construction d’un package devrait toujours ˆ etre r´ efl´ echie et structur´ ee.

Dans ce cadre, la programmation objet est conseill´ ee.

1.6 Le cˆ ot´ e obscur de la programmation

Pour terminer avec cette longue introduction, une petite digression.

1.6.1 D’accord, pas d’accord

Vous ˆ etes en train de lire un manuel de programmation objet. Vous ˆ etes en train d’apprendre une nouvelle m´ ethode. Sachez qu’il n’existe pas “une” mais “des” mani` eres de programmer : ` a ce sujet, les informaticiens ne sont pas toujours d’accord entre eux.

Ce livre suit une certaine vision, celle de son auteur. Des gens tr` es comp´ etents sont d’accord, d’autres le sont moins... Y a-t-il une v´ erit´ e et si oui, o` u se trouve-t-elle ? Mys- t` ere. N´ eanmoins, pour essayer de donner une vision la plus large possible, il arrivera que ce livre vous pr´ esente plusieurs points de vue, celui de l’auteur, mais aussi celui de lecteurs qui ont r´ eagi ` a ce qu’ils lisaient et qui ont fait valoir une autre vision des choses.

Ainsi, lecteur avis´ e, vous aurez tous les ´ el´ ements en main, vous pourrez peser le pour et le contre

et vous choisirez votre voie en toute libert´ e,

`

a la lumi` ere de la connaissance...

1.6.2 Les fus´ ees, la bourse, les bugs... et les coupables !

Quand les hommes ont commenc´ e ` a envoyer des fus´ ees dans l’espace 3 et qu’elles ont explos´ e en plein vol, ils ont ´ ecras´ e une petite larme et ont cherch´ e les causes de l’´ echec.

Comme il fallait bien brˆ uler quelqu’un, ils ont cherch´ e un coupable. Et ils ont trouv´ e... les informaticiens. “C’est pas d’not’ faute, ont d´ eclar´ e les informaticiens tout marris, c’est un fait av´ er´ e intrins` eque aux ordinateurs : tous les programmes sont buggu´ es !” Sauf que dans le cas pr´ esent, la facture du bug ´ etait plutˆ ot sal´ ee...

3. Ou quand ils ont confi´ e la bourse, les hˆ opitaux, les fiches de paye...aux ordinateurs.

(17)

1.6. LE C ˆ OT ´ E OBSCUR DE LA PROGRAMMATION 17 Des gens tr` es forts et tr` es intelligents ont donc cherch´ e des moyens de rendre la pro- grammation moins buggu´ ee. Ils ont fabriqu´ e des nouveaux langages et d´ efini des r` egles de programmation. On appelle ¸ca la programmation propre ou les bonnes pratiques. Vous trouverez une proposition de bonnes pratiques en annexe section ?? page ??. Certaines op´ erations, certaines pratiques, certaines mani` eres de programmer sont donc qualifi´ ees de bonnes, belles ou propres ; d’autres au rebours sont qualifi´ es de mauvaises, dangereuses, impropres voire sales (Le terme exact consacr´ e par les informaticiens est crade...) Il ne s’agit pas l` a de jugements de valeur, ce sont simplement des qualificatifs qui indiquent que ce type de programmation favorise l’apparition d’erreurs dans le code. Donc ` a ´ eviter d’urgence.

1.6.3 R, langage propre ?

R n’est pas un langage tr` es propre. Quand un informaticien veut ajouter un package, il est libre de faire ` a peut pr` es ce qu’il veut (ce qui est une grande force) y compris la d´ efinition d’instructions “surprenantes” (ce qui est une faiblesse). Une instruction “surprenante” est une instruction dont le fonctionnement est contraire ` a l’intuition. Par exemple, sachant que numeric() d´ esigne un numeric vide et que integer() est en entier vide, comment d´ esigner une matrice vide ? Toute d´ efinition autre que matrix() serait surprenante. De nombreuses surprises existent dans R... (Voir la section 4.6 page 33 pour plus de d´ etails sur les objets vides). R permet donc de faire tout un tas d’op´ erations dangereuses. Il sera n´ eanmoins parfois possible de le rendre propre en nous auto-interdisant des manipulations. Mais ¸ ca ne sera pas toujours le cas, nous serons amen´ es ` a utiliser des outils impropres. En tout ´ etat de cause, les passages dangereux seront signal´ es par le petit logo qui orne le d´ ebut de ce paragraphe.

Mais tout le monde ne partage pas ce point de vue : “On a n´ eanmoins besoin des langages ultra-flexibles et peu contraints, pr´ ecise un relecteur, parce qu’ils rendent cer- taines applications faciles ` a programmer alors que les langages propres ne les g` erent pas ou mal. Dans ce genre de cas, utiliser un langage propre revient un peu ` a prendre un marteau-piqueur pour ´ ecraser une noix. En particulier, ´ ecrire le coeur d’un programme en C (au lieu de R) peut accroitre la rapidit´ e d’ex´ ecution par un facteur 10 ou 20.”

C’est vrai. Mais tout d´ epend du niveau du programmeur : ` a haut niveau, pour ceux qui ne font pas d’erreur, l’efficacit´ e peut primer sur la propret´ e. A notre niveau, il me pa- rait surtout important de programmer proprement pour r´ esoudre le probl` eme principal : programmer sans bug.

En vous souhaitant de ne jamais tomber

du cˆ ot´ e obscur de la programmation...

(18)

18 CHAPITRE 1. INTRODUCTION

(19)

Chapitre 2

G´ en´ eralit´ es sur les objets

2.1 D´ efinition formelle

Un objet est un ensemble coh´ erent de variables et de fonctions qui tournent autour d’un concept central. Formellement, un objet est d´ efini par trois ´ el´ ements :

– La classe est le nom de l’objet. C’est aussi son architecture, la liste de variables et de fonctions qui le compose.

– Les variables de l’objet sont appel´ ees attributs.

– Les fonctions de l’objet sont appel´ ees m´ ethodes.

Dans l’introduction, nous avions d´ efini un objet de classe IMC. Il avait pour attributs poids et taille, pour m´ ethode show.

2.1.1 Les attributs

Les attributs sont simplement des variables typ´ ees. Une variable typ´ ee est une variable dont on a fix´ e la nature une bonne fois pour toutes. Dans R, on peut ´ ecrire poids <- 62 (` a ce stade, poids est un numeric) puis poids <- "bonjour" (poids est devenu un character). Le type de la variable poids peut changer.

En programmation objet, il ne sera pas possible de changer le type des attributs en cours de programmation 1 . Cela semble ˆ etre une contrainte, c’est en fait une s´ ecurit´ e. En effet, si une variable a ´ et´ e cr´ e´ ee pour contenir un poids, elle n’a aucune raison de recevoir une chaˆıne de caract` eres... sauf erreur de programmation.

2.1.2 Les m´ ethodes

On distingue 4 types d’op´ erations ` a faire sur les objets :

– M´ ethodes de cr´ eation : entrent dans cette cat´ egorie toutes les m´ ethodes per- mettant de cr´ eer un objet. La plus importante s’appelle le constructeur. Mais son utilisation est un peu rugueuse pour l’utilisateur. Le programmeur ´ ecrit donc des

1. H´ elas, avec R et la S4, c’est possible. Mais comme c’est sans doute l’op´ eration la plus impropre de toute l’histoire de l’informatique, nous pr´ ef´ erons “oublier” et faire comme si ¸ ca ne l’´ etait pas.

19

(20)

20 CHAPITRE 2. G ´ EN ´ ERALIT ´ ES SUR LES OBJETS m´ ethodes faciles d’acc` es pour cr´ eer un objet ` a partir de donn´ ees, d’un fichier ou ` a partir d’un autre objet (par exemple numeric ou read.csv2).

– Validation : en programmation objet, il est possible de v´ erifier que les attributs respectent certaines contraintes. Il est ´ egalement possible de cr´ eer des attributs ` a partir de calculs faits sur les autres attributs. Tout cela rentre dans la validation d’objet.

– Manipulation des attributs : modifier et lire les attributs n’est pas aussi anodin que dans la programmation classique. Aussi, d´ edie-t-on des m´ ethodes ` a la mani- pulation des attributs (par exemple names et names<-).

– Autres : tout ce qui pr´ ec` ede constitue une sorte de “minimum l´ egal” ` a programmer pour chaque objet. Reste ensuite les m´ ethodes sp´ ecifiques ` a l’objet, en particulier les m´ ethodes d’affichage et les m´ ethodes effectuant des calculs.

Les m´ ethodes sont des fonctions typ´ ees. Le type d’une fonction est la juxtaposition de deux types : son type entr´ ee et son type sortie.

– Le type-entr´ ee est simplement l’ensemble des types des arguments de la fonction.

Par exemple, la fonction trace prend pour argument une matrice, son type-entr´ ee est donc matrix.

– Le type-sortie est le type de ce que la fonction retourne. Par exemple, la fonction trace retourne un nombre, son type-sortie est donc numeric.

Au final, le type d’une fonction est (type-entree,type-sortie). On le note Type- Sortie <- fonction(TypeEntree).

Par exemple, le type de la fonction trace est numeric <- trace(matrix).

2.2 Dessiner, c’est gagner !

Il vaut mieux un bon dessin qu’un long discours. La maxime s’applique particuli` e- rement bien ` a la programmation objet. Chaque classe est repr´ esent´ ee par un rectangle dans lequel sont not´ es les attributs et les m´ ethodes avec leur type.

L’h´ eritage (voir section 9 page 69) entre deux classes est not´ e par une fl` eche, du fils

vers le p` ere.

(21)

Chapitre 3

Exemple de travail

Plutˆ ot que d’inventer un exemple avec des ‘wiz’, des ‘spoun’ ou des concepts ma- th´ ematiques complexes truff´ es d’´ equations, voil` a un cas r´ eel (fortement simplifi´ e, mais r´ eel) : la doctoresse Tam travaille sur des patientes anorexiques. Semaine apr` es semaine, elle mesure leur IMC (exemple 17, puis 17.2, puis 17.1, puis 17.4). Pour une patiente, la suite obtenue forme une trajectoire (exemple (17, 17.3, 17.2, 17.4)). Graphi- quement, on obtient :

1 2 3 4

16.0 17.0 18.0

L’IMC de la demoiselle augmente progressivement. Lorsqu’on dispose de plusieurs trajectoires, les graphes deviennent illisibles :

1 2 3 4

10 14 18

D’o` u la n´ ecessit´ e, pour y voir plus clair, de regrouper les trajectoires.

21

(22)

22 CHAPITRE 3. EXEMPLE DE TRAVAIL Elle veut donc classer ses patientes en groupe selon des crit` eres bien pr´ ecis : [AGrandi] (Oui)/(Non), [DemandeAVoirSesParents] (Oui)/(Non)/(Refuse), [Re- mangeRapidement] (Oui)/(Non). Au final, son but est de comparer diff´ erentes mani` eres de regrouper les trajectoires.

3.1 Analyse du probl` eme

Ce probl` eme est d´ ecoupable en trois objets.

– Le premi` ere sera celui qui contiendra les trajectoires des patientes.

– Le deuxi` eme repr´ esentera un d´ ecoupage en groupe (que nous appellerons une par- tition).

– Le troisi` eme sera un m´ elange des deux : les trajectoires partitionn´ ees en groupe.

3.2 L’objet Trajectoires

Tam nous pr´ evient que pour un groupe donn´ e, les mesures sont faites soit toutes les semaines, soit tous les quinze jours. L’objet Trajectoires doit en tenir compte. Il sera donc d´ efini par deux attributs :

– temps : num´ ero de la semaine o` u les mesures sont effectu´ ees. Pour simplifier, la semaine o` u commence le suivi du groupe aura le num´ ero 1.

– traj : les trajectoires de poids des patientes Exemple :

temps = (1, 2, 4, 5)

traj =

15 15.1 15.2 15.2 16 15.9 16 16.4 15.2 15.2 15.3 15.3 15.7 15.6 15.8 16

Quelle(s) m´ ethode(s) pour cet objet ? Tam nous dit que dans ce genre de recherche, il y a souvent des donn´ ees manquantes. Il est important de savoir combien il y en a. Nous d´ efinirons donc une premi` ere m´ ethode qui comptera le nombre de valeurs manquantes.

La deuxi` eme m´ ethode sera ` a cheval entre les objets Trajectoires et Partition 1 : une mani` ere classique de construire une partition de groupes est de distinguer les patients selon leur IMC initial : dans notre exemple, on pourrait consid´ erer deux groupes, les “IMC initial faible” et “IMC initial haut”. Il faudra donc d´ efinir une m´ ethode de d´ ecoupage selon l’IMC initial et le nombre de groupes souhait´ e.

1. En R, ¸ ca n’a pas beaucoup d’importance mais dans un langage objet classique, chaque m´ ethode

doit obligatoirement appartenir ` a une classe et une seule. Pour nous conformer aux r` egles de l’objet,

nous inclurons donc cette m´ ethode dans Trajectoires.

(23)

3.3. L’OBJET PARTITION 23 Enfin, la pr´ esence de valeurs manquantes peut interdire l’utilisation d’outils statis- tiques. Il sera donc int´ eressant de pouvoir les imputer 2 . La troisi` eme m´ ethode imputera les manquantes.

3.3 L’objet Partition

Une partition est un ensemble de groupe. Par exemple les groupes pourraient ˆ etre A ={T1,T3} et B={T2,T4}. Il sera sans doute plus simple de les consid´ erer comme un vecteur ayant pour longueur le nombre de patientes : {A,B,A,B}. Dans un certain nombre de cas, il faudra ´ egalement connaˆıtre le nombre de groupe, en particulier quand un groupe est manquant : si Tam classe ses ados en trois groupes et qu’elle obtient la partition {A,C,C,A}, il est important de garder en m´ emoire que le groupe B existe, mˆ eme s’il ne contient personne. D’o` u deux attributs pour l’objet Partition :

– nbGroupes : donne le nombre de groupes.

– part : la suite des groupes auxquels les trajectoires appartiennent.

Exemple :

nbGroupe = 3

part =

 A B A C

Certains statisticiens (et mˆ eme certains logiciels) transforment les variables nominales en chiffres. Nous pourrions d´ efinir part comme un vecteur d’entier.

“C’est beaucoup plus pratique”, s’entend-on dire r´ eguli` erement. Sauf que ce faisant, on trompe R sur la nature de nos variables : R est con¸cu pour savoir calculer la moyenne d’une variable num´ erique, mais refuser de calculer la moyenne d’une variable nominale (un factor). Si nous codons part avec des chiffres, R acceptera de calculer la moyenne d’une partition, ce qui n’a aucun sens. ¸ Ca serait un peu comme faire la moyenne de Tortue, Girafe et Tigre... Une variable nominale doit donc ˆ etre cod´ ee par un factor, une num´ erique par un numeric. Oui, nous savons, dans certains cas, il serait un peu plus pratique de coder part par des nombres, mais c’est beaucoup plus dangereux. Donc ` a

´

eviter d’urgence !

3.4 L’objet TrajDecoupees

TrajDecoupees sera l’objet regroupant un objet Trajectoires et plusieurs Parti- tion. En effet, il est possible que pour un ensemble de trajectoires, plusieurs partition- nements soient int´ eressants. Il sera donc h´ eritier de Trajectoires. Par contre, il ne

2. L’imputation d’une valeur manquante est son remplacement par une valeur que l’on “devine” grˆ ace

aux autres valeurs... avec plus ou moins de bonheur !

(24)

24 CHAPITRE 3. EXEMPLE DE TRAVAIL sera pas h´ eritier de Partition parce que les deux classes ne partagent pas vraiment de propri´ et´ es. Pour plus de d´ etail, voir section 9 page 69.

– temps : le temps auquel les mesures sont effectu´ ees (comme dans ‘trajectoires’) – traj : les trajectoires de poids des patientes (comme dans ‘trajectoires’) – listePartitions : un ensemble de partitions.

Exemple :

temps = (1, 2, 4, 5)

traj =

15 15.1 15.2 15.2 16 15.9 16 16.4 15.2 15.2 15.3 15.3 15.5 15.6 15.8 16

listePartitions =

nbGroupe = 3

part =

 A B A C

nbGroupe = 2

part =

 A B A A

3.5 Plan d’analyse

Pour r´ esumer, nous avons donc trois classes :

(25)

3.6. APPLICATION ` A R 25 La fl` eche pleine (du fils vers le p` ere) indique l’h´ eritage, la fl` eche en pointill´ e d´ esigne l’inclusion d’un objet dans l’autre sans h´ eritage.

3.6 Application ` a R

Et R dans tout ¸ ca, seriez-vous en droit de r´ eclamer ? C’est ´ egalement une des caract´ e- ristiques des langages objets, nous avons fait une analyse relativement pouss´ ee (pouss´ ee pour un probl` eme aussi simple que le nˆ otre) et il n’y a toujours pas la moindre ligne de code R... Th´ eoriquement, on pourrait mˆ eme choisir de coder dans un autre langage.

Mais bon, l` a n’est pas le sujet du jour.

Appliqu´ ees ` a R, les m´ ethodes d´ efinies au 2.1.2 page 19 deviennent :

– M´ ethodes de cr´ eation : la m´ ethode de cr´ eation principale porte le nom de la classe.

– Validation : Cela d´ epend de l’objet.

– Manipulation des attributs : pour chaque attribut, il faudra une m´ ethode per- mettant d’acc´ eder ` a sa valeur et une m´ ethode permettant de la modifier.

– Autres : les m´ ethodes “autres” d´ ependent des particularit´ es de l’objet, ` a l’excep- tion toutefois des m´ ethodes d’affichage. Pour l’affichage, show permet un affichage sommaire de l’objet quand on tape son nom dans la console. print donne un affichage plus complet. plot est l’affichage graphique.

Pour finir avec les particularit´ es de R, la majorit´ e des langages objets forcent le programmeur ` a grouper tout ce qui concerne un objet dans un mˆ eme endroit. Cela s’appelle l’encapsulation. R n’a pas cette propri´ et´ e : vous pouvez tr` es bien d´ eclarer un objet, puis un autre, puis une m´ ethode pour le premier objet, puis d´ eclarer un troisi` eme objet, et ainsi de suite. C’est fortement d´ econseill´ e, et de surcroit facilement ´ evitable en suivant une r` egle toute simple :

A chaque objet son fichier. `

Tout ce qui concerne un objet doit ˆ etre dans un unique ficher, un fichier ne doit

contenir que des informations relatives ` a un unique objet. Cela sera repris plus en d´ etail

lors de la cr´ eation de package section ?? page ??.

(26)

26 CHAPITRE 3. EXEMPLE DE TRAVAIL

(27)

Deuxi` eme partie

Les bases de l’objet

27

(28)
(29)

Chapitre 4

D´ eclaration des classes

Nous l’avons ´ evoqu´ e dans les chapitres pr´ ec´ edents, une classe est un ensemble d’at- tributs et de m´ ethodes. Nous allons maintenant d´ efinir les uns et les autres.

Dans la majorit´ e des langages objets, la d´ efinition de l’objet contient les attributs et les m´ ethodes. En R, la d´ efinition ne contient que les attributs.

Les m´ ethodes sont pr´ ecis´ ees ensuite. C’est dommage, ¸ ca att´ enue la puissance de l’encapsulation, mais c’est comme ¸ ca. L’utilisateur averti (c’est ` a dire vous) peut compenser “manuellement”, par exemple en se for¸ cant ` a d´ efinir attributs et m´ ethodes en bloc dans un mˆ eme fichier, et en utilisant un fichier par objet.

Plus de conseils sur l’art de bien encapsuler section ?? page ??.

4.1 D´ efinition des attributs

La premi` ere ´ etape est de d´ efinir les attributs de l’objet proprement dit. Cela se fait

`

a l’aide de l’instruction setClass. setClass est une fonction qui prend deux arguments (et quelques autres ingr´ edients que nous verrons plus tard).

– Class (avec une majuscule) est le nom de la classe que nous sommes en train de d´ efinir.

– representation est la liste des attributs de la classe.

Comme nous l’avons vu dans l’exemple introductif, la programmation objet fait du contrˆ ole de type, c’est ` a dire qu’elle ne permettra pas ` a une chaˆıne de caract` eres d’ˆ etre rang´ ee l` a o` u devrait se trouver en entier. Chaque attribut doit ˆ etre d´ eclar´ e avec son type.

> s e t C l a s s (

+ Class = " T r a j e c t o i r e s " ,

+ r e p r e s e n t a t i o n = representation ( + t e m p s = " n u m e r i c " ,

+ tra j = " m a t r i x "

+ )

+ )

[1] " T r a j e c t o i r e s "

29

(30)

30 CHAPITRE 4. D ´ ECLARATION DES CLASSES Malheureusement, il est tout de mˆ eme possible de ne pas typer (ou de mal typer) en utilisant les listes. Le non typage est fortement d´ econseill´ e, mais lors de l’utilisation de listes, il n’y a pas d’autre option.

4.2 Constructeur par d´ efaut

On peut ensuite cr´ eer un objet trajectoire grˆ ace au constructeur new :

> new( Class = " T r a j e c t o i r e s " )

An o b j e c t of c l a s s " T r a j e c t o i r e s "

Sl ot " t e m p s " : n u m e r i c (0) Sl ot " t raj " :

<0 x 0 matrix >

Comme vous pouvez le constater, l’affichage n’est pas extraordinaire. Il sera impor- tant de d´ efinir une m´ ethode pour l’am´ eliorer.

En g´ en´ eral, on d´ efinit un objet en sp´ ecifiant les valeurs de ses attributs. On doit ` a chaque fois pr´ eciser le nom de l’attribut en question :

> new( Class = " T r a j e c t o i r e s " , t e m p s = c (1 ,3 ,4)) An o b j e c t of c l a s s " T r a j e c t o i r e s "

Sl ot " t e m p s " : [1] 1 3 4 Sl ot " t raj " :

<0 x 0 matrix >

> new( Class = " T r a j e c t o i r e s " , t e m p s = c (1 ,3) , t raj = matrix (1:4 , nc ol =2) ) An o b j e c t of c l a s s " T r a j e c t o i r e s "

Sl ot " t e m p s " : [1] 1 3

Sl ot " t raj " : [ ,1] [ ,2]

[1 ,] 1 3

[2 ,] 2 4

Naturellement, un objet se stocke dans une variable comme n’importe quelle autre valeur de R. Pour illustrer nos dires, nous allons constituer une petite base de travail.

Trois hˆ opitaux participent ` a l’´ etude. La Piti´ e Salpˆ etri` ere (qui n’a pas encore rendu son fichier de donn´ ees, honte ` a eux), Cochin et Sainte-Anne :

> t r a j P i t i e <- new( Class = " T r a j e c t o i r e s " )

> t r a j C o c h i n < - new(

+ Class = " T r a j e c t o i r e s " ,

(31)

4.3. ACC ´ EDER AUX ATTRIBUTS 31

+ t e m p s = c (1 ,3 ,4 ,5) ,

+ tr aj = rbind (

+ c (15 ,15.1 ,15.2 ,15.2) ,

+ c (16 ,15.9 ,16 ,16.4) ,

+ c (15.2 , NA ,15.3 ,15.3) ,

+ c (15.7 ,15.6 ,15.8 ,16)

+ )

+ )

> t r a j S t A n n e < - new(

+ Class = " T r a j e c t o i r e s " , + t e m p s = c ( 1 : 1 0 , ( 6 : 1 2 ) * 2) ,

+ tr aj = rbind (

+ matrix ( seq (16 ,19 , length =17) , ncol =17 , nrow =50 ,byrow=TRUE) , + matrix ( seq (15.8 ,18 , length =17) , ncol =17 , nrow =30 ,byrow=TRUE)

+ )+rnorm(17 * 80 ,0 ,0.2)

+ )

4.3 Acc´ eder aux attributs

Toute cette section est plac´ ee sous le double signe du danger...

et du danger...

L’acc` es aux attributs se fait grˆ ace ` a l’op´ erateur @ :

> t r a j C o c h i n @ t e m p s [1] 1 3 4 5

> t r a j C o c h i n @ t e m p s <- c (1 ,2 ,4 ,5)

> t r a j C o c h i n

An o b j e c t of c l a s s " T r a j e c t o i r e s "

Sl ot " t e m p s " : [1] 1 2 4 5 Sl ot " t raj " :

[ ,1] [ ,2] [ ,3] [ ,4]

[1 ,] 15 .0 15 .1 15 .2 15 .2 [2 ,] 16 .0 15 .9 16 .0 16 .4

[3 ,] 15 .2 NA 15 .3 15 .3

[4 ,] 15 .7 15 .6 15 .8 16 .0

Comme nous le verrons par la suite, l’utilisation de @ est ` a ´ eviter. En effet, il ne fait pas appel aux m´ ethodes de v´ erification. L’utilisation que nous pr´ esentons ici (affichage d’un attribut, et pire encore affectation d’une valeur ` a un attribut) est donc ` a proscrire dans la plupart des cas. En tout ´ etat de cause, l’utilisateur final ne devrait jamais avoir

`

a l’utiliser.

Il est ´ egalement possible d’utiliser les fonctions attr ou attributes, mais

c’est largement pire : en effet, si on fait une simple erreur de typographie, on

modifie la structure de l’objet. Et ¸ ca, c’est tr` es tr` es tr` es mal !

(32)

32 CHAPITRE 4. D ´ ECLARATION DES CLASSES

4.4 Valeurs par d´ efaut

On peut d´ eclarer un objet en lui donnant des valeurs par d´ efaut. A chaque cr´ eation, si l’utilisateur ne sp´ ecifie pas les valeurs des attributs, ceux-ci en auront quand mˆ eme une. Pour cela, on doit ajouter l’argument prototype ` a la d´ efinition de l’objet :

> s e t C l a s s (

+ Class = " T r a j e c t o i r e s B i s " , + r e p r e s e n t a t i o n = representation ( + t e m p s = " n u m e r i c " ,

+ tra j = " m a t r i x "

+ ) ,

+ prototype = prototype (

+ t e m p s = 1 ,

+ tra j = matrix (0)

+ )

+ )

[1] " T r a j e c t o i r e s B i s "

L’initialisation par d´ efaut ´ etait quelque chose de n´ ecessaire ` a l’´ epoque loin- taine o` u, si on n’initialisait pas une variable, on risquait d’´ ecrire dans la m´ emoire syst` eme (et donc de provoquer un blocage de l’ordinateur, la perte de notre programme et d’autres trucs encore plus terribles). Aujourd’hui, une telle chose n’est plus possible. Si on n’initialise pas un attribut, R lui donne pour valeur un objet vide du type ad´ equat.

Du point de vue philosophique, lorsqu’on cr´ ee un objet, soit on connaˆıt sa valeur auquel cas on la lui affecte, soit on ne la connaˆıt pas auquel cas il n’y a aucune raison de lui donner une valeur plutˆ ot qu’une autre. L’utilisation d’une valeur par d´ efaut semble donc ˆ etre plus une r´ eminiscence du pass´ e qu’une r´ eelle n´ ecessit´ e. Elle n’a plus lieu d’ˆ etre.

De plus, dans le feu de la programmation, il peut arriver qu’on “oublie” de donner

`

a un objet sa vraie valeur. S’il existe une valeur par d´ efaut, elle sera utilis´ ee. S’il n’y a pas de valeur par d´ efaut, cela provoquera une erreur... ce qui, dans ce cas pr´ ecis, est pr´ ef´ erable, cela attire notre attention et nous permet de corriger. Donc, les valeurs par d´ efaut autres que les valeurs vides sont ` a ´ eviter.

4.5 Supprimer un objet

Dans le cas pr´ ecis de l’objet trajectoires, il n’y a pas vraiment de valeur par d´ efaut qui s’impose. Il est donc pr´ ef´ erable de conserver la classe comme elle a ´ et´ e initialement d´ efinie. La classe TrajectoiresBis n’a plus raison d’ˆ etre. On peut la supprimer grˆ ace

`

a removeClass :

> removeClass ( " T r a j e c t o i r e s B i s " )

[1] TRU E

(33)

4.6. L’OBJET VIDE 33

> new( Class = " T r a j e c t o i r e s B i s " )

E r r o r in g e t C l a s s ( Class , w h e r e = t o p e n v ( p a r e n t . f r a m e ( ))) :

" T r a j e c t o i r e s B i s " is not a d e f i n e d c l a s s

Supprimer la d´ efinition d’une classe ne supprime pas les m´ ethodes qui lui sont associ´ ees. Pour supprimer d´ efinitivement une classe dans le sens classique du terme, il faut supprimer la classe puis supprimer toutes ses m´ ethodes...

En particulier, vous cr´ eez une classe et ses m´ ethodes. ¸ Ca ne marche pas comme pr´ evu.

Vous d´ ecidez de tout reprendre ` a z´ ero. Vous effacez donc la classe. Si vous la recr´ eez, toutes les anciennes m´ ethodes seront ` a nouveau actives.

4.6 L’objet vide

Certaines fonctionnalit´ es objets appellent la fonction new sans lui transmettre d’argument. Par exemple, nous utiliserons dans la section sur l’h´ eritage l’instruction as(tdCochin,"Trajectoires") (voir section 9.8 page 77). Cette instruction fait appel

`

a new("Trajectoires"). Il est donc indispensable, lors de la construction d’un objet, de toujours garder ` a l’esprit que new doit ˆ etre utilisable sans argument. Comme les valeurs par d´ efaut sont d´ econseill´ ees, il faut pr´ evoir la construction de l’objet vide. Cela sera important en particulier lors de la construction de la m´ ethode show.

Un objet vide est un objet poss´ edant tous les attributs normaux d’un objet, mais ceux-ci sont vides, c’est ` a dire de longueur z´ ero. Par contre, un objet vide a une classe.

Ainsi, un numeric vide est diff´ erent d’un integer vide.

> i d e n t i c a l ( n u m e r i c () , i n t e g e r ()) [1] F A L S E

Quelques r` egles ` a connaˆıtre concernant les objets vides : – numeric() et numeric(0) d´ esignent un numeric vide.

– Mˆ eme chose pour character() et character(0).

– Mˆ eme chose pour integer() et integer(0).

– Par contre, factor() d´ esigne un factor vide, factor(0) d´ esigne un factor de longueur 1 et contenant l’´ element z´ ero.

– Plus probl´ ematique, matrix() d´ esigne une matrice ` a une ligne et une co- lonne contenant NA. En tout ´ etat de cause, ¸ ca n’est pas la matrice vide (son attribut length vaut 1). Pour d´ efinir une matrice vide, il faut utiliser ma- trix(nrow=0,ncol=0).

– Mˆ eme chose pour les array().

– NULL repr´ esente l’objet nul. Ainsi, NULL est de classe NULL alors que numeric() est de classe numeric.

Pour tester qu’un objet est l’objet vide, il faut tester son attribut length. De mˆ eme,

si nous d´ ecidons de d´ efinir la m´ ethode length pour nos objets, il faudra prendre garde

(34)

34 CHAPITRE 4. D ´ ECLARATION DES CLASSES

`

a ce que length(monObjet)=0 soit vrai si et seulement si l’objet est vide (pour assurer une certaine coh´ erence ` a R).

4.7 Voir l’objet

Vous venez de cr´ eer votre premi` ere classe. F´ elicitations ! Pour pouvoir v´ erifier ce que vous venez de faire, plusieurs instructions permettent de “voir” la classe et sa structure.

Le terme savant d´ esignant ce qui permet au programme de voir le contenu ou la structure des objets s’appelle l’introspection.

slotNames donne le nom des attributs. getSlots donne le nom des attributs et leur type. getClass donne les noms des attributs et leur type, mais aussi les h´ eritiers et les ancˆ etres. Comme l’h´ eritage est encore “terra incognita”, ¸ ca ne fait pour l’instant aucune diff´ erence :

> slotNames ( " T r a j e c t o i r e s " ) [1] " t e m p s " " t raj "

> g e t S l o t s ( " T r a j e c t o i r e s " )

t e m p s tr aj

" n u m e r i c " " m a t r i x "

> getCla ss ( " T r a j e c t o i r e s " )

C l a s s " T r a j e c t o i r e s " [ in " . G l o b a l E n v " ] S l o t s :

Na me : t e m p s tr aj

C l a s s : n u m e r i c m a t r i x

(35)

Chapitre 5

Les m´ ethodes

Un des int´ erˆ ets de l’objet est de pouvoir d´ efinir des fonctions qui vont adapter leur comportement ` a l’objet. Exemple que vous connaissez d´ ej` a, la fonction plot r´ eagit dif- f´ eremment selon la classe de ses arguments :

> t a i l l e <- rnorm(1 0 , 1.7 0 , 10)

> p o i d s < - rnorm(10 ,70 ,5)

> g r o u p e <- as . f a c t o r ( rep ( c ( " A " , " B " ) ,5))

> p l o t ( t a i l l e ~ p o i d s )

> p l o t ( t a i l l e ~ g r o u p e ) E M P T Y

E M P T Y

64 66 68 70 72 74 76

−15−10−50510

poids

taille

A B

−15−10−50510

groupe

taille

Le premier plot trace un nuage de points, le deuxi` eme dessine des boites ` a mous- taches. De mˆ eme, il va ˆ etre possible de d´ efinir un comportement sp´ ecifique pour nos trajectoires.

5.1 setMethod

Pour cela, on utilise la fonction setMethod. Elle prend trois arguments :

35

(36)

36 CHAPITRE 5. LES M ´ ETHODES 1. f est le nom de la fonction que nous sommes en train de red´ efinir. Dans notre cas,

plot

2. signature est le nom de la classe ` a laquelle elle s’applique. Nous aurons l’occasion d’y revenir section 8.2 page 64

3. definition est la fonction ` a utiliser. Dans notre cas, nous allons simplement uti- liser un matplot en prenant en compte les temps des mesures et en les affichant sur l’axe des abscisses

> setMethod(

+ f = " plot " ,

+ s i g n a t u r e = " T r a j e c t o i r e s " , + d e f i n i t i o n = function (x ,y ,...){

+ matplot ( x@temps , t ( x@traj ) , xaxt = " n " , type = " l " , + yla b = " " , xl ab = " " , pch =1 , col =1 , lty =1) + a x i s (1 , at = x @temp s )

+ }

+ )

[1] " p lot "

> p l o t ( t r a j C o c h i n )

> p l o t ( t r a j S t A n n e ) E M P T Y

E M P T Y

15.015.415.816.2

1 2 4 5

16171819

1 3 5 7 9 12 16 20 24

Petite remarque : R nous impose, lors de la red´ efinition d’une fonction, d’utiliser les mˆ emes arguments que la fonction en question. Pour connaˆıtre les arguments de plot, on peut utiliser args

> args ( p l o t )

f u n c t i o n ( x , y , .. .)

NU LL

(37)

5.2. SHOW ET PRINT 37 Nous sommes donc oblig´ es d’utiliser function(x,y,...) mˆ eme si nous sa- vons d’ors et d´ ej` a que l’argument y n’a pas de sens. De plus, les noms par d´ efaut ne sont pas vraiment uniformis´ es, certaines fonctions appellent object, d’autres .Object, d’autres encore x. R-la-go´ elette vogue au gr´ e de ses programmeurs...

5.2 show et print

show et print servent pour l’affichage. Nous allons les d´ efinir pour les trajectoires.

args(print) nous indique que print prend pour argument (x,...). Donc :

> setMethod( " p r i n t " , " T r a j e c t o i r e s " ,

+ fu ncti on (x ,...){

+ cat ( " * * * Class Trajectoires , method Print * * * \ n " ) + cat ( " * Temps = " ); p r i n t ( x@t emps )

+ cat ( " * Traj = \ n " ); p r i n t ( x @ t r a j )

+ cat ( " * * * * * * * Fin P r i n t ( t r a j e c t o i r e s ) * * * * * * * \ n " )

+ }

+ )

[1] " p r i n t "

> p r i n t ( t r a j C o c h i n )

* * * C l a s s T r a j e c t o i r e s , m e t h o d P r i n t * * *

* T e m p s = [1] 1 2 4 5

* T raj =

[ ,1] [ ,2] [ ,3] [ ,4]

[1 ,] 15 .0 15 .1 15 .2 15 .2 [2 ,] 16 .0 15 .9 16 .0 16 .4

[3 ,] 15 .2 NA 15 .3 15 .3

[4 ,] 15 .7 15 .6 15 .8 16 .0

* * * * * * * Fin P r i n t ( t r a j e c t o i r e s ) * * * * * * *

Pour Cochin, le r´ esultat est satisfaisant. Pour Sainte-Anne (qui compte 80 lignes), on ne verrait pas grand-chose, d’o` u le besoin d’une deuxi` eme m´ ethode d’affichage.

show est la m´ ethode utilis´ ee quand on tape le nom d’un objet. Nous allons donc la red´ efinir en prenant en compte la taille de l’objet : s’il y a trop de trajectoires, show n’en affichera qu’une partie.

> setMethod( " s how " , " T r a j e c t o i r e s " ,

+ fu ncti on ( object ){

+ cat ( " * * * Class Trajectoires , method Show * * * \ n " ) + cat ( " * Temps = " ); p r i n t ( o b j e c t @ t e m p s )

+ n r o w S h o w < - min (10 , n row ( o b j e c t @ t r a j )) + n c o l S h o w < - min (10 , n col ( o b j e c t @ t r a j ))

+ cat ( " * Traj ( l i m i t ´ e ` a une m a t r i c e 10 x10 ) = \ n " ) + p r i n t ( for matC ( o b j e c t @ t r a j [1: nrowShow ,1: n c o l S h o w ]) ,

+ q u o t e =FALSE)

+ cat ( " * ... ...\ n " )

+ cat ( " * * * * * * * Fin Sho w ( t r a j e c t o i r e s ) * * * * * * * \ n " )

+ }

+ )

(38)

38 CHAPITRE 5. LES M ´ ETHODES

[1] " s how "

> t r a j S t A n n e

* * * C l a s s T r a j e c t o i r e s , m e t h o d Sh ow * * *

* T e m p s = [1] 1 2 3 4 5 6 7 8 9 10 12 14 16 18 20 22 24

* T raj ( l i m i t ´ e ` a une m a t r i c e 10 x10 ) =

[ ,1] [ ,2] [ ,3] [ ,4] [ ,5] [ ,6] [ ,7] [ ,8] [ ,9] [ ,10]

[1 ,] 1 6 . 2 5 1 6.1 1 6 . 1 6 1 6 . 5 3 1 6 . 6 7 17 .2 1 7 . 5 5 17. 3 1 7 . 4 7 1 7 . 5 5 [2 ,] 1 6 . 2 3 1 6 . 3 6 1 6 . 4 5 1 6.4 1 7 . 1 4 17 1 6 . 8 4 1 7 . 2 5 1 7 . 9 8 1 7 . 4 3 [3 ,] 1 5 . 8 9 1 6 . 0 2 1 6 . 1 5 1 6 . 6 9 1 6 . 7 7 1 6 . 6 2 1 7 . 5 2 1 7 . 2 6 1 7 . 4 6 17. 6 [4 ,] 1 5 . 6 3 1 6 . 2 5 16. 4 1 6.6 1 6 . 6 5 1 6 . 9 6 1 7 . 0 2 1 7 . 3 9 1 7.5 1 7 . 6 7 [5 ,] 1 6 . 1 6 1 5 . 8 5 1 5 . 9 7 1 6 . 3 2 1 6 . 7 3 1 6 . 9 4 1 6 . 7 3 1 6 . 9 8 1 7 . 6 4 1 7 . 7 2 [6 ,] 1 5 . 9 6 1 6.2 1 6 . 5 3 1 6.4 1 6 . 4 7 1 6 . 9 5 1 6 . 7 3 1 7 . 3 6 1 7 . 3 3 1 7 . 5 5 [7 ,] 1 6 . 0 3 1 6 . 3 3 1 6 . 2 3 1 6 . 6 7 1 6 . 7 9 1 7 . 1 4 17 1 7 . 3 5 1 7 . 5 8 1 7 . 9 9 [8 ,] 1 5 . 6 9 1 6 . 0 6 1 6 . 6 3 1 6 . 7 2 1 6 . 8 1 1 7 . 1 6 1 6 . 9 8 1 7 . 4 1 1 7 . 5 1 1 7 . 4 3 [9 ,] 1 5 . 8 2 1 6 . 1 7 1 6 . 7 5 1 6 . 7 6 1 6 . 7 8 1 6 . 5 1 1 7 . 1 9 1 7 . 2 1 1 7 . 8 4 1 7 . 9 5 [10 ,] 1 5 . 9 8 1 5 . 7 6 1 6.1 1 6 . 5 4 1 6 . 7 8 1 6 . 8 9 1 7 . 2 2 1 7 . 1 8 1 6 . 9 4 1 7 . 3 6

* ... ...

* * * * * * * Fin Sho w ( t r a j e c t o i r e s ) * * * * * * *

Reste un probl` eme ` a r´ egler. Nous avons vu section 4.6 page 33 que new devait ˆ etre utilisable sans argument. Or, il ne l’est plus :

> new( " T r a j e c t o i r e s " )

* * * C l a s s T r a j e c t o i r e s , m e t h o d Sh ow * * *

* T e m p s = n u m e r i c (0)

* T raj ( l i m i t ´ e ` a une m a t r i c e 10 x10 ) =

E r r o r in p r i n t ( f o r m a t C ( o b j e c t @ t r a j [1: n row Sho w , 1: n c o l S h o w ]) , q u o t e

= F A L S E ) :

e r r e u r lor s de l ' ´evaluation de l ' argument ' x ' lors de la s ´ e l e c t i o n d ' une m´ethode pour la fonction ' print '

En effet, new cr´ ee un objet, puis l’affiche en utilisant show. Dans le cas de new sans argument, l’objet vide est pass´ e ` a show. Or, show tel que nous l’avons con¸cu ne peut pas traiter l’objet vide.

D’une mani` ere plus g´ en´ erale, toutes nos m´ ethodes doivent prendre en compte le fait qu’elles auront peut-ˆ etre ` a traiter l’objet vide :

> setMethod( " s how " , " T r a j e c t o i r e s " ,

+ fu ncti on ( object ){

+ cat ( " * * * Class Trajectoires , method Show * * * \ n " ) + cat ( " * Temps = " ); p r i n t ( o b j e c t @ t e m p s )

+ n r o w S h o w < - min (10 , n row ( o b j e c t @ t r a j )) + n c o l S h o w < - min (10 , n col ( o b j e c t @ t r a j ))

+ cat ( " * Traj ( l i m i t ´ e ` a une m a t r i c e 10 x10 ) = \ n " ) + i f ( length ( o b j e c t @ t r a j ) ! = 0){

+ p r i n t ( for matC ( o b j e c t @ t r a j [1: nrowShow ,1: n c o l S h o w ]) ,

+ q u o t e =FALSE)

+ } e l s e {}

+ cat ( " * ... ...\ n " )

(39)

5.3. SETGENERIC 39

+ cat ( " * * * * * * * Fin Sho w ( t r a j e c t o i r e s ) * * * * * * * \ n " )

+ }

+ )

[1] " s how "

> new( " T r a j e c t o i r e s " )

* * * C l a s s T r a j e c t o i r e s , m e t h o d Sh ow * * *

* T e m p s = n u m e r i c (0)

* T raj ( l i m i t ´ e ` a une m a t r i c e 10 x10 ) =

* ... ...

* * * * * * * Fin Sho w ( t r a j e c t o i r e s ) * * * * * * *

¸

Ca marche !

Nous disposons donc de deux m´ ethodes d’affichage. Par d´ efaut, show montre l’objet ou une partie de l’objet si celui-ci est trop grand ; print permet d’afficher l’int´ egralit´ e de l’objet.

5.3 setGeneric

Jusqu’` a pr´ esent, nous n’avons fait que d´ efinir pour l’objet Trajectoires des m´ e- thodes qui existaient d´ ej` a par ailleurs (print existait pour les numeric, pour les cha- racter...). Nous allons maintenant d´ efinir une m´ ethode nouvelle. Pour cela, il nous faut la d´ eclarer. Cela se fait ` a l’aide de la fonction setGeneric. ´ A ce stade, une petite digres- sion sur le concept de g´ en´ erique s’impose.

5.3.1 G´ en´ erique versus Sp´ ecifique

En S4, les fonctions doivent ˆ etre d´ efinies de deux mani` eres : g´ en´ erique et sp´ eci- fique. La d´ efinition g´ en´ erique d’une fonction est la donn´ ee d’un comportement global (ou conceptuel). La d´ efinition sp´ ecifique d’une fonction est l’application de ce concept ` a un cas particulier. Un exemple va ´ eclaircir les choses.

plot est une fonction qui repr´ esente graphiquement des donn´ ees. Telle est sa d´ efini- tion g´ en´ erique. Le type pr´ ecis de repr´ esentation n’entre pas en ligne de compte dans la d´ efinition g´ en´ erique. Celle-ci ne s’occupe pas de d´ etail ou des cas particuliers, elle reste floue, g´ en´ erale...

plot appliqu´ e ` a une variable numeric trace un histogramme. C’est une d´ efinition sp´ ecifique. Nous ne sommes plus au niveau du concept mais dans la discussion pratique : il faut d´ efinir le type de graphe qui sera pr´ ecis´ ement utilis´ e. Dans notre cas, c’est un histogramme.

Une fonction n’a qu’une d´ efinition g´ en´ erique, mais peut avoir plusieurs d´ efinitions sp´ ecifiques. Par exemple, plot appliqu´ e ` a un (numeric,factor) trace des boites ` a mous- taches. C’est une deuxi` eme d´ efinition sp´ ecifique.

Dans R, chaque fonction sp´ ecifique doit n´ ecessairement ˆ etre connue du programme

comme fonction g´ en´ erique : avant d’entrer dans les d´ etails, il faut d´ efinir le concept

global.

(40)

40 CHAPITRE 5. LES M ´ ETHODES Une m´ ethode nouvelle devra donc en premier lieu ˆ etre d´ eclar´ ee comme fonction g´ en´ e- rique, puis comme fonction sp´ ecifique. Une fonction dont la g´ en´ erique existe d´ ej` a (comme print) n’a pas besoin d’ˆ etre d´ eclar´ ee en g´ en´ erique et peut directement ˆ etre d´ eclar´ ee en sp´ ecifique, comme nous l’avons fait au paragraphe pr´ ec´ edent. Mais toute fonction nou- velle doit ˆ etre d´ eclar´ ee en g´ en´ erique.

5.3.2 D´ efinition formelle

D´ efinir une fonction g´ en´ erique se fait grˆ ace ` a setGeneric. setGeneric prend deux arguments :

– name est le nom de la m´ ethode que nous allons d´ efinir.

– def est un exemple de fonction qui sera utilis´ e pour la d´ efinir.

A ce stade, il n’est pas possible de la typer puisqu’elle est g´ en´ erique et doit donc ˆ etre utilisable pour plusieurs types diff´ erents.

> setGeneric (

+ name= " c o m p t e r M a n q u a n t e s " ,

+ def = function ( object ){ standardGeneric ( " c o m p t e r M a n q u a n t e s " )}

+ )

[1] " c o m p t e r M a n q u a n t e s "

compterManquantes a donc ´ et´ e ajout´ e ` a la liste des m´ ethodes que R connait. Nous pouvons maintenant la d´ efinir comme fonction sp´ ecifique pour l’objet Trajectoires :

> setMethod(

+ f = " c o m p t e r M a n q u a n t e s " , + s i g n a t u r e = " T r a j e c t o i r e s " , + d e f i n i t i o n = function ( object ){

+ return ( sum ( is . na ( o b j e c t @ t r a j )))

+ }

+ )

[1] " c o m p t e r M a n q u a n t e s "

> c o m p t e r M a n q u a n t e s ( t r a j C o c h i n ) [1] 1

5.3.3 lockBinding

Il n’y a pas de contrˆ ole sur l’utilisation d’un setGeneric : si une fonction

g´ en´ erique existe d´ ej` a, la nouvelle d´ efinition d´ etruit l’ancienne - un peu de

la mˆ eme mani` ere qu’affecter une valeur ` a une variable d´ etruit la pr´ ec´ edente

valeur -. Sauf que dans ce cas pr´ ecis, une red´ efinition est plus probablement li´ ee au fait

que le programmeur ignore que la fonction existe d´ ej` a... Pour se prot´ eger de ce probl` eme,

il est possible de “verrouiller” la d´ efinition d’une m´ ethode grˆ ace ` a lockBinding :

(41)

5.4. VOIR LES M ´ ETHODES 41

> lockBinding ( " c o m p t e r M a n q u a n t e s " ,. G l o b a l E n v )

> setGeneric (

+ name= " c o m p t e r M a n q u a n t e s " ,

+ def = function ( object , value ){

+ standardGeneric ( " c o m p t e r M a n q u a n t e s " )

+ }

+ )

E r r o r in a s s i g n ( name , fdef , w h e r e ) : i m p o s s i b l e de c h a n g e r la

v a l e u r d ' un lien verrouill´e pour ' compterManquantes '

Il n’est plus possible d’effacer “par erreur” le setGeneric.

Cette m´ ethode pr´ esente toutefois un inconv´ enient majeur, celui de la non r´ e- ex´ ecutabilit´ e du code. Pendant la phase de d´ eveloppement, on a tendance ` a ex´ ecuter notre code, le modifier et le r´ e-ex´ ecuter. lockBinding empˆ eche une telle r´ e ex´ ecution puisqu’une fonction g´ en´ erique ne peut-ˆ etre d´ efinie qu’une fois (et que la r´ e-ex´ ecution est une seconde d´ efinition).

5.3.4 D´ eclaration des g´ en´ eriques

Une autre mani` ere de se prot´ eger contre l’´ ecrasement des g´ en´ eriques est de regrouper la d´ eclaration des g´ en´ eriques dans un fichier unique. En tout ´ etat de cause, une fonction g´ en´ erique ne concerne pas un objet particulier puisque, par d´ efinition, elle doit s’adapter ` a tous les objets. Il est donc pr´ ef´ erable de d´ eclarer toutes les fonctions g´ en´ eriques ensemble en d´ ebut de programme, ´ eventuellement class´ ees par ordre alphab´ etique. Si par erreur nous devions d´ ecider de d´ eclarer une g´ en´ erique deux fois, il serait alors facile de s’en rendre compte. Plus de d´ etail sur l’art et la mani` ere de placer son code dans le fichier ad´ equat section ?? page ??.

5.4 Voir les m´ ethodes

Notre classe commence ` a s’´ etoffer. Il est temps de faire une petite pause et d’admirer notre travail. showMethods est la m´ ethode de la situation. Il existe plusieurs mani` eres de l’utiliser. L’une d’entre elles permet de voir les noms des m´ ethodes que nous avons d´ efinies pour une classe donn´ ee :

> showMethods( c l a s s = " T r a j e c t o i r e s " ) F u n c t i o n : i n i t i a l i z e ( p a c k a g e m e t h o d s ) . O b j e c t = " T r a j e c t o i r e s "

( i n h e r i t e d fr om : . O b j e c t = " ANY " ) F u n c t i o n : plo t ( p a c k a g e g r a p h i c s ) x = " T r a j e c t o i r e s "

F u n c t i o n : p r i n t ( p a c k a g e bas e )

(42)

42 CHAPITRE 5. LES M ´ ETHODES

x = " T r a j e c t o i r e s "

F u n c t i o n : sho w ( p a c k a g e m e t h o d s ) o b j e c t = " T r a j e c t o i r e s "

Maintenant que nous avons list´ e ce qui existe, nous pouvons nous int´ eresser d’un peu plus pr` es ` a une m´ ethode particuli` ere : getMethod permet d’afficher la d´ efinition (le contenu du corps de la fonction) d’une m´ ethode pour un objet donn´ e. Si la m´ ethode en question n’existe pas, getMethod renvoie une erreur :

> getMethod( f = " p lot " , s i g n a t u r e = " T r a j e c t o i r e s " ) M e t h o d D e f i n i t i o n :

f u n c t i o n ( x , y , .. .) {

m a t p l o t ( x@temps , t ( x @ t r a j ) , x axt = " n " , ty pe = " l " , yl ab = " " , xl ab = " " , pch = 1 , col = 1 , lty = 1)

ax is (1 , at = x @ t e m p s ) }

S i g n a t u r e s : x

t a r g e t " T r a j e c t o i r e s "

d e f i n e d " T r a j e c t o i r e s "

> getMethod( f = " p lot " , s i g n a t u r e = " P a r t i t i o n " )

E r r o r in g e t M e t h o d ( f = " pl ot " , s i g n a t u r e = " T r j e c t o i r e s " ) : No

m e t h o d f o u n d for f u n c t i o n " plo t " and s i g n a t u r e T r j e c t o i r e s

Plus simplement, existsMethod indique si une m´ ethode est ou n’est pas d´ efinie pour une classe :

> existsMethod ( f = " p lot " , s i g n a t u r e = " T r a j e c t o i r e s " ) [1] TRU E

> existsMethod ( f = " p lot " , s i g n a t u r e = " P a r t i t i o n " ) [1] F A L S E

¸

Ca n’est pas vraiment utile pour l’utilisateur, ¸ ca l’est plus pour le programmeur

qui peut ´ ecrire des choses du genre : “Si telle m´ ethode existe pour tel objet, adopte le

comportement 1, sinon le comportement 2”.

Riferimenti

Documenti correlati

Per qualunque tipo di disequazione , ci comporteremo nello stesso modo e con la medesima procedura che abbiamo usato per le corrispondenti

[r]

that describes the entire Design Thinking process, suggests practical methods to complete the different iterative steps of the process, and concludes with 6 case studies from the

After gaining a common understanding of these steps, the actual Design Thinking process started with different brainstorming methods (silent and open brainstorming, mind mapping)

geriamo a voler unire la vostra alla nostra sollecitudine, e vegliare non solo per impedire che il nemico delle anime semini di nascosto la zizzania nel

[r]

Nous comptons sur l’expertise de l’´ equipe de d´ eveloppement pour pr´ eciser les quelques d´ etails techniques auxquels la soci´ et´ e “Aventure G´ en´ erique”. n’a

En ce sens, comme pour le risque VIH (Rhodes et al., 2005) il faut sans doute élargir l’analyse des conduites auto-agressives à tout un environnement à « risque suicidaire »,