November 02, 2017
On Thu, Nov 02, 2017 at 12:50:47PM +0000, Nick Treleaven via Digitalmars-d wrote: [..]
> I'd like to mention null-coalescing assignment syntax. Perl has `$a //= $b`, and PHP has voted to support `$a ??= $b`, expanding to `$a = $a ?? $b`.
[...]
> I expect D could do the same with `a ?:= b` or use the `??` operator syntax.

Isn't the `??` syntax what the Elvis operator `?:` supposed to do?

Given that the proposed Elvis operator would be `?:`, I'd expect the corresponding assignment operator would be `?:=`, in following the pattern of the other op-assign operators.


> Just from memory, I think I would use null coalescing assignments more than null coalescing comparisons.

If we're going to have one of them, might as well have both.


T

-- 
I think the conspiracy theorists are out to get us...
November 02, 2017
On Thursday, November 02, 2017 09:46:06 H. S. Teoh via Digitalmars-d wrote:
> On Thu, Nov 02, 2017 at 12:50:47PM +0000, Nick Treleaven via Digitalmars-d wrote: [..]
>
> > I'd like to mention null-coalescing assignment syntax. Perl has `$a //= $b`, and PHP has voted to support `$a ??= $b`, expanding to `$a = $a ?? $b`.
>
> [...]
>
> > I expect D could do the same with `a ?:= b` or use the `??` operator syntax.
> Isn't the `??` syntax what the Elvis operator `?:` supposed to do?
>
> Given that the proposed Elvis operator would be `?:`, I'd expect the corresponding assignment operator would be `?:=`, in following the pattern of the other op-assign operators.

In a previous thread, it was stated that in other languages (no idea which ones), ?? tests specifically for null, whereas ?: tests for true.

Other, related operators were discussed as well - including ?. - which if I understood correctly, allows you to call a member function only if the object isn't null.

But going into other operators like that starts taking this well beyond the basic idea of shortening the ternary operator for the x ? x : y case like the elvis operator does, and for better or worse, that takes the DIP in a whole new direction. However, if we do add ?:, I think that it's pretty clear that some folks will be asking for stuff like ?. or ?:=, since I think that it's largely the case that the folks who want the elvis operator are interested in the related operators.

However, their usefulness seems to be mostly predicated on the idea that you're doing a lot with class references or pointers which might be null and where you would want to do an operation with them if they're non-null and just skip that code if they're null. And given how little idiomatic D code uses classes, I don't know how useful they'll be in practice in D. It's likely to depend a lot on your coding style. I'm quite sure that I would find them borderline useless, but some of the folks who are highly interested in them may find a lot of use for them. I don't know.

- Jonathan M Davis

November 05, 2017
On Monday, 30 October 2017 at 19:46:54 UTC, Andrei Alexandrescu wrote:
>> I see from comments that different people think of it in a different way. I suggest them to read this section from Kotlin docs to understand the reasoning behind the elvis operator.
>
> The principle of least astonishment indicates we should do what the lowering does:
>
> expr1 ?: expr2
> ==>
> (x => x ? x : expr2)(expr1)
>
> An approach that does things any differently would have a much more difficult time. It is understood (and expected) that other languages have subtly different takes on the operator.
>
> Andrei

I may add that the same logic is used in .get(key, defaultValue) method of Associative Arrays

November 06, 2017
On Saturday, 28 October 2017 at 11:38:52 UTC, Andrei Alexandrescu wrote:
> Walter and I decided to kick-off project Elvis for adding the homonym operator to D.

It's easy to write in function form:

  auto orElse(T)(T a, lazy T b)
  {
    return a ? a : b;
  }

  writeln(args[1].length.orElse(fibonacci(50)));

This version can also be specialized for things like Nullable, where you can't necessarily cast it safely to a boolean but have a check for validity.

Is it that valuable to have an operator for it instead?


As an aside, I believe feepingcreature had a custom infix operator for this sort of thing defined, so you could write:

  (a /or/ b /or/ c).doStuff();

The implementation (along with /and/) is left as an exercise to the reader.
November 06, 2017
On Monday, 6 November 2017 at 00:20:09 UTC, Neia Neutuladh wrote:
> On Saturday, 28 October 2017 at 11:38:52 UTC, Andrei Alexandrescu wrote:
>> Walter and I decided to kick-off project Elvis for adding the homonym operator to D.
>
> It's easy to write in function form:
>
>   auto orElse(T)(T a, lazy T b)
>   {
>     return a ? a : b;
>   }
>
>   writeln(args[1].length.orElse(fibonacci(50)));
>
> This version can also be specialized for things like Nullable, where you can't necessarily cast it safely to a boolean but have a check for validity.
>
> Is it that valuable to have an operator for it instead?
>
>
> As an aside, I believe feepingcreature had a custom infix operator for this sort of thing defined, so you could write:
>
>   (a /or/ b /or/ c).doStuff();
>
> The implementation (along with /and/) is left as an exercise to the reader.

