Missing binary operator shortcuts &&= and ||=

605 views
Skip to first unread message

occ...@esperanto.org

unread,
May 4, 2017, 2:15:46 PM5/4/17
to golang-nuts
One apparently random omission in C, which was fixed in Perl, is &&= and ||=:

a &&= b
    a = a && b
a ||= b
    a = a || b

except that a gets evalutated only once (e.g.  myarray[f(2)] &&= b)

Besides being useful, this would make Go more consistent.  Of course relative operators also do not have this, but there usually the result type is different (e.g.  bool = int < int)

regards – Da

Ian Lance Taylor

unread,
May 4, 2017, 3:43:19 PM5/4/17
to occ...@esperanto.org, golang-nuts
The &&= and ||= operators are omitted in both C and Go because they
are short-cutting operators. When you write `a = a && b`, then if a
is true, b is not evaluated. So presumably when you write `a &&= b`
then if a is true b is not evaluated. But it is potentially confusing
to see `a &&= f()` when f() may or may not be called.

Ian

Michael Jones

unread,
May 4, 2017, 3:50:16 PM5/4/17
to Ian Lance Taylor, occ...@esperanto.org, golang-nuts
What is *actually* missing is boolean operators for boolean types.


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Michael T. Jones
michae...@gmail.com

occ...@esperanto.org

unread,
May 4, 2017, 4:39:02 PM5/4/17
to golang-nuts, occ...@esperanto.org
Le jeudi 4 mai 2017 21:43:19 UTC+2, Ian Lance Taylor a écrit :
... it is potentially confusing
to see `a &&= f()` when f() may or may not be called.

How is that more confusing than `a && f()` when f() may or may not be called?

Da

Ian Lance Taylor

unread,
May 4, 2017, 4:44:58 PM5/4/17
to occ...@esperanto.org, golang-nuts
I assert without evidence that for many people it would be confusing
to see a function call alone on the right hand side of an `=` when
that function may or may not be called.

Ian

roger peppe

unread,
May 5, 2017, 3:52:00 AM5/5/17
to Michael Jones, Ian Lance Taylor, occ...@esperanto.org, golang-nuts
On 4 May 2017 at 20:48, Michael Jones <michae...@gmail.com> wrote:
> What is *actually* missing is boolean operators for boolean types.

Really? We've got !, &&, ||, != (xor), == (xnor). What's missing?

> On Thu, May 4, 2017 at 12:43 PM, Ian Lance Taylor <ia...@golang.org> wrote:
>>
>> On Thu, May 4, 2017 at 9:42 AM, <occ...@esperanto.org> wrote:
>> >
>> > One apparently random omission in C, which was fixed in Perl, is &&= and
>> > ||=:
>> >
>> > a &&= b
>> > a = a && b
>> > a ||= b
>> > a = a || b
>> >
>> > except that a gets evalutated only once (e.g. myarray[f(2)] &&= b)
>> >
>> > Besides being useful, this would make Go more consistent. Of course
>> > relative operators also do not have this, but there usually the result
>> > type
>> > is different (e.g. bool = int < int)
>>
>> The &&= and ||= operators are omitted in both C and Go because they
>> are short-cutting operators. When you write `a = a && b`, then if a
>> is true, b is not evaluated. So presumably when you write `a &&= b`
>> then if a is true b is not evaluated. But it is potentially confusing
>> to see `a &&= f()` when f() may or may not be called.
>>
>> Ian
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "golang-nuts" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to golang-nuts...@googlegroups.com.
>> For more options, visit https://groups.google.com/d/optout.
>
>
>
>
> --
> Michael T. Jones
> michae...@gmail.com
>
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts...@googlegroups.com.

Ian Lance Taylor

unread,
May 5, 2017, 8:35:43 AM5/5/17
to roger peppe, Michael Jones, occ...@esperanto.org, golang-nuts
On Fri, May 5, 2017 at 12:51 AM, roger peppe <rogp...@gmail.com> wrote:
> On 4 May 2017 at 20:48, Michael Jones <michae...@gmail.com> wrote:
>> What is *actually* missing is boolean operators for boolean types.
>
> Really? We've got !, &&, ||, != (xor), == (xnor). What's missing?

In a sense we are missing & and |, the non-shortcut versions of && and ||.

Ian

Michael Jones

unread,
May 5, 2017, 9:12:04 AM5/5/17
to Ian Lance Taylor, roger peppe, Da Niel, golang-nuts
Just so. One cannot do boolean arithmetic with boolean variables. 

