August 14
On Tuesday, 13 August 2024 at 20:55:09 UTC, Nick Treleaven wrote:
> On Tuesday, 13 August 2024 at 10:14:29 UTC, Timon Gehr wrote:
>> A bug that crops up now and then in D is that someone negates `a == b` by prepending a `!`. The result is `!a == b`. This parses as `(!a) == b` and will often silently do the wrong thing because negation implies cast to `bool`, and `bool` can be compared with integral types and `enum` members.
>
> I was a bit surprised that someone would write that (other than someone new to C-like syntax), but then I saw:
> https://github.com/dlang/dmd/pull/16778#discussion_r1715017456

In my defence, I was half asleep and recovering from a cold, but CI would have caught this.

Having said that, I agree, it should be made an error. Well deprecation then error, it probably doesn't need to be a DIP
August 14

On Tuesday, 13 August 2024 at 21:02:28 UTC, Nick Treleaven wrote:

>

On Tuesday, 13 August 2024 at 20:40:32 UTC, IchorDev wrote:

>

On Tuesday, 13 August 2024 at 20:30:10 UTC, IchorDev wrote:

>

Do we really need to pander to people who don’t even understand that logical operators only return bool?

I think it's actually that they don't know the operator precedence, or they just made a mistake.

My point being that it’s a weird mistake to make, and one I’ve never seen. Have you ever seen it before?

> >

A problem I have actually had is not being able to parse the operation order for expressions like 1 + 2 * 3, but I don’t think we should require parenthesis there either.

Agreed, because that syntax comes from maths rather than a subset of programming languages.

I learned programming to learn programming, not to learn mathematics. A lot of concepts from mathematics are completely incompatible with programming because we work with numbers that have to be physically stored. You can’t store irrational numbers, you can’t even store recursive fractions without a special encoding system, and even then there’ll still be a fraction that’s too long to store in the universe.

> >

Also, here’s a nice case where I’d actually want to write this: !myInt == myBool Again, here the parenthesis would just be visual noise.

The diagnostic doesn't need to fire when both sides are bool.

Well there’s still situations like ternary enums to account for.

August 14

On Tuesday, 13 August 2024 at 21:13:17 UTC, Dennis wrote:

>

On Tuesday, 13 August 2024 at 20:30:10 UTC, IchorDev wrote:

>

But I’ve also never seen anyone think this would work?

It's easy to have a lapse of focus. Last hour, I accidentally used && for bit masking instead of &. I also sometimes write if (x = 3) by mistake, or forget a return statement like this:

bool f(int x)
{
    x == 3;
}

Wow you have some… strange problems.

>

Luckily the D compiler catches these. It's not that I thought these things would work in D, but simple human error.

When you write the wrong thing, you get the wrong result. The language doesn’t pull any punches when it comes to much more complex things, so why be pedantic with something so elementary? If you want something like this to have an anti-goof mechanism, let’s just add such a mechanism for all of the other situations that might trip up a beginner:

  • mutability attributes are transitive —> always require parenthesis after mutability attributes
  • integral to floating point conversion can occur implicitly —> require a cast
  • operator precedence is arbitrary —> require parenthesis around every operator
  • cast doesn’t always do the same thing —> require a cast keyword after the type to make sure the programmer knows what type of cast it is (e.g. cast(long, signExtend)myInt)
  • dereferencing null values —> require a cast to typeof(null) ;)
  • contracts shouldn’t have side effects —> treat contract code as pure
  • integer promotion is stupid —> require a cast
>

It's also worth noting that things are different in other programming languages. In some languages the last expression is automatically returned.

Other languages will always have things that work in contradictory ways, should we really shape the language around that?
Also if we added last-expression return then it would generally be convenient, instead of inconvenient like the proposed feature. Not that I’m particularly for or against last-expression return, it is what it Is.

>

And in Python, the order of operations makes !a == b actually work like most (new) programmers intend

Exceptions terminate for loops, numbers are immutable class instances, +, and now this too? This is no python, it’s more akin to Jörmungandr!

August 14

On Wednesday, 14 August 2024 at 13:26:44 UTC, IchorDev wrote:

>

Wow you have some… strange problems.

If you've never made such silly programming mistakes, enjoy it while it lasts!

>

let’s just add such a mechanism for all of the other situations that might trip up a beginner:

Interesting list. Some of them have been seriously suggested for D or implemented in other languages. Specifically, D's integer promotion rules get criticized a lot, and some languages are a lot stricter about it.

I do agree with you generally: just because a combination of features is commonly used mistakenly, doesn't mean a special case should be added disallowing the combination.

However, there are cases where the ratio of erroneous usage / intentional usage is so large, that a compiler error will in practice reduce the total amount of 'programmer rage' so to speak.

Whether !a == b is such a case depends. You apparently have seen intentional use, so it makes sense you judge it as not worth adding an error for. I'm actually curious, can you link to real code using that pattern intentionally?

>

Other languages will always have things that work in contradictory ways, should we really shape the language around that?

All I'm saying is that it's possible for polyglot programmer's to make mixups, in response to you saying you couldn't imagine how someone could make a mistake like !a == b.