Sure you might be able to write it easily, but pretty much everyone writes a function like that in their projects and you don\t really know the implementation always and you have to remember the exact name or else you end up writing the function yourself in your project to make sure the implementation is exactly like that, which in fact turns out to be re-inventing the wheel.

By having an official syntax for it, you don't end up with code duplication like that and the implementation details of the behavior is clear.

Because in some implementation "orElse()" might only check if the value is null and not necessary if the value is true.

Ex. one might implement it like:

   auto orElse(T)(T a, lazy T b)
   {
     return a !is null ? a : b;
   }

Such implementation detail is not clear from the call-side.

However with an official implementation you know exactly how it will behave and nothing is obscure like this.
November 06, 2017
On Monday, November 06, 2017 07:10:43 bauss via Digitalmars-d wrote:
> On Monday, 6 November 2017 at 00:20:09 UTC, Neia Neutuladh wrote:
> > On Saturday, 28 October 2017 at 11:38:52 UTC, Andrei
> >
> > Alexandrescu wrote:
> >> Walter and I decided to kick-off project Elvis for adding the homonym operator to D.
> >
> > It's easy to write in function form:
> >   auto orElse(T)(T a, lazy T b)
> >   {
> >
> >     return a ? a : b;
> >
> >   }
> >
> >   writeln(args[1].length.orElse(fibonacci(50)));
> >
> > This version can also be specialized for things like Nullable, where you can't necessarily cast it safely to a boolean but have a check for validity.
> >
> > Is it that valuable to have an operator for it instead?
> >
> >
> > As an aside, I believe feepingcreature had a custom infix
> >
> > operator for this sort of thing defined, so you could write:
> >   (a /or/ b /or/ c).doStuff();
> >
> > The implementation (along with /and/) is left as an exercise to
> > the reader.
>
> Sure you might be able to write it easily, but pretty much everyone writes a function like that in their projects and you don\t really know the implementation always and you have to remember the exact name or else you end up writing the function yourself in your project to make sure the implementation is exactly like that, which in fact turns out to be re-inventing the wheel.
>
> By having an official syntax for it, you don't end up with code duplication like that and the implementation details of the behavior is clear.
>
> Because in some implementation "orElse()" might only check if the value is null and not necessary if the value is true.
>
> Ex. one might implement it like:
>
>     auto orElse(T)(T a, lazy T b)
>     {
>       return a !is null ? a : b;
>     }
>
> Such implementation detail is not clear from the call-side.
>
> However with an official implementation you know exactly how it will behave and nothing is obscure like this.

That might be an argument for having an official implementation, but it's not really an argument for why it should be built into the language; it could just as easily be in Phobos if that's all that matters.

- Jonathan M Davis

November 06, 2017
On Monday, 6 November 2017 at 08:06:54 UTC, Jonathan M Davis wrote:
> On Monday, November 06, 2017 07:10:43 bauss via Digitalmars-d wrote:
>> On Monday, 6 November 2017 at 00:20:09 UTC, Neia Neutuladh wrote:
>> > On Saturday, 28 October 2017 at 11:38:52 UTC, Andrei
>> >
>> > Alexandrescu wrote:
>> >> [...]
>> >
>> > It's easy to write in function form:
>> >   auto orElse(T)(T a, lazy T b)
>> >   {
>> >
>> >     return a ? a : b;
>> >
>> >   }
>> >
>> >   writeln(args[1].length.orElse(fibonacci(50)));
>> >
>> > This version can also be specialized for things like Nullable, where you can't necessarily cast it safely to a boolean but have a check for validity.
>> >
>> > Is it that valuable to have an operator for it instead?
>> >
>> >
>> > As an aside, I believe feepingcreature had a custom infix
>> >
>> > operator for this sort of thing defined, so you could write:
>> >   (a /or/ b /or/ c).doStuff();
>> >
>> > The implementation (along with /and/) is left as an exercise to
>> > the reader.
>>
>> Sure you might be able to write it easily, but pretty much everyone writes a function like that in their projects and you don\t really know the implementation always and you have to remember the exact name or else you end up writing the function yourself in your project to make sure the implementation is exactly like that, which in fact turns out to be re-inventing the wheel.
>>
>> By having an official syntax for it, you don't end up with code duplication like that and the implementation details of the behavior is clear.
>>
>> Because in some implementation "orElse()" might only check if the value is null and not necessary if the value is true.
>>
>> Ex. one might implement it like:
>>
>>     auto orElse(T)(T a, lazy T b)
>>     {
>>       return a !is null ? a : b;
>>     }
>>
>> Such implementation detail is not clear from the call-side.
>>
>> However with an official implementation you know exactly how it will behave and nothing is obscure like this.
>
> That might be an argument for having an official implementation, but it's not really an argument for why it should be built into the language; it could just as easily be in Phobos if that's all that matters.
>
> - Jonathan M Davis

