On Thursday, 30 July 2015 at 10:40:59 UTC, Atila Neves wrote:
On Wednesday, 29 July 2015 at 20:41:02 UTC, Tofu Ninja wrote:
On Wednesday, 29 July 2015 at 20:26:53 UTC, Tofu Ninja wrote:
If you write:

@satisfies!(isInputRange, MyRange) struct MyRange { ... }

the UDA can check it self, it really works as expected. Which is why I suggested a way to get whatever the UDA is attached to automatically in my other post.

A UDA can reference the thing it's being attached to with no problems.
For example, this works 100% as expected right now...

@UDA!testS struct testS // UDA fails to instantiate because testS is not an inputRange!
{
        
}

template UDA(alias a)
{
        import std.range;
        static assert(isInputRange!a);
}

The only thing that would be needed to make this a nice solution is some syntax sugar to automatically get whatever the UDA is attached to, which is why I suggested this:

template UDA(alias a = __UDA_ATTACHMENT__) { ... }

You still wouldn't get a better error message here than with:

struct MyRange {
    ...
    static assert(isInputRange!MyRange);
}

It's less typing, but you still wouldn't know why the static assertion failed. Now, if we make Adam's idiom in my aforementioned pull request the go-to thing, then this would be good:

@satisfies!(checkInputRange, MyRange) struct MyRange { ... }

There's still the problem of having two names for each constraint: checkInputRange and isInputRange. But... we could also establish the convention of checkXXX and use string mixins to turn this:

@satifies!(isInputRange, MyRange)

into (which works cos I just tried it):

template satisfies(alias Constraint, R) {
    enum check = "check" ~ Constraint.stringof[2..$-3] ~ "!(R)";
    enum assert_ = "static assert("~ check ~ ");";
mixin(assert_); //mixes in "static assert(checkInputRange!R)"
}


@satisfies!(isInputRange, Zeroes)
struct Zeroes {
    enum empty = false;
    void popFront() {}
    @property int front() { return 0; }
}


Now, _this_ I could go for.

Atila

The one thing I'm dissatisfied with this proposition is “isInputRange”. Implementing it requires checking that the struct has some methods, and checking that means that “isInputRange” has the information about what methods it should have, and the name suggests that it is done imperatively. Don't we already have something to describe what methods an (conceptual) object should have? Yes we do, that's interfaces and they are declarative which is nice. They are great as reference and for documentation, better than a succession of “static if”. The problem with interfaces is that one has to inherit from them.

I think “isInputRange” in itself is a bad idea hardly reusable. What I would like to see is a way to take an interface and implicitely turn it into an interface checker that would statically check a struct. I'd like to turn:

  @satisfies!(isInputRange, Zeroes)
  struct Zeroes {
      enum empty = false;
      void popFront() {}
      @property int front() { return 0; }
  }

into

  @satisfies!(InputRangeInterface /*whatever the name */, Zeroes)
  struct Zeroes {
      enum empty = false;
      void popFront() {}
      @property int front() { return 0; }
  }

That would be great to get people to properly document their interfaces (good for documentation) without the drawback of having to inherit from them, while still being available for normal interfaces and without any information redundancy.

However, I'm not sure that's possible today... What do you think about it?

Reply via email to