February 14, 2020
Hi,

I've released an experimental implementation of the concept of traits/signatures/protocols-ish. The basics seems to work decently well, with very decent error messages e.g.:

source/bolts/experimental/signature.d(111,17): Error: static assert:  "Type Y is missing the following members of enum X: ["three"]
  source/bolts/experimental/signature.d(156): <-- Signature Sig defined here.
  source/bolts/experimental/signature.d(166): <-- Mixed in here."

Package: https://code.dlang.org/packages/bolts
Implementation PR: https://github.com/aliak00/bolts/pull/6/files

I'm not sure about a few things thought and wouldn't mind some feedback.

1. Malleable properties. Take input ranges for example:

struct InputRange(T) {
  bool empty() { return true; }
  // other members...
}

This works:

struct SomeRange(T) {
  mixin ModelsSignature!(InputRange!T));
  bool empty() { return true; }
  // other members...
}

But for variations such as infinite ranges, this will not work

struct SomeRange(T) {
  mixin ModelsSignature!(InputRange!T));
  enum empty = false;
  // other members...
}

The way I'm thinking of handling it right now is by using UDAs?

struct InputRange(T) {
  @onlyAssign
  bool empty;
  // other members...
}

So then the mixin template Models will check if a name has the UDA onlyAssign attached to it, and if so it will be more lenient with the SomeRange struct.

Does anyone have any other suggestions?

2. Naming. Not very happy with onlyAssign, and also ModelsSignature. Any bikesheds? :p

3. Having to implement functions. Like in the InputRange signature above, I had to implement function empty. So for that I'm thinking templates? Something like:

struct Signature {
  mixin Function!("f", int(int, int));
}

Or the like? And the mixin would put in a stubbed function named "f" that returns int.init

Opinions?

Cheers,
- ali
February 19, 2020
On Friday, 14 February 2020 at 21:33:01 UTC, aliak wrote:
> Hi,
> [...]
>
> Cheers,
> - ali

Ok, you can now model an actual input range with most of it's caveats:

interface InputRange(T) {
    @property bool empty();
    @property T front();
    @ignoreAttributes void popFront();
}

struct MyRange {
    mixin Models!(InputRange!int);
}

source/bolts/experimental/signatures.d(341,5): Error: static assert:  "Type MyRange does not comply to signature InputRange!(int)
  Missing identifier empty of type bool.
  Missing identifier front of type int.
  Missing identifier popFront of function type void().
  source/bolts/experimental/signatures.d(8): <-- Signature InputRange!(int) defined here.
  source/bolts/experimental/signatures.d(15): <-- Checked here."

To fix the errors you'd need a name called empty that returns a bool (i.e. is a member variable or a property function). Same with front. And for popFront it can be a function with whichever attributes attached to it.

Not sure what to do with a range model that has "ref T front". Maybe an @ignoreRefness attribute?

Cheers