digitalmars.D - surprising semantics of the && expression
- user1234 (8/8) Feb 03 So yesterday someone oppened an issue:
- Timon Gehr (13/26) Feb 03 C is not very type safe (and used to be even less so), and people get
- Forum User (4/15) Feb 03 Sure, but in C (as in C++) with int b and void foo ()
- Walter Bright (5/5) Feb 03 ```
- Timon Gehr (11/31) Feb 04 Why declare the return type as `void` when you could just claim it is
- Walter Bright (7/17) Feb 04 ```c
- Derek Fawcus (16/17) Feb 04 It did, added around Nov '78 (or latest Jul 82).
- Walter Bright (2/5) Feb 04 My copy of K+R was published in 1978. No void!
- Derek Fawcus (4/9) Feb 05 So was mine. As I noted, the compiler had it, simply that the
- Derek Fawcus (5/15) Feb 05 More to the point though, for backward compatibility, the
- Timon Gehr (6/27) Feb 04 If validity as D is not a concern you can also just write:
- Forum User (18/26) Feb 04 $ gcc -Wall -pedantic -pedantic-errors c.c
- Timon Gehr (2/32) Feb 04 gcc -w c.c
- Iain Buclaw (5/13) Feb 03 This has been valid since early D1.
- Julian Fondren (43/56) Feb 03 and only since DIP 1034 in 2021 can || still evaluate to a bool
So yesterday someone oppened an issue: https://github.com/dlang/dmd/issues/22500 Which was closed after accurate explanations of Ian. However I'd like to know where this semantics are coming from. I suspect C++ ? What is the history behind ? Let's mention the POLA. The very basic human-being would expect that both the LHS and RHS sub-expressions can be implictly convertible to `bool`.
Feb 03
On 2/3/26 18:29, user1234 wrote:So yesterday someone oppened an issue: https://github.com/dlang/dmd/issues/22500 Which was closed after accurate explanations of Ian. However I'd like to know where this semantics are coming from. I suspect C++ ? What is the history behind ? ...C is not very type safe (and used to be even less so), and people get attached to idioms.Let's mention the POLA. The very basic human-being would expect that both the LHS and RHS sub-expressions can be implictly convertible to `bool`.That is not true anyway. ;p ```d int foo(){ ... } bool a = foo()&&foo(); // ok bool b = foo(); // not ok ``` (It requires explicit convertibility, not implicit.) A common shorthand in D for `cast(bool)e` is `!!e`. `assert(c)` for class reference `c` used to segfault on `null`. I still consistently write `assert(!!c)` today.
Feb 03
On Tuesday, 3 February 2026 at 20:15:42 UTC, Timon Gehr wrote:On 2/3/26 18:29, user1234 wrote:Sure, but in C (as in C++) with int b and void foo () b && foo (); is not an idiom. It does not compile.So yesterday someone oppened an issue: https://github.com/dlang/dmd/issues/22500 Which was closed after accurate explanations of Ian. However I'd like to know where this semantics are coming from. I suspect C++ ? What is the history behind ? ...C is not very type safe (and used to be even less so), and people get attached to idioms.
Feb 03
``` b && foo() ``` is there because it is useful, as `if` statements cannot be put inside an expression.
Feb 03
On 2/3/26 23:34, Forum User wrote:On Tuesday, 3 February 2026 at 20:15:42 UTC, Timon Gehr wrote:Why declare the return type as `void` when you could just claim it is `int` instead. Compiles as C as well as D: ```c auto foo(){} void main(){ int b = 1; b && foo(); } ```On 2/3/26 18:29, user1234 wrote:Sure, but in C (as in C++) with int b and void foo () b && foo (); is not an idiom. It does not compile.So yesterday someone oppened an issue: https://github.com/dlang/dmd/issues/22500 Which was closed after accurate explanations of Ian. However I'd like to know where this semantics are coming from. I suspect C++ ? What is the history behind ? ...C is not very type safe (and used to be even less so), and people get attached to idioms.
Feb 04
On 2/4/2026 1:20 AM, Timon Gehr wrote:
Compiles as C as well as D:
```c
auto foo(){}
void main(){
int b = 1;
b && foo();
}
```
```c
int foo() { }
```
compiles without complaint from C.
The reason is historical, as K+R C did not require a function to annotate its
return type, and defaulted to int. K+R C did not have a void type.
Feb 04
K+R C did not have a void type.It did, added around Nov '78 (or latest Jul 82). It is just that they never reprinted the book to account for void, enums and struct assignment/pass/return being added. If one grabs some of the historical sources, one can see said support. From DMR's home page: 'However, it turns out that the paper copies of the 7th Edition manual that we printed locally include not only what became Appendix A of K&R 1, but also a page entitled "Recent Changes to C", and I retyped this.' I recall reading this in the papers section at the end of the Unix manuals for the system I had access to. https://www.nokia.com/bell-labs/about/dennis-m-ritchie/cchanges.pdf The page above doesn't specifically mention void, but one can see it in the historical PCC sources if one grabs them (file dates between Jun 81 and Jul 82). Bitsavers has a cooy somewhere, as they were used to build the PC-TCP stack.
Feb 04
On 2/4/2026 11:41 AM, Derek Fawcus wrote:My copy of K+R was published in 1978. No void!K+R C did not have a void type.It did, added around Nov '78 (or latest Jul 82).
Feb 04
On Thursday, 5 February 2026 at 02:04:00 UTC, Walter Bright wrote:On 2/4/2026 11:41 AM, Derek Fawcus wrote:So was mine. As I noted, the compiler had it, simply that the book did not mention it. DFMy copy of K+R was published in 1978. No void!K+R C did not have a void type.It did, added around Nov '78 (or latest Jul 82).
Feb 05
On Thursday, 5 February 2026 at 11:34:39 UTC, Derek Fawcus wrote:On Thursday, 5 February 2026 at 02:04:00 UTC, Walter Bright wrote:More to the point though, for backward compatibility, the compiler still allowed falling off the end of a function returning 'int'. DFOn 2/4/2026 11:41 AM, Derek Fawcus wrote:So was mine. As I noted, the compiler had it, simply that the book did not mention it.My copy of K+R was published in 1978. No void!K+R C did not have a void type.It did, added around Nov '78 (or latest Jul 82).
Feb 05
On 2/4/26 19:08, Walter Bright wrote:On 2/4/2026 1:20 AM, Timon Gehr wrote:If validity as D is not a concern you can also just write: ```c foo(){ } ```Compiles as C as well as D: ```c auto foo(){} void main(){ int b = 1; b && foo(); } ``````c int foo() { } ``` compiles without complaint from C. ...The reason is historical, as K+R C did not require a function to annotate its return type, and defaulted to int. K+R C did not have a void type.Yes, and then `b && foo()` works, even if you don't return a value.
Feb 04
On Wednesday, 4 February 2026 at 09:20:13 UTC, Timon Gehr wrote:
Compiles as C as well as D:
```c
auto foo(){}
void main(){
int b = 1;
b && foo();
}
```
$ gcc -Wall -pedantic -pedantic-errors c.c
c.c:1:6: error: function definition declared 'auto'
1 | auto foo(){}
| ^~~
c.c:1:6: error: return type defaults to 'int' [-Wimplicit-int]
c.c:3:6: error: return type of 'main' is not 'int' [-Wmain]
3 | void main(){
| ^~~~
c.c: In function 'main':
c.c:5:7: warning: value computed is not used [-Wunused-value]
5 | b && foo();
| ^~
c.c: In function 'foo':
c.c:1:12: warning: control reaches end of non-void function
[-Wreturn-type]
1 | auto foo(){}
| ^
Feb 04
On 2/4/26 22:19, Forum User wrote:On Wednesday, 4 February 2026 at 09:20:13 UTC, Timon Gehr wrote:gcc -w c.cCompiles as C as well as D: ```c auto foo(){} void main(){ int b = 1; b && foo(); } ```$ gcc -Wall -pedantic -pedantic-errors c.c c.c:1:6: error: function definition declared 'auto' 1 | auto foo(){} | ^~~ c.c:1:6: error: return type defaults to 'int' [-Wimplicit-int] c.c:3:6: error: return type of 'main' is not 'int' [-Wmain] 3 | void main(){ | ^~~~ c.c: In function 'main': c.c:5:7: warning: value computed is not used [-Wunused-value] 5 | b && foo(); | ^~ c.c: In function 'foo': c.c:1:12: warning: control reaches end of non-void function [-Wreturn-type] 1 | auto foo(){} | ^
Feb 04
On Tuesday, 3 February 2026 at 17:29:05 UTC, user1234 wrote:So yesterday someone oppened an issue: https://github.com/dlang/dmd/issues/22500 Which was closed after accurate explanations of Ian. However I'd like to know where this semantics are coming from. I suspect C++ ? What is the history behind ?This has been valid since early D1. https://digitalmars.com/d/1.0/expression.html#OrOrExpressionLet's mention the POLA. The very basic human-being would expect that both the LHS and RHS sub-expressions can be implictly convertible to `bool`.Perhaps you've never used a scripting language such as Perl? Ruby and Python are probably the same too.
Feb 03
On Tuesday, 3 February 2026 at 23:11:03 UTC, Iain Buclaw wrote:On Tuesday, 3 February 2026 at 17:29:05 UTC, user1234 wrote:and only since DIP 1034 in 2021 can || still evaluate to a bool in an assert-like case: ```d import std.stdio : writeln; import core.stdc.stdlib : exit; noreturn fail() { exit(1); } void main(string[] args) { bool b = args.length == 1 || fail(); writeln(b); } ```So yesterday someone oppened an issue: https://github.com/dlang/dmd/issues/22500 Which was closed after accurate explanations of Ian. However I'd like to know where this semantics are coming from. I suspect C++ ? What is the history behind ?This has been valid since early D1.The principle of least astonishment most often comes across as a slightly rude dismissal of the expectations of others. What's the astonishment-math that says that another is wrong for expecting `test || fail()` to work in D? Now, you can do that if you don't take the value of the expression. I imagine that the status quo silences some rare programmer errors, like ```d bool flag; test && complain(); do_something(flag); ``` where during editing you dropped an assignment to `flag`, and didn't notice because the code was still accepted with a different meaning than you intended. The code also would not have worked if you'd kept the assignment, but the two errors cancel out and permit a third error that you are now confused by: how could flag possibly be false when you can see the output from complain()??? The other way that the "principle of least astonishment" comes up is that someone has an unpleasant experience like this and wishes that the language hadn't permitted the confusion. Especially when the feature, that was used without the programmer even knowing about it, doesn't seem to add much. I sympathize a lot with this and have some stories, but you are just going to be confused sometimes, and terms like POLA too easily discount that reality. A new epoch of D with different enough semantics could lead to many errors of confusion just from the difference, even if the new semantics are much cleaner.Let's mention the POLA. The very basic human-being would expect that both the LHS and RHS sub-expressions can be implictly convertible to `bool`.
Feb 03









Walter Bright <newshound2 digitalmars.com> 