Jump to page: 1 2
Thread overview
Template constraints: opCmp and opUnary!"++"
Dec 20, 2013
Philippe Sigaud
Dec 20, 2013
monarch_dodra
Dec 20, 2013
Timon Gehr
Dec 20, 2013
Philippe Sigaud
Dec 20, 2013
monarch_dodra
Dec 20, 2013
Timon Gehr
Dec 20, 2013
Timon Gehr
Dec 21, 2013
Jakob Ovrum
Dec 20, 2013
monarch_dodra
Dec 20, 2013
Philippe Sigaud
December 20, 2013
I'm trying to experiment a bit around the iota function.
If I try to impose the following constraits:

auto my_iota(B, E)(B begin, E end)
if (is (typeof(++begin)) && is (typeof(begin < end))) {}

Everything works as it should, but according to "D Templates: A Tutorial" book, you should not use arguments in constraints.
If I try doing something like:

auto my_iota(B, E)(B begin, E end)
if (is (typeof(++B.init)) && is (typeof(B.init < E.init))) {}

the code stops compiling for integers.
On the other hand the code

auto my_iota(B, E)(B begin, E end)
if (is (typeof(++B)) && is (typeof(B < E))) {}

fails to compile for both integers and my defined types.
I read the "D Templates: A Tutorial" book and as far as I can tell "++B.init" and "B.init < E.init" doesn't look too much wrong, but I've not seen any constraint of this kind in phobos (using variables instead of types) so I was wondering if doing something like this is actually bad or even really bad. (And I also wonder how to properly setting those constraints directly on types)
December 20, 2013
> fails to compile for both integers and my defined types.
> I read the "D Templates: A Tutorial" book and as far as I can tell
> "++B.init" and "B.init < E.init" doesn't look too much wrong, but I've not
> seen any constraint of this kind in phobos (using variables instead of
> types) so I was wondering if doing something like this is actually bad or
> even really bad. (And I also wonder how to properly setting those
> constraints directly on types)

You could put the target code inside a anonymous block and use
__traits(compiles, ...), like this:

if (__traits(compiles, {
    B begin;
    E end;
    ++begin;
    bool stop = begin < end;
}))

I never hade any problem by using Type.init, that's strange.
December 20, 2013
On Friday, 20 December 2013 at 15:38:56 UTC, Francesco Cattoglio
wrote:
> I'm trying to experiment a bit around the iota function.
> If I try to impose the following constraits:
>

>
> Everything works as it should, but according to "D Templates: A Tutorial" book, you should not use arguments in constraints.

That's news to me.

> If I try doing something like:
>
> auto my_iota(B, E)(B begin, E end)
> if (is (typeof(++B.init)) && is (typeof(B.init < E.init))) {}
>
> the code stops compiling for integers.

That's normal, because "T.init" is not an lvalue.

If you need an lvalue, we have `std.traits.lvalueOf!T` which you
can use.

That said:

> auto my_iota(B, E)(B begin, E end)
> if (is (typeof(++begin)) && is (typeof(begin < end))) {}

Seems perfectly legit to me.

> On the other hand the code
>
> auto my_iota(B, E)(B begin, E end)
> if (is (typeof(++B)) && is (typeof(B < E))) {}
>
> fails to compile for both integers and my defined types.

"B" is a type, so "++B" will always resolve to "__error", unless
you've implemented a static operator (not sure if even legal?).
December 20, 2013
On 12/20/2013 05:40 PM, monarch_dodra wrote:
>
> That's normal, because "T.init" is not an lvalue.
>
> If you need an lvalue, we have `std.traits.lvalueOf!T` which you
> can use.

is(typeof((T v){ /+ use v +/ }))

I think this is a lot cleaner.
December 20, 2013
On Friday, 20 December 2013 at 16:40:23 UTC, monarch_dodra wrote:
>> Everything works as it should, but according to "D Templates: A Tutorial" book, you should not use arguments in constraints.
>
> That's news to me.
It seems strange to me too, but: page 69 on the PDF:
"Do not use argument in your constraint. If you need a value of type T, use T.init."
Since I don't know D really well, I thought something was wrong with it.
> That's normal, because "T.init" is not an lvalue.
Right! I was suspecting something like this.

> That said:
> Seems perfectly legit to me.
Then I'll probably stick to it. It's simple, easy to understand, and works.
Or maybe the __traits(compiles) actually looks even better.

