www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Understanding isInfinite(Range)

reply Andrej Mitrovic <andrej.mitrovich test.com> writes:
I was reading about the various range templates in std.range and I found this:

http://www.digitalmars.com/d/2.0/phobos/std_range.html#isInfinite

Seems simple enough. But I dont understand it's implementation, this from
range.d:

template isInfinite(Range)
{
    static if (isInputRange!Range && is(char[1 + Range.empty]))
        enum bool isInfinite = !Range.empty;
    else
        enum bool isInfinite = false;
}

What does char[1 + Range.empty] do? It looks rather cryptic..
Sep 03 2010
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 03 Sep 2010 11:12:29 -0400, Andrej Mitrovic  
<andrej.mitrovich test.com> wrote:

 I was reading about the various range templates in std.range and I found  
 this:

 http://www.digitalmars.com/d/2.0/phobos/std_range.html#isInfinite

 Seems simple enough. But I dont understand it's implementation, this  
 from range.d:

 template isInfinite(Range)
 {
     static if (isInputRange!Range && is(char[1 + Range.empty]))
         enum bool isInfinite = !Range.empty;
     else
         enum bool isInfinite = false;
 }

 What does char[1 + Range.empty] do? It looks rather cryptic..

char[1+Range.empty] is a type. If Range.empty is a compile-time constant, then this type is valid, otherwise it's not valid (the is expression results to true if the argument is a valid type). If it's valid, then Range.empty never changes. If it never changes and it's always false, then it's infinite. -Steve
Sep 03 2010
next sibling parent Andrej Mitrovic <andrej.mitrovich test.com> writes:
Ah, you're right. Whenever I see the square brackets my brain automatically
things "we're indexing something". I'll blame that on C. :p

Thanks.

Steven Schveighoffer Wrote:

 On Fri, 03 Sep 2010 11:12:29 -0400, Andrej Mitrovic  
 <andrej.mitrovich test.com> wrote:
 
 I was reading about the various range templates in std.range and I found  
 this:

 http://www.digitalmars.com/d/2.0/phobos/std_range.html#isInfinite

 Seems simple enough. But I dont understand it's implementation, this  
 from range.d:

 template isInfinite(Range)
 {
     static if (isInputRange!Range && is(char[1 + Range.empty]))
         enum bool isInfinite = !Range.empty;
     else
         enum bool isInfinite = false;
 }

 What does char[1 + Range.empty] do? It looks rather cryptic..

char[1+Range.empty] is a type. If Range.empty is a compile-time constant, then this type is valid, otherwise it's not valid (the is expression results to true if the argument is a valid type). If it's valid, then Range.empty never changes. If it never changes and it's always false, then it's infinite. -Steve

Sep 03 2010
prev sibling parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
== Quote from Steven Schveighoffer (schveiguy yahoo.com)'s article
 On Fri, 03 Sep 2010 11:12:29 -0400, Andrej Mitrovic
 <andrej.mitrovich test.com> wrote:
 What does char[1 + Range.empty] do? It looks rather cryptic..

then this type is valid, otherwise it's not valid (the is expression results to true if the argument is a valid type). If it's valid, then Range.empty never changes. If it never changes and it's always false, then it's infinite. -Steve

That's really ugly code :-( Is there a way you could write an isStatic(expr) template? Using something like that would make the code a hell of a lot more readable. At the moment, the code itself does a very poor job of conveying what it's trying to accomplish. These SFINAE-like tricks should be black-boxed as much as possible, or (at the very least) commented so that people know what's going on.
Sep 04 2010
parent reply Pelle <pelle.mansson gmail.com> writes:
On 09/04/2010 02:11 PM, Simen kjaeraas wrote:
 Peter Alexander <peter.alexander.au gmail.com> wrote:

 == Quote from Steven Schveighoffer (schveiguy yahoo.com)'s article
 On Fri, 03 Sep 2010 11:12:29 -0400, Andrej Mitrovic
 <andrej.mitrovich test.com> wrote:
 What does char[1 + Range.empty] do? It looks rather cryptic..

