Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vignette typos fixes #492

Merged
merged 9 commits into from
Nov 14, 2024
9 changes: 5 additions & 4 deletions vignettes/classes-objects.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ library(S7)
## Validation

S7 classes can have an optional **validator** that checks that the values of the properties are OK.
A validator is a function that takes the object (called `self`) and returns `NULL` if its valid or returns a character vector listing the problems.
A validator is a function that takes the object (called `self`) and returns `NULL` if it's valid or returns a character vector listing the problems.

### Basics

Expand Down Expand Up @@ -168,7 +168,7 @@ This makes it possible to use the same property definition for multiple properti

### Default value

The defaults of `new_class()` create an class that can be constructed with no arguments:
The defaults of `new_class()` create a class that can be constructed with no arguments:

```{r}
Empty <- new_class("Empty",
Expand Down Expand Up @@ -225,7 +225,7 @@ Range <- new_class("Range",
start = class_double,
end = class_double,
length = new_property(
getter = function(self) self@end - self@start,
getter = function(self) self@end - self@start
)
)
)
Expand Down Expand Up @@ -257,6 +257,7 @@ Range <- new_class("Range",
class = class_double,
getter = function(self) self@end - self@start,
setter = function(self, value) {
if (length(value) == 0) return(self)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@t-kalinowski it probably makes sense for this to be an explicit is.null() test, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. The default value passed in by the constructor will be double(0). If we want the default to be NULL, we'd have to change the property class to NULL | class_double, or implement a custom constructor.

self@end <- self@start + value
self
}
Expand Down Expand Up @@ -398,7 +399,7 @@ Range <- new_class("Range",
}
)

range(c(10, 5, 0, 2, 5, 7))
Range(c(10, 5, 0, 2, 5, 7))
```

A constructor must always end with a call to `new_object()`.
Expand Down
4 changes: 2 additions & 2 deletions vignettes/compatibility.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ rle(1:10)
Alternatively you could convert it to the most natural representation using S7:

```{r}
rle <- new_class("rle", properties = list(
new_rle <- new_class("rle", properties = list(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rle2? I think calling it new_ is a bit confusing because the while the object is constructor, it's also the class.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, rle2 would be clearer than new_rle.

Copy link
Contributor Author

@mattheaphy mattheaphy Nov 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a few other instances north of this line where the name new_rle is used that would have to be updated as well for the examples to work as the original author intended. I'll add that change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this! After looking more closely, I see that new_rle() is indeed the best choice here. The intent is for rle() to serve as a convenient constructor, and we show how to redefine the underlying new_rle() from the “old-style” S3 approach to the S7 approach (in two different ways) while keeping the user-facing rle() constructor unchanged.

Strictly speaking, it might make sense to replace the user-facing rle() with an S7 rle class that has a custom constructor, but that would increase the example’s size and complexity without adding much clarity, in my opinion. I’ve restored the previous new_rle() approach.

lengths = class_integer,
values = class_atomic
))
Expand All @@ -118,7 +118,7 @@ rle <- new_class("rle", properties = list(
To allow existing methods to work you'll need to override `$` to access properties instead of list elements:

```{r}
method(`$`, rle) <- prop
method(`$`, new_rle) <- prop
rle(1:10)
```

Expand Down
14 changes: 7 additions & 7 deletions vignettes/generics-methods.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ simple_print(list(1, 2, "x"), diggits = 3)

Occasional it's useful to create a generic without `…` because such functions have a useful property: if a call succeeds for one type of input, it will succeed for any type of input.
To create such a generic, you'll need to use the third argument to `new_generic()`: an optional function that powers the generic.
This function has one key property: it must call `call_method()` to actually perform dispatch.
This function has one key property: it must call `S7_dispatch()` to actually perform dispatch.

In general, this property is only needed for very low-level functions with precisely defined semantics.
A good example of such a function is `length()`:
Expand All @@ -126,7 +126,7 @@ length <- new_generic("length", "x", function(x) {
```

Omitting `…` from the generic signature is a strong restriction as it prevents methods from adding extra arguments.
For this reason, it's should only be used in special situations.
For this reason, it should only be used in special situations.

## Customizing generics

Expand All @@ -137,7 +137,7 @@ display <- new_generic("display", "x")
S7_data(display)
```

The most important part of the body is `S7_dispatch()`; this function finds the method the matches the arguments used for dispatch and calls it with the arguments supplied to the generic.
The most important part of the body is `S7_dispatch()`; this function finds the method that matches the arguments used for dispatch and calls it with the arguments supplied to the generic.

It can be useful to customize this body.
The previous section showed one case when you might want to supply the body yourself: dropping `…` from the formals of the generic.
Expand All @@ -147,7 +147,7 @@ There are three other useful cases:
- To add optional arguments.
- Perform some standard work.

A custom `fun` must always include a call to `call_method()`, which will usually be the last call.
A custom `fun` must always include a call to `S7_dispatch()`, which will usually be the last call.

### Add required arguments

Expand Down Expand Up @@ -213,7 +213,7 @@ The only downside to performing error checking is that you constraint the interf

## `super()`

Sometimes it's useful to define a method for in terms of its superclass.
Sometimes it's useful to define a method for a class that relies on its superclass.
mattheaphy marked this conversation as resolved.
Show resolved Hide resolved
A good example of this is computing the mean of a date --- since dates represent the number of days since 1970-01-01, computing the mean is just a matter of computing the mean of the underlying numeric vector and converting it back to a date.

To demonstrate this idea, I'll first define a mean generic with a method for numbers:
Expand Down Expand Up @@ -256,8 +256,8 @@ This explicitness makes the code easier to understand and will eventually enable

## Multiple dispatch

So far we have focused primarily on single dispatch, i.e. generics where `dispatch_on` is a single string.
It is also possible to supply a length 2 (or more!) vector `dispatch_on` to create a generic that performs multiple dispatch, i.e. it uses the classes of more than one object to find the appropriate method.
So far we have focused primarily on single dispatch, i.e. generics where `dispatch_args` is a single string.
It is also possible to supply a length 2 (or more!) vector `dispatch_args` to create a generic that performs multiple dispatch, i.e. it uses the classes of more than one object to find the appropriate method.

Multiple dispatch is a feature primarily of S4, although S3 includes some limited special cases for arithmetic operators.
Multiple dispatch is heavily used in S4; we don't expect it to be heavily used in S7, but it is occasionally useful.
Expand Down