Adding to a global AliasSeq
Basile B.
b2.temp at gmx.com
Tue Aug 15 07:02:45 UTC 2023
On Tuesday, 15 August 2023 at 02:30:37 UTC, repr_man wrote:
> Consider the following template mixin:
> ```d
> mixin template Base()
> {
> int x(){ return 10; }
> }
> ```
> It could be used in a variety of structs as follows:
> ```d
> struct Child
> {
> mixin Base!();
> }
> ```
> Now, let's suppose we write a function with a parameter that
> should only be able to take items that mix in `Base`:
> ```d
> auto f(T)(T arg)
> {
> return arg.x;
> }
> ```
> This works because D uses structural subtyping. However, this
> creates a problem: if we make another struct that looks like it
> mixes in `Base` and pass it to the function, we could get
> unexpected results:
> ```d
> struct Other
> {
> int x = 5;
> }
>
> unittest
> {
> import std.stdio;
>
> auto c = Child();
> auto o = Other();
>
> writeln(f(c));
> writeln(f(o));
> }
> ```
> The output from running `dub test` is as follows:
> ```
> 10
> 5
> ```
> [...]
> Is there any template-fu of which I am not aware that would
> make the thing I am trying to do possible?
You can add a kind of tag with the mixin, that will allow to to
test if the type supplied to `f` is well a Base implementor:
```d
mixin template Base()
{
enum LookImABase = true;
int x(){ return 10; }
}
struct Child
{
mixin Base!();
}
auto f(T)(T arg)
if (is(typeof(T.LookImABase)))
{
return arg.x;
}
struct Other
{
int x = 5;
}
void main(string[] args)
{
import std.stdio;
auto c = Child();
auto o = Other();
writeln(f(c)); // ok
writeln(f(o)); // error
}
```
This is what is called in D the "design by introspection". There
are alternatives way of doing that, notably with UDAs.
```d
mixin template Base()
{
enum Base;
@Base int x(){ return 10; }
}
```
But the introspection code is more complex (std.traits getUDA,
hasUDA)
Finally a different approach, with no introspection, is to use a
named mixin:
```d
mixin template Base()
{
enum Base;
int x(){ return 10; }
}
struct Child
{
mixin Base!() base;
}
auto f(T)(T arg)
{
return arg.base.x;
}
struct Other
{
int x = 5;
}
void main(string[] args)
{
import std.stdio;
auto c = Child();
auto o = Other();
writeln(f(c));
writeln(f(o)); // error
}
```
which works but has the same problem as what lead you to ask your
question, for example if it turns out that the supplied argument
has unfortunately a `base` member that itself has a `x` member.
More information about the Digitalmars-d-learn
mailing list