We describe guiding principles used in the code.

Lines with a `function`

or `classdef`

declaration must be standalone, i.e. must not end with a continuation `...`

.

This mean that those lines can go over the column limit (TODO: add link to this limit when we decide on one.)

Whenever possible, we reuse primitive types and do not wrap them in classes.

To perform generic operations upon them, we pass around a “typeclass”, which is a collection of methods/default values for the type.

All typeclasses derive from `Laws`

which provides the test harness for property-based checks.

Permutations are

`1 x n`

vectors containing a permutation of the integers`{1..n}`

, stored as double coefficients.Signed permutations are

`1 x n`

vectors containing the integers`{+/-1..+/-n}`

, such that`abs(signedPerm)`

is a permutation.

Some typeclasses define *domains*, which are mathematical sets.

Domains define the following methods:

`replab.Domain.eqv`

tests for equality,`replab.Domain.sample`

provides a random element of the domain.

Example: `replab.Permutations(10)`

is the domain of permutations acting on 10 elements.

Other typeclasses define relations between domains, such as `replab.Action`

.

Typeclasses that depend on other types contain the typeclasses of those types as properties.
For example, a `replab.Action`

typeclass contain a property `G`

describing the group structure, and a property `P`

describing the domain of elements being acted upon.
There, `G`

and `P`

are domains, while `Action`

itself is not.

Typeclasses can define laws, which are defined as methods in a companion class deriving from `replab.Laws`

. These methods are of the form `law_name_of_the_law_TYPES`

, where `TYPES`

describes the parameters of the law (see `replab.Laws`

).

For each algebraic structure (monoid, group, …), we define:

An abstract base class (ex:

`Monoid`

) with no constructor, where the abstract methods have a body containing an error (see below).A law checking class (ex:

`MonoidLaws`

)(optional) A generic implementation using function handles (ex:

`replab.lambda.Monoid`

)

CamelCase/camelCase follows the separations of US English; words
separated either by a hyphen or a space are separated in the camel case.
Class names are `UpperCamelCase`

. Method and function names are
`lowerCamelCase`

; exception: functions that create objects such as `DihedralGroup`

.

If a computed property is cached, it is implemented using a protected property `expensiveProp_`

, and accessed using a method
`expensiveProp`

that then checks if `expensiveProp_`

has already been computed.

When there is only one implementation of an interface, the constructor is public and can be called directly.

Example: `S4 = replab.Permutations(4)`

When a base interface is available and several optimized implementations
are available, the object should be constructed by calling a function
with the same name as the base interface with a `make`

prefix, in `lowerCamelCase`

.

Example: `c = replab.makeEquivariant(rep1, rep2)`

That function will then construct the object with the best performance characteristics.

As Octave does not support the `methods (Abstract)`

syntax, we provide
generic implementations for abstract methods by having the method body be
a single line with `error('Abstract');`

.

In general, we avoid using methods/functions with a variable number of arguments, as it makes future extensions with optional parameters difficult. Exception: helper methods/function names with `of`

in their names.