Menu
CoddyTech

Création de génériques

Fait partie de la section Programmation orientée objet du Journey R de Coddy. Leçon 27 sur 57.

Un générique S4 est créé avec setGeneric(). Le corps de sa fonction est standardGeneric("name"), l’équivalent S4 de UseMethod(). setGeneric() renvoie le nom du générique, qui est affiché lorsqu’il est appelé au niveau supérieur :

setGeneric("area", function(shape) standardGeneric("area"))

Sortie :

[1] "area"

Enveloppez l’appel dans invisible() pour que cette ligne n’apparaisse pas dans la sortie. setMethod("area", "Circle", ...) ajoute ensuite la méthode pour une classe :

setClass("Circle", slots = c(r = "numeric"))
setClass("Square", slots = c(side = "numeric"))
invisible(setGeneric("area", function(shape) standardGeneric("area")))
setMethod("area", "Circle", function(shape) pi * shape@r^2)
setMethod("area", "Square", function(shape) shape@side^2)
cat(area(new("Circle", r = 1)), area(new("Square", side = 3)))

Sortie :

3.141593 9

Une méthode possède les mêmes arguments que sa fonction générique. Lorsque la fonction générique comporte ..., une méthode peut ajouter ses propres arguments nommés après ceux-ci :

setClass("Circle", slots = c(r = "numeric"))
invisible(setGeneric("describe", function(x, ...) standardGeneric("describe")))
setMethod("describe", "Circle", function(x, ..., digits = 2) {
  paste("circle of area", round(pi * x@r^2, digits))
})
c1 <- new("Circle", r = 2)
print(describe(c1))
print(describe(c1, digits = 4))

Sortie :

[1] "circle of area 12.57"
[1] "circle of area 12.5664"

setMethod() a besoin que la méthode générique existe déjà ; le fichier contenant setGeneric() est donc chargé en premier. Un appel pour une classe sans méthode s’interrompt avec une erreur qui indique la signature :

invisible(setGeneric("area", function(shape) standardGeneric("area")))
setClass("Circle", slots = c(r = "numeric"))
setMethod("area", "Circle", function(shape) pi * shape@r^2)
area(42)

Résultat :

Error: unable to find an inherited method for function ‘area’ for signature ‘shape = "numeric"’
Execution halted
challenge icon

Défi

Facile

Les formes sont des classes S4 réparties dans trois fichiers. Dans Shape.R, créez les génériques area(shape) et perimeter(shape) avec setGeneric(), enveloppés dans invisible(). Dans Circle.R et Square.R, les classes sont déclarées ; ajoutez les méthodes area et perimeter de chacune avec setMethod().

Le code fourni lit les lignes circle 2 ou square 3 et affiche circle: area 12.57, perimeter 12.57.

Votre code va dans Shape.R, Circle.R et Square.R. main.R contient le code d’entrée/sortie fourni et ne peut pas être modifié.

Essayez vous-même

source("Shape.R")
source("Circle.R")
source("Square.R")

# Code d'entrée/sortie fourni : conservez-le tel quel
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
  p <- strsplit(line, " ")[[1]]
  s <- if (p[1] == "circle") new("Circle", r = as.numeric(p[2])) else new("Square", side = as.numeric(p[2]))
  cat(sprintf("%s: area %.2f, perimeter %.2f", p[1], area(s), perimeter(s)), "\n", sep = "")
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation orientée objet

Entraînez-vous par vous-même : Compilateur R en ligne