> "B" is a type, so "++B" will always resolve to "__error", unless
> you've implemented a static operator (not sure if even legal?).
Best part is: ++B actually works, it's the B < E that fails. But they both smelled bad.
Perhaps ++B is some kind of accept-invalid bug then?
December 20, 2013
On Friday, 20 December 2013 at 17:18:01 UTC, Timon Gehr wrote:
> On 12/20/2013 05:40 PM, monarch_dodra wrote:
>>
>> That's normal, because "T.init" is not an lvalue.
>>
>> If you need an lvalue, we have `std.traits.lvalueOf!T` which you
>> can use.
>
> is(typeof((T v){ /+ use v +/ }))
>
> I think this is a lot cleaner.

Is there any difference between "is(typeof(<somecode>))" and __traits(compiles, <somecode>)?
December 20, 2013
On Fri, Dec 20, 2013 at 6:33 PM, Francesco Cattoglio <francesco.cattoglio@gmail.com> wrote:

> Is there any difference between "is(typeof(<somecode>))" and
> __traits(compiles, <somecode>)?

I find the latter cleaner: its intent is more apparent. I use
is(typeof()) only for really testing for type existence.
December 20, 2013
On Fri, Dec 20, 2013 at 6:31 PM, Francesco Cattoglio <francesco.cattoglio@gmail.com> wrote:
> On Friday, 20 December 2013 at 16:40:23 UTC, monarch_dodra wrote:
>>>
>>> Everything works as it should, but according to "D Templates: A Tutorial" book, you should not use arguments in constraints.
>>
>>
>> That's news to me.
>
> It seems strange to me too, but: page 69 on the PDF:
> "Do not use argument in your constraint. If you need a value of type T, use
> T.init."
> Since I don't know D really well, I thought something was wrong with it.

Well I wrote this, so I should explain :-)

I'm pretty sure at one time, using direct symbols led to strange behavior. And I'm still not sure symbol have values when used in template constraints. What happens when you try ++a on such a symbol?

But then, if people tell me using these values directly is perfectly OK, I'll update the text, of course.
December 20, 2013
On Friday, 20 December 2013 at 17:48:03 UTC, Philippe Sigaud wrote:
> On Fri, Dec 20, 2013 at 6:33 PM, Francesco Cattoglio
> <francesco.cattoglio@gmail.com> wrote:
>
>> Is there any difference between "is(typeof(<somecode>))" and
>> __traits(compiles, <somecode>)?
>
> I find the latter cleaner: its intent is more apparent. I use
> is(typeof()) only for really testing for type existence.

AFAIK, there is no real difference, but "is(typeof())" is more "idiomatic" in phobos.
December 20, 2013
On Friday, 20 December 2013 at 17:18:01 UTC, Timon Gehr wrote:
> On 12/20/2013 05:40 PM, monarch_dodra wrote:
>>
>> That's normal, because "T.init" is not an lvalue.
>>
>> If you need an lvalue, we have `std.traits.lvalueOf!T` which you
>> can use.
>
> is(typeof((T v){ /+ use v +/ }))
>
> I think this is a lot cleaner.

I dunno. Being forced to declare a scope and a list of variables just to have access to an lvalue instance seems a bit verbose to me. I *think* doing this can lead to issues if done inside an inout context (not certain about this. It's a buggy behavior anywyas, Kenji told me, so not a real argument).

For example:
enum isAssignable(Lhs, Rhs = Lhs) =
    __traits(compiles, lvalueOf!Lhs = lvalueOf!Rhs);

vs

enum isAssignable(Lhs, Rhs = Lhs) =
    __traits(compiles, (Lhs lhs, Rhs rhs){lhs = rhs});

Hum... Actually, I'm not sure which is cleanest. You do bring up a good point. Plus, it solves the whole "initialization issue" we've been having. Why haven't e been using this up to now...?

For example, std.range has a lot of:

template isInputRange(R)
{
    enum bool isInputRange = is(typeof(
    (inout int = 0)
    {
        R r = void;       // can define a range object
        if (r.empty) {}   // can test for empty
        r.popFront();     // can invoke popFront()
        auto h = r.front; // can get the front of the range
    }));
}

The line "R r = void;" has led to problems before. Why haven't we just used:
template isInputRange(R)
{
    enum bool isInputRange = is(typeof(
    (R r, inout int = 0)
    {
        if (r.empty) {}   // can test for empty
        r.popFront();     // can invoke popFront()
        auto h = r.front; // can get the front of the range
    }));
}

« First   ‹ Prev
1 2