constant, then this type is valid, otherwise it's not valid (the is expression results to true if the argument is a valid type). If it's valid, then Range.empty never changes. If it never changes and it's always false, then it's infinite. -Steve

That's really ugly code :-( Is there a way you could write an isStatic(expr) template? Using something like that would make the code a hell of a lot more readable. At the moment, the code itself does a very poor job of conveying what it's trying to accomplish. These SFINAE-like tricks should be black-boxed as much as possible, or (at the very least) commented so that people know what's going on.

template isStatic( alias T ) { enum isStatic = is( char[1+T] ); } unittest { int n = 3; assert( !isStatic!n ); assert( isStatic!1 ); enum r = 5; assert( isStatic!r ); }

enum s = "Hello"; assert (isStatic!s); Gonna need more work than that.
Sep 06 2010
next sibling parent reply Andrej Mitrovic <andrej.mitrovich test.com> writes:
Apparently I can't post to D.learn from gmail without waiting for a review?
What the..?

Anyway, I've posted this:

On a related note, I always wanted to make a template to replace the
dreaded is(typeof('delegate literal'())); calls.

For example, instead of this:

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

We'd have a much cleaner call like so:

enum bool isInputRange = validate!(
{
   R r;             // can define a range object
   if (r.empty) {}  // can test for empty
   r.popFront;          // can invoke next
   auto h = r.front; // can get the front of the range
});

But I haven't found a way to do it properly. If I call validate on a
type R range which doesn't feature the empty() method, then no matter
what the definition of validate is the compiler will error out because
it sees the call to r.empty() in the function literal, and 'r' doesn't
have an empty method.

Philippe Sigaud Wrote:

 On Mon, Sep 6, 2010 at 18:47, Pelle <pelle.mansson gmail.com> wrote:
 
 On 09/04/2010 02:11 PM, Simen kjaeraas wrote:

 Is there a way you could write an isStatic(expr) template? Using

template isStatic( alias T ) { enum isStatic = is( char[1+T] ); } unittest { int n = 3; assert( !isStatic!n ); assert( isStatic!1 ); enum r = 5; assert( isStatic!r ); }

enum s = "Hello"; assert (isStatic!s); Gonna need more work than that.

Why? That's exactly the behavior we want, or so it seems to me. <div class="gmail_quote">On Mon, Sep 6, 2010 at 18:47, Pelle <span dir="ltr">&lt;<a href="mailto:pelle.mansson gmail.com">pelle.mansson gmai .com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"> <div><div></div><div class="h5">On 09/04/2010 02:11 PM, Simen kjaeraas wrote:<br> <blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"> Is there a way you could write an isStatic(expr) template? Using<br></blockquote> <br> template isStatic( alias T ) {<br> enum isStatic = is( char[1+T] );<br> }<br> <br> unittest {<br> int n = 3;<br> assert( !isStatic!n );<br> assert( isStatic!1 );<br> enum r = 5;<br> assert( isStatic!r );<br> }<br> </blockquote> <br></div></div> enum s = &quot;Hello&quot;;<br> <br> assert (isStatic!s);<br> <br> Gonna need more work than that.<br> </blockquote></div><br>Why? That's exactly the behavior we want, or so it seems to me.<br><br><br>

Sep 06 2010
next sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
Andrej Mitrovic wrote:
 Apparently I can't post to D.learn from gmail without waiting for a review?
