November 04, 2016
On Friday, 4 November 2016 at 14:16:44 UTC, Matthias Bentrup wrote:
> On Thursday, 3 November 2016 at 22:29:34 UTC, Jerry wrote:
>>     if(int i = someFunc(); i >= 0)
>>     {
>>         // use i
>>     }
>> Thoughts on this sort of feature?
>
> I would prefer the syntax
>
>   if( (int i = someFunc()) >= 0 )
>   {
>     // use i
>   }
>
> as this matches the already existing assignment expression syntax if you pull the declaration out of the if expression.

Well you can argue the "if( init ; condition )" syntax matches "for( init ; condition ; update)", minus the "update" section. It's cleaner as well as you don't need an extra set of parenthesizes. As well that sort of syntax would allow multiple declaration. Which I'm not sure that's desired, it becomes increasingly messy.

if((int i = someFunc()) >= 0 && (int j = otherFunc()) >= 0)
{
}

You also can't use the declaration as input for someFunc():

    if(int i; someFunc(&i) >= 0)
    {
    }
November 04, 2016
On 11/4/16 11:27 AM, Jerry wrote:
> On Friday, 4 November 2016 at 14:10:51 UTC, Steven Schveighoffer wrote:
>> Hm... what about something like:
>>
>> struct BoolCond(T, string cond)
>> {
>>    T val;
>>    bool opCast(B)() if(is(B == bool))
>>    {
>>      return mixin("val " ~ cond);
>>    }
>> }
>>
>> auto boolcond(string cond, T)(T val)
>> {
>>    return BoolCond!(T, cond)(val);
>> }
>>
>> if(auto i = someFunc.boolcond!(">= 0"))
>> {
>>    ... // use i
>> }
>>
>
> Well that's just a basic case, what if you want more than one condition.
> Using "&&" for example, or a condition along with another value that's
> in the scope.

It's just a strawman type, I'm sure there's ways to handle these things, I just didn't put a lot of effort into all the cases.

But really it's just syntax to separate the bool check from the value itself. You can get more elaborate if you want with the comparison. The difficult thing is having a type that you use normally, but that when you use in an if statement, it gives what you want. And declaring that type in the if clause itself (which is allowed in restricted circumstances).

This also isn't exactly ideal for things like int, as if(i) would now be unexpected.

> Then you need another work around for something like this:
>
> if(int value; auto i = someFunc(&value))
> {
>    // ...
> }

I thought you could only declare variables in the first clause?

In any case, I think Stefan really has the best answer:

{int value; if(auto i = someFunc(&value))
{
    // ...
}}

Sure, it doesn't look great. But my expectation is that your proposal doesn't pull enough weight to be integrated into the language. There are enough ways to solve this problem that don't involve language changes.

-Steve
November 04, 2016
On Friday, 4 November 2016 at 13:56:57 UTC, Andrea Fontana wrote:
> If you don't like indentation you can simply ignore it or you can use old goto :)
>
> {
>    int i = someFunc();
>    if (i < 0) goto outer;
>    // your code here
> }
> outer:

BTW there is a trick to avoid goto+label:

switch (true) {
default:
  int i = someFunc();
  if (i < 0) break;
  ...
}

If code after goto is long, the reader has to search for the label. With switch/break, the reader knows the current scope is just skipped, no need to interrupt reading of lines.

We could allow omitting the condition and default label:

switch {
  int i = someFunc();
  if (i < 0) break;
  ...
}

That would encourage the pattern to be used instead of the 'triangle if' pattern - the rationale for breakable blocks:
https://issues.dlang.org/show_bug.cgi?id=8622
November 04, 2016
On Thursday, 3 November 2016 at 22:29:34 UTC, Jerry wrote:
> Thoughts on this sort of feature?

Love your name, Jerry ;)

Maybe something like this psuedo code:

struct Condition(T) {
    Condition(T val, bool cond) { m_val = val; m_cond = cond; }
    bool opCast(T)() if(is(T == bool)) {
        return m_cond;
    }

    alias m_val this;

private:
    T m_val;
    bool m_cond;
}

auto cond(T v, bool cond) {
    return Condition!T(v, cond);
}


Usage:

