This allows a user to have fine-grained control over which features they import, and will allow them much more control over
combining features from multiple sources. E.g. a user may not like the way ParsedownExtra has implemented the "footnotes" feature,
and so may wish to utilise an implementation from another source. By implementing each feature as its own `StateBearer`, we give
users the freedom to compose features in a way that works for them.
## Anatomy of the `State` Object
The `State` object, generically, consists of a set of `Configurable`s. The word "set" is important here: only one instance of each
`Configurable` may exist in a `State`. If you need to store related data in a `Configurable`, your `Configurable` needs to handle
this containerisation itself.
`State` has a special property: all `Configurable`s "exist" in any `State` object when retrieving that `Configurable` with `->get`.
This means that retrieval cannot fail when using this method, though does mean that all `Configurable`s need to be "default constructable" (i.e. can be constructed into a "default" state). All `Configurable`s must therefore implement the static method
`initial`, which must return an instance of the given `Configurable`. No initial data will be provided, but the `Configurable`**must** arrive at some sane default instance.
`Configurable`s must also be immutable, unless they declare themeslves otherwise by implementing the `MutableConfigurable` interface.
### Blocks
One of the "core" `Configurable`s in Parsedown is `BlockTypes`. This contains a mapping of "markers" (a character that Parsedown
looks for, before handing off to the block-specific parser), and a list of `Block`s that can begin parsing from a specific marker.
Also contained, is a list of "unmarked" blocks, which Parsedown will hand off to prior to trying any marked blocks. Within marked
blocks there is also a precedence order, where the first block type to successfully parse in this list will be the one chosen.
The default value given by `BlockTypes::initial()` consists of Parsedown's default blocks. The following is a snapshot of this list:
If `InlineTypes` were mutable, this change would not only affect decendent parsing, but would also affect all parsing which occured after our link was parsed (i.e. would stop URL parsing from that point on in the document).
Another use case for this is implementing a recursion limiter (which *is* implemented as a configurable). After a user-specifiable
max-depth is exceeded: further parsing will halt. The implementaion for this is extremely simple, only because of immutability.
### Mutability
The preference toward immutability by default is not an assertion that "mutability is bad", rather that "unexpected mutability
is bad". By opting-in to mutability, we can treat mutability with the care it deserves.
While immutabiltiy can do a lot to simplify reasoning in the majority of cases, there are some cirumstances where mutability is
required to implement a specific feature. An exmaple of this is found in ParsedownExtra's "abbreviations" feature, which implements
the following:
```php
final class AbbreviationBook implements MutableConfigurable
{
/** @var array<string,string> */
private $book;
/**
*@param array<string,string> $book
*/
public function __construct(array $book = [])
{
$this->book = $book;
}
/** @return self */
public static function initial()
{
return new self;
}
public function mutatingSet(string $abbreviation, string $definition): void
{
$this->book[$abbreviation] = $definition;
}
public function lookup(string $abbreviation): ?string
{
return $this->book[$abbreviation] ?? null;
}
/** @return array<string,string> */
public function all()
{
return $this->book;
}
/** @return self */
public function isolatedCopy(): self
{
return new self($this->book);
}
}
```
Under the hood, `AbbreviationBook` is nothing more than a string-to-string mapping between an abbreviation, and its definition.
The powerful feature here is that when an abbreviation is identified during parsing, that definition can be updated immediately
everywhere, without needing to worry about the current parsing depth, or organise an alternate method to sharing this data. Footnotes
also make use of this with a `FootnoteBook`, with slightly more complexity in what is stored (so that inline references can be