September 23, 2012
On Sunday, September 23, 2012 14:47:27 Timon Gehr wrote:
> template Hello(R) if(is(typeof(R._input.takeExactly(2)) == R)){
>      alias R Hello;
> }

Thanks. That does the trick quite cleanly, though you'd think that it would be possible to test whether a template argument is the result of takeExactly without caring or knowing about the guts of takeExactly. So, this isn't a general purpose solution at all, when I think that there should be one. Still, I don't need a general purpose one for what I'm doing, so this should work just fine.

- Jonathan M Davis
September 24, 2012
On Sunday, 23 September 2012 at 21:52:23 UTC, Timon Gehr wrote:
> On 09/23/2012 10:57 PM, Ali Çehreli wrote:
>> ...
>>
>> Also, I think your code should have passed a range like R.init to
>> takeExactly, not R, which is a type:
>>
>>   takeExactly(R.init, 1)
>>
>> I don't know why your code compiles.
>>
>
> See discussion here:
> http://d.puremagic.com/issues/show_bug.cgi?id=8220

Interesting. Thanks.

On Sunday, 23 September 2012 at 21:53:20 UTC, Jonathan M Davis wrote:
> On Sunday, September 23, 2012 14:47:27 Timon Gehr wrote:
>> template Hello(R) if(is(typeof(R._input.takeExactly(2)) == R)){
>>      alias R Hello;
>> }
>
> Thanks. That does the trick quite cleanly, though you'd think that it would be
> possible to test whether a template argument is the result of takeExactly
> without caring or knowing about the guts of takeExactly. So, this isn't a
> general purpose solution at all, when I think that there should be one. Still,
> I don't need a general purpose one for what I'm doing, so this should work
> just fine.
>
> - Jonathan M Davis

What is wrong with my proposed solution?

----
import std.range;

template Hello(R)
    if ( is(typeof(takeExactly(R.init, 1))) &&
         is(R == typeof(takeExactly(R.init, 1)))
    )
{
    alias R Hello;
}

struct R
{
    enum empty = false;
    @property int front();
    void popFront();
}

struct S{}

void main( ) {
     Hello!(int[]) a; //OK
     Hello!R b;       //Fails second Check: R == typeof(...)
     Hello!S c;       //Fails first check: is(typeof(takeExactly(...)))
}
----

Forgive me again if there is something wrong with it, but this time, I think it is correct...?
September 24, 2012
On Monday, 24 September 2012 at 06:20:57 UTC, monarch_dodra wrote:
> What is wrong with my proposed solution?

I think I forgot this test, when R is already a type returned by takeExactly:

void main( ) {
     alias typeof(takeExactly(R.init, 5)) G;
     Hello!G g;
}

Which also works.
September 24, 2012
On Monday, 24 September 2012 at 06:29:25 UTC, monarch_dodra wrote:
> On Monday, 24 September 2012 at 06:20:57 UTC, monarch_dodra wrote:
>> What is wrong with my proposed solution?
>
> I think I forgot this test, when R is already a type returned by takeExactly:
>
> void main( ) {
>      alias typeof(takeExactly(R.init, 5)) G;
>      Hello!G g;
> }
>
> Which also works.

Er, sorry for triple post, no edit button.

This is R:

struct R
{
    enum empty = false;
    @property int front();
    void popFront();
}

I meant when "Hello' R is already the result of a Take exactly", sorry for the confusion.
September 24, 2012
On Monday, September 24, 2012 08:21:46 monarch_dodra wrote:
> template Hello(R)
>      if ( is(typeof(takeExactly(R.init, 1))) &&
>           is(R == typeof(takeExactly(R.init, 1)))
>      )
> {
>      alias R Hello;
> }

> What is wrong with my proposed solution?

It may work, but again, it's relying on how takeExactly works. It's testing that you can call takeExactly on R.init and then that R is the same type as that result, which means that it's relies on the fact that takeExactly returns itself if you call takeExactly on it. It also relies on init, which can be risky, given the fact that it can be disabled.

So, between your prosposal and the other that Philippe and Timon gave, theirs seems better. But unfortunately, none of the proposals work generically. Ideally, there would be a way to generically test that a type is the type returned by particular function, and I would _think_ that that's possible, but the way that I would expect to work doesn't.

Regardless, thanks for your help.

- Jonathan M Davis
September 24, 2012
On Monday, 24 September 2012 at 07:07:16 UTC, Jonathan M Davis
wrote:
> On Monday, September 24, 2012 08:21:46 monarch_dodra wrote:
>> template Hello(R)
>>      if ( is(typeof(takeExactly(R.init, 1))) &&
>>           is(R == typeof(takeExactly(R.init, 1)))
>>      )
>> {
>>      alias R Hello;
>> }
>
>> What is wrong with my proposed solution?
>
> It may work, but again, it's relying on how takeExactly works. It's testing
> that you can call takeExactly on R.init and then that R is the same type as
> that result, which means that it's relies on the fact that takeExactly returns
> itself if you call takeExactly on it. It also relies on init, which can be
> risky, given the fact that it can be disabled.
>
> So, between your prosposal and the other that Philippe and Timon gave, theirs
> seems better. But unfortunately, none of the proposals work generically.
> Ideally, there would be a way to generically test that a type is the type
> returned by particular function, and I would _think_ that that's possible, but
> the way that I would expect to work doesn't.
>
> Regardless, thanks for your help.
>
> - Jonathan M Davis

