[R] How to create a proper S4 class?

Leonard Mada |eo@m@d@ @end|ng |rom @yon|c@eu
Thu Nov 18 02:00:04 CET 2021


Dear Martin,


thank you very much for the guidance.


Ultimately, I got it running. But, for mysterious reasons, it was 
challenging:

- I skipped for now the inheritance (and used 2 explicit non-inherited 
slots): this is still unresolved; [*]

- the code is definitely cleaner;


[*] Mysterious errors, like:

"Error in cbind(deparse.level, ...) :
   cbind for agentMatrix is only defined for 2 agentMatrices"


One last question pops up:

If B inherits from A, how can I down-cast back to A?

b = new("B", someA);

??? as.A(b) ???

Is there a direct method?

I could not explore this, as I am still struggling with the inheritance. 
The information may be useful, though: it helps in deciding the design 
of the data-structures. [Actually, all base-methods should work natively 
as well - but to have a solution in any case.]


Sincerely,


Leonard


On 11/17/2021 5:48 PM, Martin Morgan wrote:
> Hi Leonard --
>
> Remember that a class can have 'has a' and 'is a' relationships. For instance, a People class might HAVE slots name and age
>
> .People <- setClass(
>      "People",
>      slots = c(name = "character", age = "numeric")
> )
>
> while an Employees class might be described as an 'is a' relationship -- all employeeds are people -- while also having slots like years_of_employment and job_title
>
> .Employees <- setClass(
>      "Employees",
>      contains = "People",
>      slots = c(years_of_employment = "numeric", job_title = "character")
> )
>
> I've used .People and .Employees to capture the return value of setClass(), and these can be used as constructors
>
> people <- .People(
>     name = c("Simon", "Andre"),
>     age = c(30, 60)
> )
>
> employees = .Employees(
>      people, # unnamed arguments are class(es) contained in 'Employees'
>      years_of_employment = c(3, 30),
>      job_title = c("hard worker", "manager")
> )
>
> I would not suggest using attributes in addition to slots. Rather, embrace the paradigm and represent attributes as additional slots. In practice it is often helpful to write a constructor function that might transform between formats useful for users to formats useful for programming, and that can be easily documented.
>
> Employees <-
>      function(name, age, years_of_employment, job_title)
> {
>      ## implement sanity checks here, or in validity methods
>      people <- .People(name = name, age = age)
>      .Employees(people, years_of_employment = years_of_employment, job_title = job_title)
> }
>
> plot() and lines() are both S3 generics, and the rules for S3 generics using S4 objects are described in the help page ?Methods_for_S3. Likely you will want to implement a show() method; show() is an S4 method, so see ?Methods_Details. Typically this should use accessors rather than relying on direct slot access, e.g.,
>
> person_names <- function(x) x using name
> employee_names <- person_names
>
> The next method implemented is often the [ (single bracket subset) function; this is relatively complicated to get right, but worth exploring.
>
> I hope that gets you a little further along the road.
>
> Martin Morgan
>
> On 11/16/21, 11:34 PM, "R-help on behalf of Leonard Mada via R-help" <r-help-bounces using r-project.org on behalf of r-help using r-project.org> wrote:
>
>      Dear List-Members,
>
>
>      I want to create an S4 class with 2 data slots, as well as a plot and a
>      line method.
>
>
>      Unfortunately I lack any experience with S4 classes. I have put together
>      some working code - but I presume that it is not the best way to do it.
>      The actual code is also available on Github (see below).
>
>
>      1.) S4 class
>      - should contain 2 data slots:
>      Slot 1: the agents:
>        = agentMatrix class (defined externally, NetlogoR S4 class);
>      Slot 2: the path traveled by the agents:
>         = a data frame: (x, y, id);
>        - my current code: defines only the agents ("t");
>      setClass("agentsWithPath", contains = c(t="agentMatrix"));
>
>      1.b.) Attribute with colors specific for each agent
>      - should be probably an attribute attached to the agentMatrix and not a
>      proper data slot;
>      Note:
>      - it is currently an attribute on the path data.frame, but I will
>      probably change this once I get the S4 class properly implemented;
>      - the agentMatrix does NOT store the colors (which are stored in another
>      class - but it is useful to have this information available with the
>      agents);
>
>      2.) plot & line methods for this class
>      plot.agentsWithPath;
>      lines.agentsWithPath;
>
>
>      I somehow got stuck with the S4 class definition. Though it may be a
>      good opportunity to learn about S4 classes (and it is probably better
>      suited as an S4 class than polynomials).
>
>
>      The GitHub code draws the agents, but was somehow hacked together. For
>      anyone interested:
>
>      https://github.com/discoleo/R/blob/master/Stat/ABM.Models.Particles.R
>
>
>      Many thanks,
>
>
>      Leonard
>
>      ______________________________________________
>      R-help using r-project.org mailing list -- To UNSUBSCRIBE and more, see
>      https://stat.ethz.ch/mailman/listinfo/r-help
>      PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
>      and provide commented, minimal, self-contained, reproducible code.



More information about the R-help mailing list