You need additional import for this
verbose syntax
https://en.wikipedia.org/wiki/Syntactic_sugar
Why we have operators overloading when we could have Equals() and stuff like in java?
Why we have arr ~= arr2 when we could have Array.mergeArrays(arr, arr2) instead?

Look, this operator does not break anything. If you don't want to use it, just don't, but why do you force everyone else to not to use it, just because it is not adding anything "more valuable" than just better syntax?
November 06, 2017
On Monday, November 06, 2017 09:26:24 Satoshi via Digitalmars-d wrote:
> Look, this operator does not break anything. If you don't want to use it, just don't, but why do you force everyone else to not to use it, just because it is not adding anything "more valuable" than just better syntax?

_Everything_ that is added to the language complicates it further. It's one more thing that everyone learning the language has to learn and know and potentially deal with in code. Obviously, some things are worth the extra complication, or we'd all be programming in C, but there is always a cost to adding something, and the feature needs to be worth that cost.

Granted, the elvis operator as proposed is not all that complicated, but adding it does make the language that much more complex, and it really doesn't do much. All it does is take the expression

x ? x : y

and make it

x ?: y

It saves 2 characters plus the length of the variable name. That's it. And it's optimizing an idiom that isn't going to tend to show up much in idiomatic D code. It seems to be targeted primarily at code that does a lot with classes and is written in such a way that it's not clear whether a class reference should be null or not, whereas most D code doesn't do much with classes. Rather, it does a lot with ranges and structs on the stack. Obviously, some code uses classes, and I expect that some code would benefit from the elvis operator, but I dispute that it's a common enough idiom to merit being added the language.

Personally, while I frequently use the ternary operator, I almost never end up with the left and middle branches being the same, which is the only place that the elvis operator would be useful. And I don't think that Phobos does it much either. So, unless a lot of D code out there is using a drastically different coding style that does a lot with null, the elvis operator will not help much D code.

So, IMHO, the elvis operator adds very little value, and I'd just as soon not see the language complicated further without adding real value in the process. So, I'll argue against it, but ultimately, it's not my decision. Rather, it's up to Walter and Andrei, and they'll decide what they decide.

But don't expect anyone not to be unhappy about a feature being added to the language when they don't think that the feature adds value, because there is always a cost to a new feature. The difference is that you think that the feature is worth the cost, not that the folks who don't want to use the feature don't have to pay the cost.

- Jonathan M Davis

November 06, 2017
On 11/05/2017 07:20 PM, Neia Neutuladh wrote:
> On Saturday, 28 October 2017 at 11:38:52 UTC, Andrei Alexandrescu wrote:
>> Walter and I decided to kick-off project Elvis for adding the homonym operator to D.
> 
> It's easy to write in function form:
> 
>    auto orElse(T)(T a, lazy T b)
>    {
>      return a ? a : b;
>    }
> 
>    writeln(args[1].length.orElse(fibonacci(50)));
> 
> This version can also be specialized for things like Nullable, where you can't necessarily cast it safely to a boolean but have a check for validity.
> 
> Is it that valuable to have an operator for it instead?
> 
> 
> As an aside, I believe feepingcreature had a custom infix operator for this sort of thing defined, so you could write:
> 
>    (a /or/ b /or/ c).doStuff();
> 
> The implementation (along with /and/) is left as an exercise to the reader.

If a DIP emerges, it would need to present such alternatives and argue how it adds value over them. -- Andrei
November 06, 2017
On Monday, 6 November 2017 at 10:12:11 UTC, Jonathan M Davis wrote:
> x ? x : y
>
> and make it
>
> x ?: y
>
> It saves 2 characters plus the length of the variable name. That's it.

I find I often use this in C# with a more complex expression on the left-hand side, like a function call. A quick search shows more than 2/3 of my uses are function calls or otherwise significantly more complex than a variable. Also, it works great in conjunction with the null conditional:

foo.Select(a => bar(a, qux)).FirstOrDefault?.Name ?? "not found";

> It seems to be targeted primarily at code that does a lot with classes and is written in such a way that it's not clear whether a class reference should be null or not, whereas most D code doesn't do much with classes.

In my C# code, it's used with strings and Nullable<T> more often than with classes.

Given my own experience with the ?? operator, I'd argue it's probably not worth it without also including null conditional (?.). A quick search in a few projects indicate roughly half the uses of ?? also use ?..

--
  Biotronic