concepts ~update
Concepts for D
To use this package, run the following command in your project's root directory:
Manual usage
Put the following dependency into your project's dependences section:
Concepts for D
Template constraints in D are one the language's best
features. However, when a constraint fails it can be hard to know
why it failed. This library tries to remedy that by providing a way
to specify that user-defined types are supposed to implement a
compile-time interface, or concept. An example would be
isInputRange
. If you happen to, say, spell empty
as empt
by
mistake your type would not be an input range, but you wouldn't know
why that's the case even though the compiler does. The fix is to use
models
, which can be used as a UDA or in a static assert:
import concepts.models: models;
void checkFoo(T)()
{
T t = T.init;
t.foo();
}
enum isFoo(T) = is(typeof(checkFoo!T));
@models!(Foo, isFoo) //as a UDA
struct Foo
{
void foo() {}
static assert(models!(Foo, isFoo)); //as a static assert
}
// can still be used as a template constraint:
void useFoo(T)(auto ref T foo) if(isFoo!T) {
}
Here a template constraint isFoo
is guaranteed to be true for type Foo
.
The difference between this and a regular static assert is that when the
predicate fails the code for checkFoo
is instantiated anyway so that
the user knows why it failed to compile. Example error message with dmd 2.074:
source/concepts/models.d(111,10): Error: no property 'foo' for type 'Foo', did you mean 'fo'?
source/concepts/models.d-mixin-42(42,1): Error: template instance concepts.models.checkFoo!(Foo) error instantiating
source/concepts/models.d(61,6): instantiated from here: models!(Foo, isFoo)
This library also implements its own versions of the range template
constraints from Phobos so that they can be used with models
:
import concepts: models, isInputRange;
@models!(Foo, isInputRange)
struct Foo {
// ...
}
Example error message with dmd 2.074 (having implemented front
and popFront
but not empty
):
source/concepts/range.d(13,10): Error: template std.range.primitives.empty cannot deduce function from argument types !()(B), candidates are:
/usr/include/dlang/dmd/std/range/primitives.d(2043,16): std.range.primitives.empty(T)(in T[] a)
source/concepts/models.d-mixin-42(42,1): Error: template instance concepts.range.checkInputRange!(B) error instantiating
source/concepts/range.d(72,6): instantiated from here: models!(B, isInputRange)
Using a D interface
to specify compile-time template constraints
interface IFoo {
int foo(int i, string s) @safe;
double lefoo(string s) @safe;
}
@implements!(Foo, IFoo)
struct Foo {
int foo(int i, string s) @safe { return 0; }
double lefoo(string s) @safe { return 0; }
}
// doesn't compile
/*
@implements!(Oops, IFoo)
struct Oops {}
*/
Other examples
Contraining a struct to not have member functions (credit to @jmh530):
void checkOnlyData(T)()
if (is(T == struct))
{
import std.traits : isFunction;
static foreach (mem; __traits(allMembers, T))
{
static if (mem != "this")
{
static assert(!(isFunction!(__traits(getMember, T.init, mem))),
T.stringof ~ " is constrained to not have any member functions, but it has (at least) the member function: " ~ mem);
}
}
}
template isOnlyData(T)
if (is(T == struct))
{
enum isOnlyData = is(typeof(checkOnlyData!(T)));
}
@models!(Foo, isOnlyData)
struct Foo
{
int a;
}
Foo foo;
- Registered by Atila Neves
- ~update released 2 years ago
- atilaneves/concepts
- BSD
- Copyright © 2016, Atila Neves
- Authors:
- Dependencies:
- none
- Versions:
-
0.1.0 2023-Feb-07 0.0.9 2022-Oct-04 0.0.8 2018-Nov-11 0.0.7 2017-Sep-02 0.0.6 2017-May-04 - Download Stats:
-
-
17 downloads today
-
129 downloads this week
-
563 downloads this month
-
166674 downloads total
-
- Score:
- 4.4
- Short URL:
- concepts.dub.pm