What the..?
 
 Anyway, I've posted this:
 
 On a related note, I always wanted to make a template to replace the
 dreaded is(typeof('delegate literal'())); calls.
 
 For example, instead of this:
 
 enum bool isInputRange = is(typeof(
 {
    R r;             // can define a range object
    if (r.empty) {}  // can test for empty
    r.popFront;          // can invoke next
    auto h = r.front; // can get the front of the range
 }()));
 
 We'd have a much cleaner call like so:
 
 enum bool isInputRange = validate!(
 {
    R r;             // can define a range object
    if (r.empty) {}  // can test for empty
    r.popFront;          // can invoke next
    auto h = r.front; // can get the front of the range
 });
 
 But I haven't found a way to do it properly. If I call validate on a
 type R range which doesn't feature the empty() method, then no matter
 what the definition of validate is the compiler will error out because
 it sees the call to r.empty() in the function literal, and 'r' doesn't
 have an empty method.
 

What about __traits(compiles) ?
Sep 06 2010
parent reply Andrej Mitrovic <andrej.mitrovich test.com> writes:
Yeah, that could work:

template isInputRange(R)
{
   enum bool isInputRange = __traits(compiles,
   {
       R r;             // can define a range object
       if (r.empty) {}  // can test for empty
       r.popFront;          // can invoke next
       auto h = r.front; // can get the front of the range
   });
}

It does look nice. It would look even nicer if __traits gets renamed to meta.

Stanislav Blinov Wrote:

 What about __traits(compiles) ?

Sep 06 2010
parent reply Andrej Mitrovic <andrej.mitrovich test.com> writes:
I'd love to see this used more in Phobos. I don't know if there are any
drawbacks, but this looks and works nicely:

import std.stdio : writeln;

void main()
{
    writeln(isInputRange!(N));
}

class N
{
    N test;
    
    bool empty()
    {
        return false;
    }
    
     property
    void popFront()
    {
    }
    
     property
    N front()
    {
        return test;
    }
}


template isInputRange(R)
{
    enum bool isInputRange = __traits(compiles,
    {
        R r;             // can define a range object
        if (r.empty) {}  // can test for empty
        r.popFront;          // can invoke next
        auto h = r.front; // can get the front of the range
    });
}

If you uncomment some of those methods in class N, then you get back false,
which is what you want. Currently isInputRange is defined like so in Phobos:

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

It's getting close to LISP! :)

Andrej Mitrovic Wrote:

 Yeah, that could work:
 
 template isInputRange(R)
 {
    enum bool isInputRange = __traits(compiles,
    {
        R r;             // can define a range object
        if (r.empty) {}  // can test for empty
        r.popFront;          // can invoke next
        auto h = r.front; // can get the front of the range
    });
 }
 
 It does look nice. It would look even nicer if __traits gets renamed to meta.
 
 Stanislav Blinov Wrote:
 
 What about __traits(compiles) ?


Sep 06 2010
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
Andrej Mitrovic wrote:
 I'd love to see this used more in Phobos. I don't know if there are any
drawbacks, but this looks and works nicely:
 
 import std.stdio : writeln;
 
 void main()
 {
     writeln(isInputRange!(N));
 }
 
 class N
 {
     N test;
     
     bool empty()
     {
         return false;
     }
     
      property
     void popFront()
     {
     }
     
      property
     N front()
     {
         return test;
     }
 }
 
 
 template isInputRange(R)
 {
     enum bool isInputRange = __traits(compiles,
     {
         R r;             // can define a range object
         if (r.empty) {}  // can test for empty
         r.popFront;          // can invoke next
         auto h = r.front; // can get the front of the range
     });
 }
 
 If you uncomment some of those methods in class N, then you get back false,
which is what you want. Currently isInputRange is defined like so in Phobos:
 
 template isInputRange(R)
 {
     enum bool isInputRange = is(typeof(
     {
         R r;             // can define a range object
         if (r.empty) {}  // can test for empty
         r.popFront;          // can invoke next
         auto h = r.front; // can get the front of the range
     }()));
 }
 
 It's getting close to LISP! :)
 

