Thread overview
how does isInputRange(T) actually work?
Apr 21, 2015
kevin
Apr 21, 2015
John Colvin
Apr 21, 2015
Meta
Apr 21, 2015
kevin
Apr 21, 2015
anonymous
Apr 22, 2015
kevin
Apr 22, 2015
Meta
Apr 23, 2015
Vlad Levenfeld
Apr 21, 2015
Ali Çehreli
April 21, 2015
enum bool isInputRange = is(typeof(
    (inout int = 0)
    {
        R r = R.init;     // 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
    }));


... is the current implementation in Phobos. But I can't seem to understand this syntax. What is (inout int = 0)? Why can a block follow it?

My guess is that this is declaring some sort of function and testing if it is syntactically valid, but this is still strange to me.
April 21, 2015
On Tuesday, 21 April 2015 at 19:06:39 UTC, kevin wrote:
> enum bool isInputRange = is(typeof(
>     (inout int = 0)
>     {
>         R r = R.init;     // 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
>     }));
>
>
> ... is the current implementation in Phobos. But I can't seem to understand this syntax. What is (inout int = 0)? Why can a block follow it?
>
> My guess is that this is declaring some sort of function and testing if it is syntactically valid, but this is still strange to me.

It's defining a lambda function and checking that it is *semantically* valid.

No idea what the `(inout int = 0)` is there for, I would have thought it would be fine without it.
April 21, 2015
On Tuesday, 21 April 2015 at 19:11:43 UTC, John Colvin wrote:
> On Tuesday, 21 April 2015 at 19:06:39 UTC, kevin wrote:
>> enum bool isInputRange = is(typeof(
>>    (inout int = 0)
>>    {
>>        R r = R.init;     // 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
>>    }));
>>
>>
>> ... is the current implementation in Phobos. But I can't seem to understand this syntax. What is (inout int = 0)? Why can a block follow it?
>>
>> My guess is that this is declaring some sort of function and testing if it is syntactically valid, but this is still strange to me.
>
> It's defining a lambda function and checking that it is *semantically* valid.
>
> No idea what the `(inout int = 0)` is there for, I would have thought it would be fine without it.

`inout int = 0` is just `inout int n = 0` without the variable name, which is just `inout int n` with a default argument of 0.
April 21, 2015
On Tuesday, 21 April 2015 at 19:13:34 UTC, Meta wrote:
> On Tuesday, 21 April 2015 at 19:11:43 UTC, John Colvin wrote:
>> On Tuesday, 21 April 2015 at 19:06:39 UTC, kevin wrote:
>>> enum bool isInputRange = is(typeof(
>>>   (inout int = 0)
>>>   {
>>>       R r = R.init;     // 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
>>>   }));
>>>
>>>
>>> ... is the current implementation in Phobos. But I can't seem to understand this syntax. What is (inout int = 0)? Why can a block follow it?
>>>
>>> My guess is that this is declaring some sort of function and testing if it is syntactically valid, but this is still strange to me.
>>
>> It's defining a lambda function and checking that it is *semantically* valid.
>>
>> No idea what the `(inout int = 0)` is there for, I would have thought it would be fine without it.
>
> `inout int = 0` is just `inout int n = 0` without the variable name, which is just `inout int n` with a default argument of 0.

Thanks for your responses. Don't lambdas need a => token? Also, what is the purpose of typeof? I would have expected a simple is() to work just fine.
April 21, 2015
On 4/21/15 3:11 PM, John Colvin wrote:
> On Tuesday, 21 April 2015 at 19:06:39 UTC, kevin wrote:
>> enum bool isInputRange = is(typeof(
>>     (inout int = 0)
>>     {
>>         R r = R.init;     // 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
>>     }));
>>
>>
>> ... is the current implementation in Phobos. But I can't seem to
>> understand this syntax. What is (inout int = 0)? Why can a block
>> follow it?
>>
>> My guess is that this is declaring some sort of function and testing
>> if it is syntactically valid, but this is still strange to me.
>
> It's defining a lambda function and checking that it is *semantically*
> valid.
>
> No idea what the `(inout int = 0)` is there for, I would have thought it
> would be fine without it.

inout has a rule that you can't declare a type of inout as a local variable unless there is an inout parameter/return. I'm not sure if this rule still exists (it causes weird shit like the above to be required). I know some inout rules that I devised have been relaxed for the benefit of generic function sanity.

The inout int = 0 gives the lambda an inout parameter, in case you are doing isInputRange!(inout(int)[]), then you can validly declare a range of type R inside your function.

Alternatively, you could have the lambda take an R as a parameter. Or fix the semantics so that inout local variable acts like immutable inside a non-inout function.