We have:
  EQUIVALENCE ("==")
  XOR ("!=")
  NOT ("!")  -- George Boole's NEGATION

We lack:
  AND ("&") -- George Boole's CONJUNCTION
  OR ("|") -- George Boole's DISJUNCTION

As it happens, one can implement all the operators from the basis of NEGATION and either CONJUNCTION or DISJUNCTION, but as we lack each of the last two, one must be sure to use ints where bools would be natural.

Obviously Go users have gotten along fine without the two missing operations so there may be little argument for it. (Also, with the bool type as Go's platypus there is an aura of acceptable inconsistency anyway--since we can't take addresses of them* then it could be argued that other differences are ok as well.)

On the pro side, Rob did once mention openness to including them.

Michael

* Understand the reason...allowing future implementation of packed boolean arrays.


>>> For more options, visit https://groups.google.com/d/optout.
>>
>>
>>
>>
>> --
>> Michael T. Jones
>> michae...@gmail.com
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "golang-nuts" group.
>> To unsubscribe from this group and stop receiving emails from it, send an

>> For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

roger peppe

unread,
May 5, 2017, 10:27:03 AM5/5/17
to Michael Jones, Ian Lance Taylor, Da Niel, golang-nuts
On 5 May 2017 at 14:11, Michael Jones <michae...@gmail.com> wrote:
> Just so. One cannot do boolean arithmetic with boolean variables.
>
> We have:
> EQUIVALENCE ("==")
> XOR ("!=")
> NOT ("!") -- George Boole's NEGATION
>
> We lack:
> AND ("&") -- George Boole's CONJUNCTION
> OR ("|") -- George Boole's DISJUNCTION
>
> As it happens, one can implement all the operators from the basis of
> NEGATION and either CONJUNCTION or DISJUNCTION, but as we lack each of the
> last two, one must be sure to use ints where bools would be natural.

I don't get it. What's the difference between a&&b
and the hypothetical a&b for two expressions a and b,
assuming a and b are free of side-effects ?

> Obviously Go users have gotten along fine without the two missing operations
> so there may be little argument for it. (Also, with the bool type as Go's
> platypus there is an aura of acceptable inconsistency anyway--since we can't
> take addresses of them* then it could be argued that other differences are
> ok as well.)

I don't get this either - we can indeed take addresses of bool-typed
values: https://play.golang.org/p/L9yxgq_bSj

Apologies for my obtuseness :)

occ...@esperanto.org

unread,
May 5, 2017, 7:07:16 PM5/5/17
to golang-nuts, occ...@esperanto.org
Le jeudi 4 mai 2017 22:44:58 UTC+2, Ian Lance Taylor a écrit :
I assert without evidence that for many people it would be confusing
to see a function call alone on the right hand side of an `=` when
that function may or may not be called.

Various languages like Perl, PHP, Ruby & zsh have the two operators I propose.  If you can find no evidence among programmers of those, your point seems moot. Also there is discussion (e.g. on Stackoverflow) about this for various languages like C, C++, C# & Java, so people do want this!

regards – Da


Jesper Louis Andersen

unread,
May 6, 2017, 8:12:47 AM5/6/17
to occ...@esperanto.org, golang-nuts
Finding evidence among programmers can be tricky. You may be up against a considerable selection bias in a lot of cases:

* You pick among experts in the field. Newcomers are unlikely to have the same problems as experts.
* The set of people who wants a certain feature tend to be more vocal about it. The set of people who doesn't really care can be far larger, but since they are not vocal, you don't get any response.
* Languages with dynamic types tend to be more "operator heavy" since they have to. You need an operator for certain pairings of different types, where a language with static types can overload them and figure out what to do based on the input types (implicitly).

Personal opinion:

I'm hesitant when people suggest syntactic sugar in programming languages, because it adds very little expressive power for convenience saved when typing. After all, because it is sugar, there is a way to write it without said construct in the language. Granted, it is nice you can save some keystrokes. But it has to be weighed against how often those keystrokes are saved. If it is just an argument of less typing, you could argue more keystrokes would be saved by changing func to fn and while to whl.

A construction such as =&& may help if the language you are looking at has a less sophisticated optimization engine. It becomes a "macro" which can be expanded easily by the compiler into a "faster variant". Yet, once you have optimizations in place and you have propagation of values, the benefit of the "macro" can disappear.