If I remember correctly, it has been discussed not long ago that those is(typeof(...))s should really be __traits(compiles). Maybe it's just some code was written before those lovely __traits were introduced?..
Sep 06 2010
next sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
Andrej Mitrovic wrote:

 It does look nice. It would look even nicer if __traits gets renamed to meta.

By the way, there's no stopping writing template isValidCode(alias code) { enum bool isValidCode = __traits(compiles, code); } :)
Sep 06 2010
parent reply Andrej Mitrovic <andrej.mitrovich test.com> writes:
That still won't work. Observe:

import std.stdio : writeln;

void main()
{
   writeln(isInputRange!(N));
}

class N
{
    N test;

    //~ bool empty()     // oops, we"re not an input range anymore
    //~ {
    //~     return false;
    //~ }

     property
    void popFront()
    {
    }

     property
    N front()
    {
        return test;
    }
}


template isInputRange(R)
{
    enum bool isInputRange = isValidCode!(
    {
        R r;                // can define a range object
        if (r.empty) {}     // can test for empty
        r.popFront;         // can invoke next
        auto h = r.front;   // can get the front of the range
    });
}

template isValidCode(alias code) { enum bool isValidCode = __traits(compiles,
code); }

Instead of returning false, it will give out a compiler error.

Stanislav Blinov Wrote:

 
 Andrej Mitrovic wrote:
 
 It does look nice. It would look even nicer if __traits gets renamed to meta.

By the way, there's no stopping writing template isValidCode(alias code) { enum bool isValidCode = __traits(compiles, code); } :)

Sep 06 2010
next sibling parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
Andrej Mitrovic wrote:
 That still won't work. Observe:
 

Oops, sorry, I was too quick to conclude.
Sep 06 2010
prev sibling parent reply Andrej Mitrovic <andrej.mitrovich test.com> writes:
I'm sorry, but what does q{..} mean?

Philippe Sigaud Wrote:

 On Mon, Sep 6, 2010 at 23:31, Andrej Mitrovic <andrej.mitrovich test.com>wrote:
 
 That still won't work. Observe:

 template isInputRange(R)
 {
     enum bool isInputRange = isValidCode!(
     {
        R r;                // can define a range object
        if (r.empty) {}     // can test for empty
        r.popFront;         // can invoke next
        auto h = r.front;   // can get the front of the range
    });
 }

 template isValidCode(alias code) { enum bool isValidCode =
 __traits(compiles, code); }

 Instead of returning false, it will give out a compiler error.

That's because the part between the curly braces is evaluated before being passed to the template. And there is no lazy alias. As Mafi said, you can use a string, it's still the best way to move code around in D. With q{ ... }, it's palatable. And no, before you try it, there is no way to pass the {...} to another template that would stringify it into a q{...} :-) Maybe, eventually, something like this: import std.stdio; template isValidCode(alias code) { template For(T) { enum bool For = __traits(compiles, code(T.init)); } } void main() { // use an anonymous templated function: alias isValidCode!((r) { if (r.empty) {} // can test for empty r.popFront; // can invoke next auto h = r.front; // c } ) isInputRange; // writeln(isInputRange.For!(int[])); } Except DMD doesn't like the commented-out line. Whaoh! Philippe

Sep 06 2010
parent reply bearophile < bearophileHUGS lycos.com> writes:
Andrej Mitrovic:

 I'm sorry, but what does q{..} mean?

q{} is just a different syntax to write "" or `` It's a controversial feature. q{} isn't recognized by editors as a string, so they colour the syntax it contains normally as code, and not as a string. So it's a bit useful if you want to give a string to a higher order function like map, instead of a delegate, and you want to keep the visual illusion of a delegate: map!q{a * a}([1, 2, 3]) The problem comes straight from its purpose: is that it doesn't look like a string, so its true nature is a bit hidden; and this may cause some troubles. Another possible problem was discussed when the q{} syntax was introduced. It's not a clean syntax, it's a hack from the point of view of parsing/lexing too. It's handy, but it may cause troubles too. I am getting used to it, but it's a untidy hack and it will keep being nothing more than a hack. And sometimes hacks later come back and bite your bum. Bye, bearophile
Sep 06 2010
next sibling parent reply Andrej Mitrovic <andrej.mitrovich test.com> writes:
Heh. I'd rather want text editors to use syntax highlighting on comments as
well, but use a different background color. Then I would know it's a comment
but it would also make any embedded code in the comment actually readable.