Good points.

Regarding the ".init" issue, I hadn't thought of that, but it can
be worked around pretty easily with an is(R r):

--------
template Hello(R)
     if ( is(R r) &&
          is(typeof(takeExactly(r, 1))) &&
          is(R == typeof(takeExactly(r, 1)))
     )
{
     alias R Hello;
}
--------
After that, I guess it is indeed one implementation detail vs the
other.

IMO, it really depends on whether or not you'd want "int[]" to be
considered the return type of a takeExactly :/ Maybe it is, maybe
it ain't.
September 24, 2012
On Monday, September 24, 2012 09:41:26 monarch_dodra wrote:
> Regarding the ".init" issue, I hadn't thought of that, but it can be worked around pretty easily with an is(R r):
> 
> --------
> template Hello(R)
>       if ( is(R r) &&
>            is(typeof(takeExactly(r, 1))) &&
>            is(R == typeof(takeExactly(r, 1)))
>       )
> {
>       alias R Hello;
> }
> --------

That was one trick that I was not aware of. I didn't think that one is expression could have an effect on a later one in the surrounding expression. Cool. Though I would point out that that probably doesn't avoid the init problem, because R r uses R.init (unless is expressions treat it differently, which they may). The normal way to avoid that is to do

R r = void;

but I don't think that that would work in that is expression. Sometimes disabling init is useful, but it can definitely be problematic. It may ultimately have been a mistake to allow it. I don't know.

- Jonathan M Davis
September 24, 2012
On Monday, 24 September 2012 at 07:51:23 UTC, Jonathan M Davis wrote:
> On Monday, September 24, 2012 09:41:26 monarch_dodra wrote:
>> Regarding the ".init" issue, I hadn't thought of that, but it can
>> be worked around pretty easily with an is(R r):
>> 
>> --------
>> template Hello(R)
>>       if ( is(R r) &&
>>            is(typeof(takeExactly(r, 1))) &&
>>            is(R == typeof(takeExactly(r, 1)))
>>       )
>> {
>>       alias R Hello;
>> }
>> --------
>
> That was one trick that I was not aware of. I didn't think that one is
> expression could have an effect on a later one in the surrounding expression.
> Cool. Though I would point out that that probably doesn't avoid the init
> problem, because R r uses R.init (unless is expressions treat it differently,
> which they may). The normal way to avoid that is to do
>
> R r = void;
>
> but I don't think that that would work in that is expression. Sometimes
> disabling init is useful, but it can definitely be problematic. It may
> ultimately have been a mistake to allow it. I don't know.
>
> - Jonathan M Davis

Well, it does work...

struct S
{
    @disable this();
}

void foo(T)(T i)
    if ( is(T t))
{}

void main()
{
    //S s; //Fail
    S s = void;
    foo(s); //Works
}

I think it makes sense that it works, because "is" doesn't actually validate a compile time syntax, rather it is just declaring that "t can be used as an instance of T", but it is not actually declaring *the variable* "t" itself... Not sure I'm explaining myself.

Or I think that's how it works. I've been on a wrong streak lately :/
September 24, 2012
On Monday, September 24, 2012 10:02:54 monarch_dodra wrote:
> Well, it does work...
> 
> struct S
> {
>      @disable this();
> }
> 
> void foo(T)(T i)
>      if ( is(T t))
> {}
> 
> void main()
> {
>      //S s; //Fail
>      S s = void;
>      foo(s); //Works
> }
> 
> I think it makes sense that it works, because "is" doesn't actually validate a compile time syntax, rather it is just declaring that "t can be used as an instance of T", but it is not actually declaring *the variable* "t" itself... Not sure I'm explaining myself.
> 
> Or I think that's how it works. I've been on a wrong streak lately :/

@disable this; is pretty broken, so I wouldn't really trust it at this point.

http://d.puremagic.com/issues/show_bug.cgi?id=7021

But it wouldn't surprise if is expressions are supposed to act differently. is expressions are arguably too fancy for their own good (well, our good anyway).

- Jonathan M Davis
September 24, 2012
On 09/24/2012 09:41 AM, monarch_dodra wrote:
> ...
>
> Regarding the ".init" issue, I hadn't thought of that, but it can
> be worked around pretty easily with an is(R r):
>
> --------
> template Hello(R)
>       if ( is(R r) &&
>            is(typeof(takeExactly(r, 1))) &&
>            is(R == typeof(takeExactly(r, 1)))
>       )
> {
>       alias R Hello;
> }
> --------
> After that, I guess it is indeed one implementation detail vs the
> other.
>

I don't think this does what you think it does. The 'is(R r)' declares r to be an alias for R. So 'r' is a type in that code snippet.

Also, is(typeof(takeExactly(R, 1))) && is(R == typeof(takeExactly(R, 1)))

can be written in a more compact way as

is(typeof(takeExactly(R, 1)) == R)


> IMO, it really depends on whether or not you'd want "int[]" to be
> considered the return type of a takeExactly :/ Maybe it is, maybe
> it ain't.