int v = 5;
if(v = cond(v, v > 4) {
    writeln("Happy coding");
}



Just notice I am not proud of that T.init.
November 04, 2016
On Friday, 4 November 2016 at 16:15:21 UTC, Steven Schveighoffer wrote:
> It's just a strawman type, I'm sure there's ways to handle these things, I just didn't put a lot of effort into all the cases.
>
> But really it's just syntax to separate the bool check from the value itself. You can get more elaborate if you want with the comparison. The difficult thing is having a type that you use normally, but that when you use in an if statement, it gives what you want. And declaring that type in the if clause itself (which is allowed in restricted circumstances).
>
> This also isn't exactly ideal for things like int, as if(i) would now be unexpected.

It is just a basic type but ultimately you will probably need more than one type with a different way of operating to get the same behavior. That and having part of the code as a string which makes it harder to read and no syntax highlighting for the code in text editors/ides.

What do you mean if(i) would be unexpected?

> I thought you could only declare variables in the first clause?
>
> In any case, I think Stefan really has the best answer:
>
> {int value; if(auto i = someFunc(&value))
> {
>     // ...
> }}
>
> Sure, it doesn't look great. But my expectation is that your proposal doesn't pull enough weight to be integrated into the language. There are enough ways to solve this problem that don't involve language changes.
>
> -Steve

It follows the same rules for an if statement condition which an if statement allows "if(auto i = foo())".

It's syntactic sugar, most of the existing language features don't serve a functional purpose. They simply serve to simplify another syntax. Every "foreach" statement could be written as a for-statement. Every for-statement could be written as a while-statement. And so on so forth. It doesn't add anything that new either. It follows the same syntax as a for-statement.

It's not that big of a language feature, it's just a small syntactic change, which comes down to. Is this easier to read compared to this.

    {int value; if(auto i = someFunc(&value))
    {
        // ...
    }}

vs.

    if(int value; auto i = someFunc(&value))
    {
        // ...
    }


I think it makes it easier to read and it fits with how the for-statement operates. I write code everyday that could utilize this if-statement syntax, so I thought I might as well bring it up. But if there isn't that much interest in it then I won't bother with a DIP.
November 04, 2016
On Friday, 4 November 2016 at 15:34:00 UTC, Jerry wrote:
> On Friday, 4 November 2016 at 14:16:44 UTC, Matthias Bentrup wrote:
>> On Thursday, 3 November 2016 at 22:29:34 UTC, Jerry wrote:
>>>     if(int i = someFunc(); i >= 0)
>>>     {
>>>         // use i
>>>     }
>>> Thoughts on this sort of feature?
>>
>> I would prefer the syntax
>>
>>   if( (int i = someFunc()) >= 0 )
>>   {
>>     // use i
>>   }
>>
>> as this matches the already existing assignment expression syntax if you pull the declaration out of the if expression.
>
> Well you can argue the "if( init ; condition )" syntax matches "for( init ; condition ; update)", minus the "update" section.

You've just answered your own question:
    for (int i = someFunc(); i >= 0; )
    {
        // use i
        break;
    }

November 04, 2016
On 11/4/16 1:46 PM, Jerry wrote:
> On Friday, 4 November 2016 at 16:15:21 UTC, Steven Schveighoffer wrote:
>> It's just a strawman type, I'm sure there's ways to handle these
>> things, I just didn't put a lot of effort into all the cases.
>>
>> But really it's just syntax to separate the bool check from the value
>> itself. You can get more elaborate if you want with the comparison.
>> The difficult thing is having a type that you use normally, but that
>> when you use in an if statement, it gives what you want. And declaring
>> that type in the if clause itself (which is allowed in restricted
>> circumstances).
>>
>> This also isn't exactly ideal for things like int, as if(i) would now
>> be unexpected.
>
> It is just a basic type but ultimately you will probably need more than
> one type with a different way of operating to get the same behavior.
> That and having part of the code as a string which makes it harder to
> read and no syntax highlighting for the code in text editors/ides.
>
> What do you mean if(i) would be unexpected?

I mean something like:

if(auto i = func.cond("==0"))
{
   assert(i == 0);
   if(i)
   {
      writeln("oops!");
   }
}

>> Sure, it doesn't look great. But my expectation is that your proposal
>> doesn't pull enough weight to be integrated into the language. There
>> are enough ways to solve this problem that don't involve language
>> changes.
>>
>
> It follows the same rules for an if statement condition which an if
> statement allows "if(auto i = foo())".

Right, I'm just saying syntax changes like this generally need a high motivation and perceived improvement to justify the undertaking.

For instance, we have trusted escapes via this construct:

auto foo = (() @trusted => systemFunc(x))();

It's ugly, verbose, confusing. But it works, and it works today. I'd much rather have this look like:

auto foo = @trusted(systemFunc(x));

or something similar, but how much benefit are we going to get from this? Is it going to change productivity? Is it going to make code so much easier to write that the time taken to implement was worth it? I don't know the answer to that. Often the answer to requests for such improvements is "yeah, but you can just do it this way, and that's good enough". That's all I'm trying to say.

> It's syntactic sugar, most of the existing language features don't serve
> a functional purpose. They simply serve to simplify another syntax.
> Every "foreach" statement could be written as a for-statement. Every
> for-statement could be written as a while-statement. And so on so forth.
> It doesn't add anything that new either. It follows the same syntax as a
> for-statement.

Existence of current sugar is not justification of adding more. Those already exist (and BTW have existed for a long long time), there is no cost to continuing to have them. There is a cost to adding new features, that we must weigh against the benefits.

One thing that could work in your favor is if the change is easy to implement in the compiler. That I definitely don't know the answer to.

> I think it makes it easier to read and it fits with how the
> for-statement operates. I write code everyday that could utilize this
> if-statement syntax, so I thought I might as well bring it up. But if
> there isn't that much interest in it then I won't bother with a DIP.

Please bear in mind that I'm not the gatekeeper, so what I say may not be what the actual ones in control think. It's possible that Walter and Andrei like the idea and would implement if someone fleshed out the proposal. In my experience, I have not encountered too many cases (definitely not zero though) where I needed such a feature. I can see the utility, and I wouldn't be opposed to it.

-Steve
November 04, 2016
On Thursday, 3 November 2016 at 22:29:34 UTC, Jerry wrote:
>
> So I was thinking of a way of extending if statements that have declarations. The following being as example of the current use of if statements with declarations:
>
>     if(int* weDontPollute = someFunc())
>     {
>          // use weDontPollute
>     }
>
> That's great and all, but it only works by checking if the variable evaluates to true or false. Which is fine for a pointer but otherwise useless for anything else, like integers where zero is usually valid input (index for array).

This is already possible in library code. See here: https://github.com/AndrejMitrovic/minilib/blob/510460ff1381f765a66aa3b8f8f6d7e95b4597b9/src/minilib/core/types.d#L88-L137

One could come up with a helper function that encodes the condition which is moved into the opCast method. This should be trivial to implement.
November 04, 2016
On 04.11.2016 21:03, Andrej Mitrovic wrote:
> On Thursday, 3 November 2016 at 22:29:34 UTC, Jerry wrote:
>>
>> So I was thinking of a way of extending if statements that have
>> declarations. The following being as example of the current use of if
>> statements with declarations:
>>
>>     if(int* weDontPollute = someFunc())
>>     {
>>          // use weDontPollute
>>     }
>>
>> That's great and all, but it only works by checking if the variable
>> evaluates to true or false. Which is fine for a pointer but otherwise
>> useless for anything else, like integers where zero is usually valid
>> input (index for array).
>
> This is already possible in library code. See here:
> https://github.com/AndrejMitrovic/minilib/blob/510460ff1381f765a66aa3b8f8f6d7e95b4597b9/src/minilib/core/types.d#L88-L137
>

Not worth the IFTI-induced template bloat IMHO.
November 05, 2016
On Friday, 4 November 2016 at 18:05:51 UTC, Adrian Matoga wrote:
> On Friday, 4 November 2016 at 15:34:00 UTC, Jerry wrote:
>> On Friday, 4 November 2016 at 14:16:44 UTC, Matthias Bentrup wrote:
>>> On Thursday, 3 November 2016 at 22:29:34 UTC, Jerry wrote:
>>>>     if(int i = someFunc(); i >= 0)
>>>>     {
>>>>         // use i
>>>>     }
>>>> Thoughts on this sort of feature?
>>>
>>> I would prefer the syntax
>>>
>>>   if( (int i = someFunc()) >= 0 )
>>>   {
>>>     // use i
>>>   }
>>>
>>> as this matches the already existing assignment expression syntax if you pull the declaration out of the if expression.
>>
>> Well you can argue the "if( init ; condition )" syntax matches "for( init ; condition ; update)", minus the "update" section.
>
> You've just answered your own question:
>     for (int i = someFunc(); i >= 0; )
>     {
>         // use i
>         break;
>     }

Yes, it was one of the examples I gave in the first post. Reason not to use that is, if you forget "break" you are probably going to have an infinite loop. As well you can't use "else" with a for statement.