The r has at least 4 object guidance systems (OO): S3
, S4
, Reference Classes (also known as R5
or RC
) and R6
. The latter system is not part of the r-base, but has been widely used by the community. The R6
comes from a bundle by the same name.
But watch out!!! You must even use oo on r?
It is not a question of defending this or that programming paradigm. It turns out that "R is a Functional Programming language; embrace it, don’t Fight it"1.
That is, if you really want to "understand a little the logic of programming in R
", you should start to address the problems in a more functional way. When your problem demands, abandon the pattern of r and use object orientation.
See, the system S3
is an object orientation system subordinated to functional programming logic, as its objective is to dispatch the object correctly to the appropriate function (method).
Back to the answer
Already exists a question about the difference between the native systems of the r. I’m going to focus on the answer about constructor and systems heritage S3
and R6
since they are the most used.
builders
S3
In the S3
there is no formal definition of the class. Any object can be "transformed" into the desired class.
x <- "lala"
class(x) <- "lm"
print(x)
# Error: $ operator is invalid for atomic vectors
To create, or instantiate, a class simply add the class to the object, as in the example above, or add it through the function structure()
. Good practice, however, is to create a constructor to create objects of that class.
pergunta <- function(x) {
structure(x, class = c("pergunta", class(x)))
}
p1 <- pergunta("Acabei de criar uma classe?")
p1
# [1] "Acabei de criar uma classe?"
# attr(,"class")
# [1] "pergunta" "character"
R6
In the R6
you first need to formally define the class. This is where a constructor is defined (item initialize
in public
).
library(R6)
Pergunta<- R6Class(
"Pergunta",
public = list(
initialize = function(pergunta) {
self$pergunta <- pergunta
self$responder()
},
pergunta = NULL,
responder = function() {
print(sample(c("Sim!", "Não!"), 1))
}
)
)
To then be able to instantiate it (which is when the constructor is "activated")
set.seed(1)
P1 <- Pergunta$new("Acabei de criar uma classe?")
# [1] "Sim!"
On the usefulness of builders in the R
: is the same as in any other language in which OO is used, but this paradigm has restricted use in R
, as commented by Daniel.
inheritance
S3
Inheritance in the method S3
works by adding classes in front of the "mother class". This is because the way to dispatch the object to the methods goes through the class vector until finding a method for that function.
class(dplyr::starwars)
# [1] "tbl_df" "tbl" "data.frame"
Thus, the tibble
s can work both for own methods (case of print()
), which are preferred, as for methods of the data.frame
(case of summary()
). That’s also why, even though we haven’t defined a method for printing our class, the R
turned. When no method is found, the object is played to the "default method" (nome_da_funcao.default()
)
R6
In the case of R6
, the function defining the class has an argument to identify the inheritance (inherit
). Note the fact that class itself should be passed as an object, not just its name.
PerguntaRetorica <- R6Class(
"PerguntaRetorica",
inherit = Pergunta,
public = list(responder = function() print("!?!"))
)
After the class has been defined, we can instantiate it.
retorica <- PerguntaRetorica$new("Ser ou não ser?")
[1] "!?!"
The importance of knowing the ancestry of a given object is knowing how it will behave with methods. And the way to do it is to pass the object to class()
.
class(retorica)
[1] "PerguntaRetorica" "Pergunta" "R6"
Here we see that our daughter-class is heir to Pergunta
which in turn descended from R6
References
1: The Tidy tools manifesto
2: Advanced R - Object oriented Programming
Pretty cool the answer, but... didn’t answer the original question!
– Pedro Gaspar
I believe that by the answer it is possible to understand well what is a class in the R, with this it is possible to create them and understand heritages without any problem.
– Daniel Falbel
Just by entering the external link, is not in the answer actually! ;-)
– Pedro Gaspar
it was not clear that a class is an object of the R + an attribute class? and that to identify the type of the object or use the
typeof
? anyway... the O part is missing, but I don’t think that’s what was asked either. I don’t have time to write much more, but if you are willing to complete the answer I will be happy to vote +1 :)– Daniel Falbel
I never used and I don’t know anything about R, so I thought it was cool and interesting your answer, because it gave a brush stroke on some concepts of language. I only made that comment about not having answered because the main questions were: What constructors and how they function and inheritance in the R language?, and you didn’t say anything about builders or inheritance in the R in the answer. Just this, don’t get me wrong. :-)
– Pedro Gaspar
ok! I’m not taking this the wrong way! I’m trying to understand what you think is missing? if I had answered only how to create a class S3 the answer would be complete? In R there is not only one form of OO, so my choice to explain how everything works instead of writing an extensive answer about each of the OO systems. perhaps not the best way to explain. but your comment without any other addendum is superficial and does not help to improve at all the answer.
– Daniel Falbel