-Steve
April 21, 2015
On Tuesday, 21 April 2015 at 19:17:56 UTC, kevin wrote:
> On Tuesday, 21 April 2015 at 19:13:34 UTC, Meta wrote:
>> On Tuesday, 21 April 2015 at 19:11:43 UTC, John Colvin wrote:
>>> On Tuesday, 21 April 2015 at 19:06:39 UTC, kevin wrote:
>>>> enum bool isInputRange = is(typeof(
>>>>  (inout int = 0)
>>>>  {
>>>>      R r = R.init;     // 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
>>>>  }));
[...]
> Don't lambdas need a => token?

No, D has two variants of function/delegate literal or lambda syntax:

1) with "=>": parameters => expression
Some examples:
(int a) => a + 2
a => a + 2
(a, b) => a + b
() => 2

2) with braces: (parameters) {statements}
Same examples as above:
(int a) {return a + 2;}
(a) {return a + 2;}
(a, b) {return a + b;}
{return 2;}

As you can see, a lot is optional there.

In the spec: http://dlang.org/expression.html#FunctionLiteral

> Also, what is the purpose of typeof? I would have expected a simple is() to work just fine.

(In this most simple form,) `is` evaluates to true if the argument is a valid type. A function/delegate literal isn't a type.

If you passed the lambda expression itself to `is`, the result would always be false. As it is, the result is true when the lambda expression compiles (so it has a valid type).

More about the IsExpression: http://dlang.org/expression.html#IsExpression
April 21, 2015
On 04/21/2015 12:06 PM, kevin wrote:
> enum bool isInputRange = is(typeof(
>      (inout int = 0)
>      {
>          R r = R.init;     // 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
>      }));
>
>
> ... is the current implementation in Phobos. But I can't seem to
> understand this syntax. What is (inout int = 0)? Why can a block follow it?
>
> My guess is that this is declaring some sort of function and testing if
> it is syntactically valid, but this is still strange to me.

I try to explain that syntax here:


http://ddili.org/ders/d.en/templates_more.html#ix_templates_more.named%20template%20constraint

Ali

April 22, 2015
On Tuesday, 21 April 2015 at 19:42:42 UTC, anonymous wrote:
> On Tuesday, 21 April 2015 at 19:17:56 UTC, kevin wrote:
>> On Tuesday, 21 April 2015 at 19:13:34 UTC, Meta wrote:
>>> On Tuesday, 21 April 2015 at 19:11:43 UTC, John Colvin wrote:
>>>> On Tuesday, 21 April 2015 at 19:06:39 UTC, kevin wrote:
>>>>> enum bool isInputRange = is(typeof(
>>>>> (inout int = 0)
>>>>> {
>>>>>     R r = R.init;     // 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
>>>>> }));
>> [...]
>> Also, what is the purpose of typeof? I would have expected a simple is() to work just fine.
>
> (In this most simple form,) `is` evaluates to true if the argument is a valid type. A function/delegate literal isn't a type.
>
> If you passed the lambda expression itself to `is`, the result would always be false. As it is, the result is true when the lambda expression compiles (so it has a valid type).
>
> More about the IsExpression: http://dlang.org/expression.html#IsExpression

That makes sense. It seems to me that D has very... special but effective syntax. I'm having a hard time remembering all the keywords and expression forms (especially of IsExpression) but it's definitely a vast improvement over C++'s half baked pile of whatever. Thanks for the help, everyone.
April 22, 2015
> That makes sense. It seems to me that D has very... special but effective syntax. I'm having a hard time remembering all the keywords and expression forms (especially of IsExpression) but it's definitely a vast improvement over C++'s half baked pile of whatever. Thanks for the help, everyone.

The `is` expression is complicated and has a bunch of different usage syntax, but it's like one of those little multitools. Complicated to figure out how to use, but extremely flexible and able to do a lot of cool things.
April 23, 2015
On Wednesday, 22 April 2015 at 21:22:43 UTC, Meta wrote:
>> That makes sense. It seems to me that D has very... special but effective syntax. I'm having a hard time remembering all the keywords and expression forms (especially of IsExpression) but it's definitely a vast improvement over C++'s half baked pile of whatever. Thanks for the help, everyone.
>
> The `is` expression is complicated and has a bunch of different usage syntax, but it's like one of those little multitools. Complicated to figure out how to use, but extremely flexible and able to do a lot of cool things.

Yeah, the `is` expression is one of my favorite D features.

import std.container;

template Substitute (T, U) {
  static if (is (T == F!V, alias F, V))
    alias Substitute = F!U;
}

alias List = SList!int;

static assert (is (Substitute!(List, char) == SList!char));

It's the little things.