bearophile < bearophileHUGS lycos.com> Wrote:

 Andrej Mitrovic:
 
 I'm sorry, but what does q{..} mean?

q{} is just a different syntax to write "" or `` It's a controversial feature. q{} isn't recognized by editors as a string, so they colour the syntax it contains normally as code, and not as a string. So it's a bit useful if you want to give a string to a higher order function like map, instead of a delegate, and you want to keep the visual illusion of a delegate: map!q{a * a}([1, 2, 3]) The problem comes straight from its purpose: is that it doesn't look like a string, so its true nature is a bit hidden; and this may cause some troubles. Another possible problem was discussed when the q{} syntax was introduced. It's not a clean syntax, it's a hack from the point of view of parsing/lexing too. It's handy, but it may cause troubles too. I am getting used to it, but it's a untidy hack and it will keep being nothing more than a hack. And sometimes hacks later come back and bite your bum. Bye, bearophile

Sep 06 2010
parent Andrej Mitrovic <andrej.mitrovich test.com> writes:
I meant string literals. But comments as well.

Andrej Mitrovic Wrote:

 Heh. I'd rather want text editors to use syntax highlighting on comments as
well, but use a different background color. Then I would know it's a comment
but it would also make any embedded code in the comment actually readable.
 
 bearophile < bearophileHUGS lycos.com> Wrote:
 
 Andrej Mitrovic:
 
 I'm sorry, but what does q{..} mean?

q{} is just a different syntax to write "" or `` It's a controversial feature. q{} isn't recognized by editors as a string, so they colour the syntax it contains normally as code, and not as a string. So it's a bit useful if you want to give a string to a higher order function like map, instead of a delegate, and you want to keep the visual illusion of a delegate: map!q{a * a}([1, 2, 3]) The problem comes straight from its purpose: is that it doesn't look like a string, so its true nature is a bit hidden; and this may cause some troubles. Another possible problem was discussed when the q{} syntax was introduced. It's not a clean syntax, it's a hack from the point of view of parsing/lexing too. It's handy, but it may cause troubles too. I am getting used to it, but it's a untidy hack and it will keep being nothing more than a hack. And sometimes hacks later come back and bite your bum. Bye, bearophile


Sep 06 2010
prev sibling parent Pelle <pelle.mansson gmail.com> writes:
On 09/07/2010 12:44 AM, bearophile wrote:
 Andrej Mitrovic:

 I'm sorry, but what does q{..} mean?

q{} is just a different syntax to write "" or `` It's a controversial feature. q{} isn't recognized by editors as a string, so they colour the syntax it contains normally as code, and not as a string. So it's a bit useful if you want to give a string to a higher order function like map, instead of a delegate, and you want to keep the visual illusion of a delegate: map!q{a * a}([1, 2, 3]) The problem comes straight from its purpose: is that it doesn't look like a string, so its true nature is a bit hidden; and this may cause some troubles. Another possible problem was discussed when the q{} syntax was introduced. It's not a clean syntax, it's a hack from the point of view of parsing/lexing too. It's handy, but it may cause troubles too. I am getting used to it, but it's a untidy hack and it will keep being nothing more than a hack. And sometimes hacks later come back and bite your bum. Bye, bearophile

