Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 158 additions & 0 deletions module_notes/phobos/sys/meta.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# Overview

This provides some notes on the design of phobos.sys.meta.

phobos.sys.meta is a port of Phobos v2's std.meta with changes where
appropriate. The basic goal of the module is the same in that it's supposed to
be providing templates that do metaprogramming on `AliasSeq`s - essentially a
std.algorithm for `AliasSeq`s instead of ranges.

phobos.sys.meta has fewer symbols than std.meta primarily because it's best to
use CTFE rather than template metaprogramming where possible and because a
number of the templates in std.meta are of questionable utility. Clearly,
_someone_ thought that they would be useful, or they wouldn't have been added,
but Phobos either doesn't use them at all or barely uses them, making it
questionable that we want them in the standard library. So, while we may add
some of those symbols later, for now at least, if a symbol doesn't seem like
it's generally useful, it's not being ported.

A major functionality change between std.meta and phobos.sys.meta is that
various templates in std.meta compare the elements in an `AliasSeq` - typically
using a private template which tries to do a bunch of different kinds of
comparisons with the behavior changing depending on whether the element can be
compared with `==`, an `is` expression, or `__traits(isSame, ...)`. This has
proven to be incredibly error-prone with some weird and unexpected behaviors
(e.g. whether a no-argument function is treated as a value or as a symbol
depends on what it's being compared against as well as which side of the
comparison it's on). And in general, operating on an `AliasSeq` that's a
mixture of types, values, and symbols is just a mess. So, instead of having
phobos.sys.meta's templates provide any sort of comparison, they instead now
take template predicates (typically a trait from phobos.sys.traits) so that the
programmer can decide how the comparison is done. So, ultimately, the same
functionality is provided, but it's under the control of the programmer, making
it much more flexible and less error-prone.

Another functionality change is that std.meta is inconsistent about whether a
template that does a comparison short-circuits evaluation, whereas
phobos.sys.meta's templates do not short-circuit evaluation - both for the sake
of consistency, and because it allows for more efficient implementations. Also,
given that some of the elments in an `AliasSeq` might not even compile if they
are evaluated (e.g. because the predicate assumes a type, and an element is a
value), it's arguably better to evaluate all of the elements and catch such
bugs.

With regards to the name changes, to better follow the official style guide,
any templates that evaluate to a value are camelCased, any templates which
evaluate to a type are PascalCased, and any templates which evaluate to an
`AliasSeq` (and thus could contain a combination of values, types, or symbols)
are PascalCased. Also, various names have been changed in order to improve
consistency. "static" and "template" have been removed from all of the names,
since they're not necessary, and neither is a convention that has ever been
followed consistently (even within std.meta). Presumably, in at least some of
the cases, it was done to prevent conflicts with symbols in std.algorithm, but
the module system already gives us a clean way to distinguish between symbols
with the same name but which are in different modules.

---
# Symbols

## Alias

* The Phobos v2 equivalent is [`std.meta.Alias`](../../std/meta.md#alias).
* Its functionality is unchanged.

## AliasSeq

* The Phobos v2 equivalent is [`std.meta.AliasSeq`](../../std/meta.md#aliasseq).
* Its functionality is unchanged.

## all

* The Phobos v2 equivalent is [`std.meta.allSatisfy`](../../std/meta.md#allsatisfy).
* It's been renamed to better match std.algorithm's `all`, and because having
"Satisfy" in the name is redundant, since that's true of any template which evaluates
to `true` or `false` based on a predicate.
* Its functionality is unchanged.

## And

* The Phobos v2 equivalent is [`std.meta.templateAnd`](../../std/meta.md#templateand).
* It's been renamed to better follow the official naming conventions.
* Its functionality is essentially the same. However, unlike
[`templateAnd`](../../std/meta.md#templateand), `And` does not short-circuit its
evaluation (something which std.meta in general is inconsistent about).

## any

* The Phobos v2 equivalent is [`std.meta.anySatisfy`](../../std/meta.md#anysatisfy).
* It's been renamed to better match std.algorithm's `any`, and because having
"Satisfy" in the name is redundant, since that's true of any template which evaluates
to `true` or `false` based on a predicate.
* Its functionality is unchanged.

## ApplyLeft

* The Phobos v2 equivalent is [`std.meta.ApplyLeft`](../../std/meta.md#applyleft).
* Its functionality is unchanged.

## ApplyRight

* The Phobos v2 equivalent is [`std.meta.ApplyRight`](../../std/meta.md#applyright).
* Its functionality is unchanged.

## Filter

* The Phobos v2 equivalent is [`std.meta.Filter`](../../std/meta.md#filter).
* Its functionality is unchanged.

## indexOf

* The Phobos v2 equivalent is [`std.meta.staticIndexOf`](../../std/meta.md#staticindexof).
* It's been renamed to better follow the official naming conventions.
* It now takes a template predicate to use for the comparison.

## Instantiate

* The Phobos v2 equivalent is [`std.meta.Instantiate`](../../std/meta.md#instantiate).
* Its functionality is unchanged.

## Map

* The Phobos v2 equivalent is
[`std.meta.staticMap`](../../std/meta.md#staticmap).
* It's been renamed to better follow the official naming conventions.
* Its functionality is unchanged.

## Not

* The Phobos v2 equivalent is [`std.meta.templateNot`](../../std/meta.md#templatenot).
* It's been renamed to better follow the official naming conventions.
* Its functionality is essentially the same. However, unlike
[`templateNot`](../../std/meta.md#templatenot), `Not` does not short-circuit its
evaluation (something which std.meta in general is inconsistent about).

## Or

* The Phobos v2 equivalent is [`std.meta.templateOr`](../../std/meta.md#templateor).
* It's been renamed to better follow the official naming conventions.
* Its functionality is essentially the same. However, unlike
[`templateOr`](../../std/meta.md#templateor), `Or` does not short-circuit its
evaluation (something which std.meta in general is inconsistent about).

## Reverse

* The Phobos v2 equivalent is [`std.meta.Reverse`](../../std/meta.md#reverse).
* Its functionality is unchanged.

## Stride

* The Phobos v2 equivalent is [`std.meta.Stride`](../../std/meta.md#stride).
* Its functionality is unchanged.

## Unique

* The Phobos v2 equivalent is [`std.meta.NoDuplicates`](../../std/meta.md#noduplicates).
* It's been renamed to be more in line with std.algorithm's `uniq`, which will
probably be renamed to `unique` due to Adam Wilson being against truncated
names.
* It now takes a template predicate to use for the comparison.
160 changes: 160 additions & 0 deletions module_notes/std/meta.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Overview

This provides information on the symbols in std.meta with regards to what's
happening to them in Phobos v3. Either it indicates which Phobos v3 symbol
should be used instead, or it explains why that symbol hasn't been ported to
Phobos v3.

[`phobos.sys.meta`](../phobos/sys/meta.md) is the Phobos v3 replacement for
std.meta, so in general, that's where the symbols from std.meta have been
ported to, but not all are getting ported, and some of them have had their
names and/or functionality changed in the process.

---
# Symbols

## Alias

* See [`phobos.sys.meta.Alias`](../phobos/sys/meta.md#alias).

## AliasSeq

* See [`phobos.sys.meta.AliasSeq`](../phobos/sys/meta.md#aliasseq).

## aliasSeqOf

* There are no plans to port it over to Phobos v3.
* Its usefulness is questionable, and it's barely used in Phobos v2.
* Also, even if we do decide to port it over, the current implementation
requires std.array.array, which has not yet been ported to Phobos v3.

## allSatisfy

* See [`phobos.sys.meta.all`](../phobos/sys/meta.md#all).

## anySatisfy

* See [`phobos.sys.meta.any`](../phobos/sys/meta.md#any).

## ApplyLeft

* See [`phobos.sys.meta.ApplyLeft`](../phobos/sys/meta.md#applyleft).

## ApplyRight

* See [`phobos.sys.meta.ApplyRight`](../phobos/sys/meta.md#applyright).

## DerivedToFront

* There are no plans to port it over to Phobos v3.
* Its usefulness is questionable, and it's not used anywhere in Phobos v2
outside of std.meta.

## Erase

* There are no plans to port it over to Phobos v3.
* Its usefulness is questionable, and it's currently used in only one place in
Phobos v2 outside of std.meta.
* It's arguably a trivial wrapper around [`staticIndexOf`](#staticindexof),
which would arguably still be useful if it were needed frequently, but it
isn't.
* If we do decide to add it, it will need to be reworked to take a template
predicate (which [`phobos.sys.meta.indexOf`](../phobos/sys/meta.md#indexof)
would require, unlike [`staticIndexOf`](#staticindexof)). So, it would
essentially become a version of [`Filter`](../phobos/sys/meta.md#filter) that
stopped after matching a single element (or after encountering an element
which didn't match). So, if we _do_ decide to add something along these lines
to Phobos v3, we should probably add something like `FilterUntil` rather than
actually port over `Erase`. Ultimately though, it's probably better to have
code that wants `Erase` to just use
[`indexOf`](../phobos/sys/meta.md#indexof), particularly since it does not
appear to be a common use case.

## EraseAll

* There are no plans to port it over to Phobos v3.
* [`Filter`](../phobos/sys/meta.md#filter) can be used instead, since `EraseAll` is
essentially [`Filter`](../phobos/sys/meta.md#filter) with a predicate for
comparing the elements which is supplied by std.meta (and it's a predicate
that we really don't want to continue to use given how quirky and error-prone
it is).

## Filter

* See [`phobos.sys.meta.Filter`](../phobos/sys/meta.md#filter).

## Instantiate

* See [`phobos.sys.meta.Instantiate`](../phobos/sys/meta.md#instantiate).

## MostDerived

* There are no plans to port it over to Phobos v3.
* Its usefulness is questionable, and it's currently used in only one place in
Phobos v2 outside of std.meta.

## NoDuplicates

* See [`phobos.sys.meta.Unique`](../phobos/sys/meta.md#unique).

## Repeat

* There are no plans to port it over to Phobos v3.
* Its usefulness is questionable, and it's not used anywhere in Phobos v2
outside of std.meta.

## Replace

* There are no plans to port it over to Phobos v3.
* Its usefulness is questionable, and it's currently used in only one place in
Phobos v2 outside of std.meta.

## ReplaceAll

* There are no plans to port it over to Phobos v3.
* Its usefulness is questionable, and it's not used anywhere in Phobos v2
outside of std.meta.

## Reverse

* See [`phobos.sys.meta.Reverse`](../phobos/sys/meta.md#reverse).

## staticIndexOf

* See [`phobos.sys.meta.indexOf`](../phobos/sys/meta.md#indexof).

## staticMap

* See [`phobos.sys.meta.Map`](../phobos/sys/meta.md#map).

## staticIsSorted

* There are no plans to port it over to Phobos v3.
* It does seem like it _might_ be useful under some set of circumstances, but
it's not actually used anywhere in Phobos v2 outside of std.meta. So, it's
certainly not something that seems like it fundamentally shouldn't be
included, but it also doesn't seem to be particularly useful in practice.

## staticSort

* There are no plans to port it over to Phobos v3.
* It does seem like it _might_ be useful under some set of circumstances, but
it's not actually used anywhere in Phobos v2 outside of std.meta. So, it's
certainly not something that seems like it fundamentally shouldn't be
included, but it also doesn't seem to be particularly useful in practice.

## Stride

* See [`phobos.sys.meta.Stride`](../phobos/sys/meta.md#stride).

## templateAnd

* See [`phobos.sys.meta.And`](../phobos/sys/meta.md#and).

## templateNot

* See [`phobos.sys.meta.Not`](../phobos/sys/meta.md#not).

## templateOr

* See [`phobos.sys.meta.Or`](../phobos/sys/meta.md#or).