The previous tutorial introduced S3 and piping into distr6, allowing different approaches to calling R6 methods. In this tutorial we take a look at a big feature of distr6, decorators.

Note: Decorators in distr6 are still maturing, this means the API is still subject to minor changes and the internal computations may be improved, therefore we are aware performance may be sub-optimal.

In object-oriented programming it is common to discuss ‘Design
Patterns’ as specific methods used to solve coding problems, decorators
are one of these ‘patterns’. For full definitions and details about
design patterns, we refer the reader to the seminal Design Patterns
textbook (Gamma et al. 1994). Briefly, the
decorator design pattern is used to add functionality to an object. For
example, say we have a class that only has a `print`

method
and a decorator for `summary`

methods. Then the user can
either use the object by itself with the `print`

method only
or optionally you can ‘decorate’ the object and thereby use the
`summary`

method. This is perhaps confusing in the abstract,
so lets work through an example in distr6. We will go through a quick
example and then return to which decorators are available and how they
are used in distr6:

```
N <- Normal$new()
N$survival(1)
#> Error in eval(expr, envir, enclos): attempt to apply non-function
decorate(N, "ExoticStatistics")
#> Normal is now decorated with ExoticStatistics
#> Norm(mean = 0, var = 1)
N$survival(1)
#> [1] 0.1586553
```

In the example above we:

- Constructed a Normal distribution
- Demonstrated that the
`survival`

method does not exist - Decorated the distribution with the
`ExoticStatistics`

decorator - Successfully evaluated the survival function

The CoreStatistics decorator includes methods for numeric
calculations, a generalised moments `kthmoment`

function and
a generalised expectation method `genExp`

. All methods can be
viewed using `?CoreStatistics`

. In distr6 we have a strict
design principle that only analytic results should be provided as
methods in distributions, i.e. we only return results for which we know
the output is 100% accurate. The `CoreStatistics`

decorator
allows you to return numeric results when analytic ones aren’t
available. For example,

```
w <- Weibull$new()
# Error as the characteristic function doesn't exist
w$cf(1)
#> Error in eval(expr, envir, enclos): attempt to apply non-function
decorate(w, "CoreStatistics")
#> Weibull is now decorated with CoreStatistics
#> Weibull(scale = 1, shape = 1)
# Warning as numerical integration used
w$cf(5)
#> Results from numeric calculations are approximate only. Better results may be available.
#> Results from numeric calculations are approximate only. Better results may be available.
#> [1] 0.0384616+0.1923076i
```

The decorator also introduces generalised moment and expectation
methods. The help documentation for these `?kthmoment`

and
`?genExp`

give a full overview to these methods, but both are
very useful for modelling, inference and deriving other numeric
results.

The ExoticStatistics decorator includes more complex numeric methods
as well as survival, hazard and cumulative hazard that may or may not be
analytic expressions (depending what is available in the distribution
object). Once again all the methods added by this decorator can be
viewed using `?ExoticStatistics`

. For example,

```
N <- Normal$new()
# Error as the characteristic function doesn't exist
N$hazard(1)
#> Error in eval(expr, envir, enclos): attempt to apply non-function
decorate(N, "ExoticStatistics")
#> Normal is now decorated with ExoticStatistics
#> Norm(mean = 0, var = 1)
# No warning as an analytic expression using pdf and cdf are used
N$hazard(1)
#> [1] 1.525135
# Warning as numeric calculations are used
N$pdfPNorm(2,0,4)
#> Results from numeric calculations are approximate only. Better results may be available.
#> [1] 0.3755628
```

The final implemented decorator is used to impute missing d/p/q/r
methods. We will return to the `FunctionImputation`

decorator
in a future
tutorial which looks at constructing custom distributions.

There are two main ways to decorate distributions in distr6, either in construction or after construction. We show these by example:

In Construction

```
Normal$new(decorators = "CoreStatistics")
#> Norm(mean = 0, var = 1)
Normal$new(decorators = c("CoreStatistics", "ExoticStatistics"))
#> Norm(mean = 0, var = 1)
```

After Construction

```
N <- Normal$new()
decorate(N, "CoreStatistics")
#> Normal is now decorated with CoreStatistics
#> Norm(mean = 0, var = 1)
```

And that’s all there is to it! If you forget which decorators are
available, just run `listDecorators()`

, or
`listDecorators(simplify = FALSE)`

if you want to see which
methods they include at the same time.

In this tutorial we looked at decorators in distr6 to obtain numeric results, methods for statistical modelling and imputation methods for missing d/p/q/r functions. In the next tutorial we look at the next big feature in distr6, wrappers.