It's not the same. Try q{\n}. It's lexed like code.
Sep 07 2010
prev sibling parent reply Andrej Mitrovic <andrej.mitrovich test.com> writes:
is(typeof( is used a lot in Phobos. There's some ~260 calls like that, a quick
search revealed. :p

Stanislav Blinov Wrote:

 If I remember correctly, it has been discussed not long ago that those 
 is(typeof(...))s should really be __traits(compiles). Maybe it's just 
 some code was written before those lovely __traits were introduced?..

Sep 06 2010
parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
Andrej Mitrovic wrote:
 is(typeof( is used a lot in Phobos. There's some ~260 calls like that, a quick
search revealed. :p

Hush! You're spoiling it! It's a part of intergalactic obfuscation plot ;p
Sep 06 2010
prev sibling parent Mafi <mafi example.org> writes:
Am 06.09.2010 21:24, schrieb Andrej Mitrovic:
 Apparently I can't post to D.learn from gmail without waiting for a review?
What the..?

 Anyway, I've posted this:

 On a related note, I always wanted to make a template to replace the
 dreaded is(typeof('delegate literal'())); calls.

 For example, instead of this:

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

 We'd have a much cleaner call like so:

 enum bool isInputRange = validate!(
 {
     R r;             // can define a range object
     if (r.empty) {}  // can test for empty
     r.popFront;          // can invoke next
     auto h = r.front; // can get the front of the range
 });

 But I haven't found a way to do it properly. If I call validate on a
 type R range which doesn't feature the empty() method, then no matter
 what the definition of validate is the compiler will error out because
 it sees the call to r.empty() in the function literal, and 'r' doesn't
 have an empty method.

You could just let your template get a string. Then validate!q{....} should work. It looks almost exactly the same but has a 'q'. Maybe you could even create an template overload which gets delegate which has always failing static assert with message "you forget the 'q'" but I don't know if template initialization comes before semantic analisys so I'm not sure this will work. Mafi
Sep 06 2010
prev sibling parent reply Pelle <pelle.mansson gmail.com> writes:
On 09/06/2010 08:53 PM, Philippe Sigaud wrote:
 On Mon, Sep 6, 2010 at 18:47, Pelle <pelle.mansson gmail.com
 <mailto:pelle.mansson gmail.com>> wrote:

     On 09/04/2010 02:11 PM, Simen kjaeraas wrote:

             Is there a way you could write an isStatic(expr) template? Using


         template isStatic( alias T ) {
         enum isStatic = is( char[1+T] );
         }

         unittest {
         int n = 3;
         assert( !isStatic!n );
         assert( isStatic!1 );
         enum r = 5;
         assert( isStatic!r );
         }


     enum s = "Hello";

     assert (isStatic!s);

     Gonna need more work than that.


 Why? That's exactly the behavior we want, or so it seems to me.

Sorry if I was unclear, that assert fails. Due to that you cannot add an integer and a string, not not that the string isn't static. It's an enum, so it definitely is static.
Sep 06 2010
parent reply Andrej Mitrovic <andrej.mitrovich test.com> writes:
Is this legal?:

enum a = "test";
a = "test2";

Because it seems to compile. But that shouldn't work afaik..?

I can't reassign other enum types:

enum b = 4;
b = 5;  // error

which is expected.

Pelle Wrote:

 On 09/06/2010 08:53 PM, Philippe Sigaud wrote:
 On Mon, Sep 6, 2010 at 18:47, Pelle <pelle.mansson gmail.com
 <mailto:pelle.mansson gmail.com>> wrote:

     On 09/04/2010 02:11 PM, Simen kjaeraas wrote:

             Is there a way you could write an isStatic(expr) template? Using


         template isStatic( alias T ) {
         enum isStatic = is( char[1+T] );
         }

         unittest {
         int n = 3;
         assert( !isStatic!n );
         assert( isStatic!1 );
         enum r = 5;
         assert( isStatic!r );
         }


     enum s = "Hello";

     assert (isStatic!s);

     Gonna need more work than that.


 Why? That's exactly the behavior we want, or so it seems to me.

Sorry if I was unclear, that assert fails. Due to that you cannot add an integer and a string, not not that the string isn't static. It's an enum, so it definitely is static.

Sep 06 2010
parent bearophile < bearophileHUGS lycos.com> writes:
Andrej Mitrovic:

 enum a = "test";
 a = "test2";
 
 Because it seems to compile. But that shouldn't work afaik..?

I have two open bug reports on this (and a third one was open by Don). Bye, bearophile
Sep 06 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Peter Alexander <peter.alexander.au gmail.com> wrote:

 == Quote from Steven Schveighoffer (schveiguy yahoo.com)'s article
 On Fri, 03 Sep 2010 11:12:29 -0400, Andrej Mitrovic
 <andrej.mitrovich test.com> wrote:
 What does char[1 + Range.empty] do? It looks rather cryptic..

constant, then this type is valid, otherwise it's not valid (the is expression results to true if the argument is a valid type). If it's valid, then Range.empty never changes. If it never changes and it's always false, then it's infinite. -Steve

That's really ugly code :-( Is there a way you could write an isStatic(expr) template? Using something like that would make the code a hell of a lot more readable. At the moment, the code itself does a very poor job of conveying what it's trying to accomplish. These SFINAE-like tricks should be black-boxed as much as possible, or (at the very least) commented so that people know what's going on.

template isStatic( alias T ) { enum isStatic = is( char[1+T] ); } unittest { int n = 3; assert( !isStatic!n ); assert( isStatic!1 ); enum r = 5; assert( isStatic!r ); } -- Simen
Sep 04 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--0016e6dab373b4595d048f9bcb22
Content-Type: text/plain; charset=ISO-8859-1

On Mon, Sep 6, 2010 at 18:47, Pelle <pelle.mansson gmail.com> wrote:

 On 09/04/2010 02:11 PM, Simen kjaeraas wrote:

 Is there a way you could write an isStatic(expr) template? Using

template isStatic( alias T ) { enum isStatic = is( char[1+T] ); } unittest { int n = 3; assert( !isStatic!n ); assert( isStatic!1 ); enum r = 5; assert( isStatic!r ); }

enum s = "Hello"; assert (isStatic!s); Gonna need more work than that.

Why? That's exactly the behavior we want, or so it seems to me. --0016e6dab373b4595d048f9bcb22 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On Mon, Sep 6, 2010 at 18:47, Pelle <span dir=3D= "ltr">&lt;<a href=3D"mailto:pelle.mansson gmail.com">pelle.mansson gmail.co= m</a>&gt;</span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margi= n: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-le= ft: 1ex;"> <div><div></div><div class=3D"h5">On 09/04/2010 02:11 PM, Simen kjaeraas wr= ote:<br> <blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; borde= r-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"><blockquote class= =3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid= rgb(204, 204, 204); padding-left: 1ex;"> Is there a way you could write an isStatic(expr) template? Using<br></block= quote> <br> template isStatic( alias T ) {<br> enum isStatic =3D is( char[1+T] );<br> }<br> <br> unittest {<br> int n =3D 3;<br> assert( !isStatic!n );<br> assert( isStatic!1 );<br> enum r =3D 5;<br> assert( isStatic!r );<br> }<br> </blockquote> <br></div></div> enum s =3D &quot;Hello&quot;;<br> <br> assert (isStatic!s);<br> <br> Gonna need more work than that.<br> </blockquote></div><br>Why? That&#39;s exactly the behavior we want, or so = it seems to me.<br><br><br> --0016e6dab373b4595d048f9bcb22--
Sep 06 2010
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--0016e6d9776fa86220048f9e5e31
Content-Type: text/plain; charset=ISO-8859-1

On Mon, Sep 6, 2010 at 23:31, Andrej Mitrovic <andrej.mitrovich test.com>wrote:

 That still won't work. Observe:

 template isInputRange(R)
 {
     enum bool isInputRange = isValidCode!(
     {
        R r;                // can define a range object
        if (r.empty) {}     // can test for empty
        r.popFront;         // can invoke next
        auto h = r.front;   // can get the front of the range
    });
 }

 template isValidCode(alias code) { enum bool isValidCode =
 __traits(compiles, code); }

 Instead of returning false, it will give out a compiler error.

That's because the part between the curly braces is evaluated before being passed to the template. And there is no lazy alias. As Mafi said, you can use a string, it's still the best way to move code around in D. With q{ ... }, it's palatable. And no, before you try it, there is no way to pass the {...} to another template that would stringify it into a q{...} :-) Maybe, eventually, something like this: import std.stdio; template isValidCode(alias code) { template For(T) { enum bool For = __traits(compiles, code(T.init)); } } void main() { // use an anonymous templated function: alias isValidCode!((r) { if (r.empty) {} // can test for empty r.popFront; // can invoke next auto h = r.front; // c } ) isInputRange; // writeln(isInputRange.For!(int[])); } Except DMD doesn't like the commented-out line. Whaoh! Philippe --0016e6d9776fa86220048f9e5e31 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On Mon, Sep 6, 2010 at 23:31, Andrej Mitrovic <s= pan dir=3D"ltr">&lt;<a href=3D"mailto:andrej.mitrovich test.com">andrej.mit= rovich test.com</a>&gt;</span> wrote:<br><blockquote class=3D"gmail_quote" = style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 20= 4); padding-left: 1ex;"> That still won&#39;t work. Observe:</blockquote><div>=A0</div><blockquote c= lass=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px s= olid rgb(204, 204, 204); padding-left: 1ex;">template isInputRange(R)<br><d= iv class=3D"im"> {<br> </div> =A0 =A0enum bool isInputRange =3D isValidCode!(<br> <div class=3D"im"> =A0 =A0{<br> =A0 =A0 =A0 =A0R r; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// can define a range o= bject<br> =A0 =A0 =A0 =A0if (r.empty) {} =A0 =A0 // can test for empty<br> =A0 =A0 =A0 =A0r.popFront; =A0 =A0 =A0 =A0 // can invoke next<br> =A0 =A0 =A0 =A0auto h =3D r.front; =A0 // can get the front of the range<b= r> =A0 =A0});<br> }<br> <br> </div><div class=3D"im">template isValidCode(alias code) { enum bool isVali= dCode =3D __traits(compiles, code); }<br> <br> </div>Instead of returning false, it will give out a compiler error.<br></b= lockquote><div><br>That&#39;s because the part between the curly braces is = evaluated before being passed to the template. And there is no lazy alias.<= br> As Mafi said, you can use a string, it&#39;s still the best way to move cod= e around in D. With q{ ... }, it&#39;s palatable.<br>And no, before you try= it, there is no way to pass the {...} to another template that would strin= gify it into a q{...} :-)<br> <br>Maybe, eventually, something like this:<br><br>import std.stdio;<br><br=
<br>template isValidCode(alias code)<br>{<br>=A0=A0=A0 template For(T)<br>=

ode(T.init));<br>=A0=A0=A0 }<br> }<br><br>void main()<br>{<br>=A0=A0 // use an anonymous templated function:= <br>alias isValidCode!((r)<br>=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 {<br>=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 if (r.empty) {}=A0=A0=A0=A0 // can tes= t for empty<br>=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 r.popFront;=A0=A0=A0=A0=A0=A0=A0=A0 // can invoke nex= t<br> =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 auto h =3D r.front;=A0=A0 // c<br>=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 }<br>=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 ) isInputRange;<br><br>//=A0=A0=A0 writeln(isInput= Range.For!(int[]));<br>}<br><br>Except DMD doesn&#39;t like the commented-o= ut line. Whaoh!<br> <br><br><br>Philippe<br><br></div></div> --0016e6d9776fa86220048f9e5e31--
Sep 06 2010