August 14
On Tuesday, 13 August 2024 at 10:14:29 UTC, Timon Gehr wrote:
> A bug that crops up now and then in D is that someone negates `a == b` by prepending a `!`. The result is `!a == b`. This parses as `(!a) == b` and will often silently do the wrong thing because negation implies cast to `bool`, and `bool` can be compared with integral types and `enum` members.
>
> I think it would be better for this to give a diagnostic and require explicit parentheses, similar to bitwise operators (where the operator precedence is unintuitive in the other direction).

Well, just wanna say that this is an easy check to implement in Dscanner. That does not require any context. Just match the pattern in the AST and issue a warning.
August 14

On Wednesday, 14 August 2024 at 14:36:50 UTC, Dennis wrote:

>

On Wednesday, 14 August 2024 at 13:26:44 UTC, IchorDev wrote:

>

Wow you have some… strange problems.

If you've never made such silly programming mistakes, enjoy it while it lasts!

Thanks. I’m surprised my knackered brain still manages not to make such mistakes if they’re so common.

> >

let’s just add such a mechanism for all of the other situations that might trip up a beginner:

Interesting list. Some of them have been seriously suggested for D or implemented in other languages. Specifically, D's integer promotion rules get criticized a lot, and some languages are a lot stricter about it.

Yes and I’m sure people have suggested requiring parenthesis after mutability attributes. The only one of those things I seriously want is requiring an explicit cast before dereferencing null; but it would require the compiler to literally be magical since it needs to be a compile-time feature obviously, but it depends on a runtime value.

>

I do agree with you generally: just because a combination of features is commonly used mistakenly, doesn't mean a special case should be added disallowing the combination.

However, there are cases where the ratio of erroneous usage / intentional usage is so large, that a compiler error will in practice reduce the total amount of 'programmer rage' so to speak.

I feel like integer promotion is a much more pressing issue in that department. It’s one of the few things I wish we’d just bin because it’s so atrocious. And personally I’ve been screwed over by arithmetic operator precedence on many occasions.

>

You apparently have seen intentional use [of !a == b], so it makes sense you judge it as not worth adding an error for. I'm actually curious, can you link to real code using that pattern intentionally?

I don’t think I said that? I might’ve written something like that a long time ago in another language. I don’t usually read other people’s code for fun, but it’s the kind of thing I can see myself writing, although probably as x == !y because it looks nicer. Also C code often uses int for booleans, so code that interfaces with C could trigger this mechanism even if we add an exception for bool.

August 14

On Wednesday, 14 August 2024 at 15:04:13 UTC, IchorDev wrote:

>

I feel like integer promotion is a much more pressing issue in that department. It’s one of the few things I wish we’d just bin because it’s so atrocious.

Oh, I thought the list represented things you didn't want to see in the language. But your point is rather that D is not consistent about this kind of error prevention?

>

And personally I’ve been screwed over by arithmetic operator precedence on many occasions.

Same, which is why I often defensively parenthesize expressions with binary operators.

>

I don’t think I said that?

My bad, I thought your !myInt == myBool example was based on something you wrote in the past.

August 14

On Wednesday, 14 August 2024 at 15:41:13 UTC, Dennis wrote:

>

On Wednesday, 14 August 2024 at 15:04:13 UTC, IchorDev wrote:

>

I feel like integer promotion is a much more pressing issue in that department. It’s one of the few things I wish we’d just bin because it’s so atrocious.

Oh, I thought the list represented things you didn't want to see in the language. But your point is rather that D is not consistent about this kind of error prevention?

What? No, I literally said that the only thing in that list that I’d want in the language is the null cast thing, which is impossible to do. I also stated separately that in an ideal world we’d completely remove integer promotion. In the list, the idea was that the compiler would force you to manually write a cast whenever and wherever the compiler decides to promote an integer, which would be an abomination:

short x = 1, y = 2;
int z = x + y; //warning: integer promotion must be explicit
int w = cast(int)x + cast(int)y;
int ohNo = cast(int)x * cast(int)x + cast(int)y * cast(int)y + z*z + w*w;
> >

And personally I’ve been screwed over by arithmetic operator precedence on many occasions.

Same, which is why I often defensively parenthesize expressions with binary operators.

I do that less and less. I think that learning the precedence and omitting the parenthesis makes the code a lot easier to sight-read. The tipping point for me is about 3 nested parenthesis, after which they all start to blur together.

August 14

On Wednesday, 14 August 2024 at 14:48:42 UTC, user1234 wrote:

>

Well, just wanna say that this is an easy check to implement in Dscanner. That does not require any context. Just match the pattern in the AST and issue a warning.

Sounds like a better idea to do that. I’m not a fan of having more ‘it’s unintuitive therefore we’ll force the code to be unreadable’ features like bitwise operators requiring parenthesisation.

August 14
On Wednesday, 14 August 2024 at 14:48:42 UTC, user1234 wrote:
> Well, just wanna say that this is an easy check to implement in Dscanner. That does not require any context. Just match the pattern in the AST and issue a warning.

That would error on `!bool == bool`, which is fine.