Another point worth mentioning is that whenever you add more grammar to a language, you make it harder to add more grammar later. We have an artificial limit in our keyboards and which characters are easy to type on keyboards by default. So languages tend to pick amongst those characters. Whenever you build up a digram or trigram, you may reap yourself of later extension. It is a bit more involved because lexers and parsers have limitations in what language they can easily recognize. A seemingly innocent addition can wreak havoc down the road.

Finally, since grammar is limited, using it for syntactic sugar removes your ability to use it for other constructions later. C++ 11 seems to have some reference semantics around the && operator in overloaded form, and thus =&& may have a different meaning. If you had used it for boolean values, you might reject the new construction on grounds of it being confusing.

Productivity in a programming language is weird and non-linear. Often, it is not the code itself that provides a limit, but rather the idea and solution you are cooking up in your mind. Slightly paraphrasing Peter Naur[0], programmers have a built-up knowledge in their brain of what they are working on, but the program is merely a projection of that knowledge. Crucially, we tend to value simple elegant programs, so the program is almost always a well-chosen subset of the built-up knowledge. Especially when the programmer is highly skilled, since they are able to cut off parts which are not important to the problem solution. We revel in the short and elegant program, but the real amazement to the seasoned programmer is every code line not written, but still accounted for. Thus, we value emergent behaviors of software.

In this light, productivity tend to be less tied to the verbosity of the written code. After all, most of the time should be conducted by thinking about the problem to solve, not typing it up. If you find yourself furiously typing away at the keyboard for a given problem, chances are the problem has a better solution[1]


[1] Aside: the reason we often end up doing lots of mundane stuff is because people who came before decided on other abstractions, which turn out to be slightly less optimal for our cause. A rather innocuous choice between JSON and protobufs, for example, can have far-reaching consequences for the quality of the software in the long run, because the dynamic nature and weak type classification of JSON tend to virally infect a code base. This can only be solved by additional mundane typing, debugging and bug fixing.


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Ian Lance Taylor

unread,
May 6, 2017, 9:01:07 PM5/6/17
to roger peppe, Michael Jones, Da Niel, golang-nuts
On Fri, May 5, 2017 at 10:26 AM, roger peppe <rogp...@gmail.com> wrote:
> On 5 May 2017 at 14:11, Michael Jones <michae...@gmail.com> wrote:
>> Just so. One cannot do boolean arithmetic with boolean variables.
>>
>> We have:
>> EQUIVALENCE ("==")
>> XOR ("!=")
>> NOT ("!") -- George Boole's NEGATION
>>
>> We lack:
>> AND ("&") -- George Boole's CONJUNCTION
>> OR ("|") -- George Boole's DISJUNCTION
>>
>> As it happens, one can implement all the operators from the basis of
>> NEGATION and either CONJUNCTION or DISJUNCTION, but as we lack each of the
>> last two, one must be sure to use ints where bools would be natural.
>
> I don't get it. What's the difference between a&&b
> and the hypothetical a&b for two expressions a and b,
> assuming a and b are free of side-effects ?

There is none.

But sometimes b has a side-effect. And sometimes you want that
side-effect to be executed whether or not a is true. Then writing `a
&& b` does not work, and the alternatives are either verbose or
require introducing a new temporary variable name.

Ian

roger peppe

unread,
May 8, 2017, 3:46:14 AM5/8/17
to Ian Lance Taylor, Michael Jones, Da Niel, golang-nuts
If you're doing it a lot, then you could always do:

func and(x, y bool) bool { return x && y }

To be honest, I generally think that having two sub-expressions
with visible side-effects in the same expression is not great practice,
even if Go does guarantee order of evaluation.

Michael Jones

unread,
May 8, 2017, 8:50:44 AM5/8/17
to roger peppe, Ian Lance Taylor, Da Niel, golang-nuts
To be honest, I generally think that having two sub-expressions
with visible side-effects in the same expression is not great practice,
even if Go does guarantee order of evaluation.

...in my case, I had an expression rewrite system (think DeMorgan’s theorems) with boolean functions for the values and I was in fact counting on each function being visited. I realized that && and || were my nemesis, so I switched to integers, considering the lack of & and | for bool types a loss for completeness and stayed away from bool since.

I don't know what I was thinking about the address-of-bool issue. I remember it plainly but testing it just now I see that it works fine. Hmm... Makes me feel old.
Reply all
Reply to author
Forward
0 new messages