Bug 12931 – Make const, immutable, inout, and shared illegal as function attributes on the left-hand side of a function
Status
RESOLVED
Resolution
WONTFIX
Severity
enhancement
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2014-06-16T09:20:26Z
Last change time
2020-02-17T07:22:51Z
Keywords
pull
Assigned to
No Owner
Creator
Jonathan M Davis
Comments
Comment #0 by issues.dlang — 2014-06-16T09:20:26Z
Can we _please_, _please_ make it illegal to put any function attribute which could also modify the return type on the left-hand side of the function? e.g.
const Bar foo() {...}
is currently legal and is equivalent to
Bar foo() const {...}
_Everyone_ makes the mistake of thinking that
const Bar foo() {...}
is equivalent to
const(Bar) foo() {...}
The result of this is not only confusion for newbies, but it also means that it's bad pratice to put const, immutable, or inout on the left-hand side of a function, because if you do
const Bar foo() {...}
then it immediately raises the question as to whether programmer who wrote it intended for const to modify the function or the return type.
The reason that's usually given as to why const is legal on the left-hand side is because all function attributes can go on either side of the function, and it would be inconsistent to disallow const, immutable, or inout on the left. But that's not even true! As issue# 12930 shows, static, private, public, package, and protected are all illegal on the left. It's only @property, @safe, @trusted, @nogc, pure, nothrow, const, immutable, and inout which can go on both sides. So, we're allowing const, immutable, and inout to be on the left-hand side in the name of consistency, when we're not even consistent! So, we're allowing them on the left to no real benefit. It's already considered bad practice to put them on the left-hand side, and it would reduce bugs and confusion if we disallowed it. And the fact that
const Bar foo() {...}
doesn't return a const(Bar) is inconsistent with variable declarations (where the parens are optional), so we're claiming to be consistent with function attributes when we're not and are specifically being inconsistent with variable declarations in a way that constantly confuses people. Heck, Robert Schadeck, who spoke at dconf 2013 and who's working on std.log got this wrong in a stack overflow question on this very topic!
http://stackoverflow.com/questions/24239156/const-member-fuction-vs-const-return-type/24239520#24239520
If our major contributors can't get this right, how do we expect normal D programmers to get it right?
So, I propose that we disallow const, immutable, and inout on the left-hand side of a function unless they use parens to explicitly modify the return type. So,
const(Bar) foo() {...}
would continue to be legal, and
const Bar foo() {...}
would become illegal (after the proper deprecation cycle of course). The only code that this would break would be code that's already breaking with what's considered good practice, because it's always going to be questioned as to whether the programmer who wrote it intended to modify the return type or the function. It would be nice to make it so that
const Bar foo() {...}
were then the same as
const(Bar) foo() {...}
but we obviously can't do that immediately, as that would change the semantics of the code (and potentially in a silent way, though usually, it would be quite loud). Maybe we could do so in the future, but the most important thing IMHO is to stop allowing it on the left as a function attribute, because that's too confusing and bug-prone.
I know that Walter doesn't agree with this (or at least hasn't in the past), but we really need to find a way to convince him to change this (or to allow other compiler devs to change it). The current behavior is just causing us problems.
Comment #1 by bearophile_hugs — 2014-06-16T09:33:16Z
I think there is already a closed issue on this topic. So perhaps it's better to reopen it instead of opening a dupe.
(In reply to Jonathan M Davis from comment #0)
> I know that Walter doesn't agree with this (or at least hasn't in the past),
Walter changes his mind when the evidence and need are strong.
Comment #2 by jcrapuchettes — 2014-06-18T17:08:43Z
I'm in agreement. It would be really nice to have this disallowed for the sake of new people coming to the language. It can be very confusing.
Comment #3 by k.hara.pg — 2014-06-24T02:29:50Z
(In reply to Jonathan M Davis from comment #0)
> Can we _please_, _please_ make it illegal to put any function attribute
> which could also modify the return type on the left-hand side of the
> function?
I think it would be nice improvement.
> It would be nice to make it so that
>
> const Bar foo() {...}
>
> were then the same as
>
> const(Bar) foo() {...}
There was a discussion in issue 10150 about it.
Comment #4 by schveiguy — 2014-06-24T03:35:10Z
(In reply to Jonathan M Davis from comment #0)
> The reason that's usually given as to why const is legal on the left-hand
> side is because all function attributes can go on either side of the
> function, and it would be inconsistent to disallow const, immutable, or
> inout on the left. But that's not even true! As issue# 12930 shows, static,
> private, public, package, and protected are all illegal on the left.
You mean "illegal on the *right*"
Some questions:
these are currently also legal and equivalent to your example:
const: Bar foo() {...}
const{ Bar foo() {...} }
Those OK or not? I'd say yes, because the only really confusing one is where the const seems to apply to Bar. In those cases, const looks more like a class-level attribute, and don't appear to apply to the return type.
Come to think of it, this is also not ambiguous:
const void foo() {...}
But I think this should also be disallowed for consistency
Also, shared is in this category, as it is a type constructor.
9 votes in 7 days, must be some sort of record :) I'll add mine shortly. I would guess that there would be zero
Comment #5 by schveiguy — 2014-06-24T03:36:40Z
(In reply to Steven Schveighoffer from comment #4)
> 9 votes in 7 days, must be some sort of record :)
Hah, I didn't realize we can now vote more than once for an issue. Really Jonathan, 9 votes?
Comment #6 by issues.dlang — 2014-06-24T04:05:18Z
> You mean "illegal on the *right*"
Yeah, sorry.
> these are currently also legal and equivalent to your example:
> const: Bar foo() {...}
> const{ Bar foo() {...} }
> Those OK or not?
I'd say yes. What needs to be illegal are ambiguous cases. There's no way that const: or const{} could refer to the return type.
> Come to think of it, this is also not ambiguous:
> const void foo() {...}
> But I think this should also be disallowed for consistency
Agreed. Even if it's clear to the compiler, it's just bizarre to the programmer. Also, if we can ever get to the point that const without parens on left applies to the return type rather than the function, then allowing const void would definitely be bad.
> Also, shared is in this category, as it is a type constructor.
Yeah. Any attribute which could affect the return type should be illegal no the left.
> Hah, I didn't realize we can now vote more than once for an issue. Really
> Jonathan, 9 votes?
LOL. Well, that's how many votes I had, and I was really ticked about this when I created it, so when I figured out that it would let me put multiple votes on it, I did. The fact that public, private, static, etc. can't go on the right completely goes against the entire argument for why const is allowed on the left, and as soon as I figured that I out, I was pretty mad that we'd ever agreed to let const be on the left. The whole consistency argument is bogus with regards to the current implementation, and I've never thought that the consistency was worth it here anyway. We either need to actually make them all consistent and let them all go on the right or disallow the ones on the left that are ambiguous. I vote strongly for the latter, as it's less bug-prone.
Comment #7 by schveiguy — 2014-06-24T04:09:51Z
(In reply to Jonathan M Davis from comment #6)
> LOL. Well, that's how many votes I had, and I was really ticked about this
> when I created it, so when I figured out that it would let me put multiple
> votes on it, I did.
This is pretty funny, it was the other Jonathan who voted 9 times for this :)
Comment #8 by schveiguy — 2014-06-24T04:15:46Z
(In reply to Jonathan M Davis from comment #6)
> The fact that public, private, static, etc. can't go on
> the right completely goes against the entire argument for why const is
> allowed on the left, and as soon as I figured that I out, I was pretty mad
> that we'd ever agreed to let const be on the left.
BTW, I think this is allowed for historical reasons -- attributes on the right did not exist before a certain version. On the left was the only way early on. I can't remember which version allowed it on the right, but there was a debate about it on the NG.
Comment #9 by issues.dlang — 2014-06-24T04:24:46Z
> This is pretty funny, it was the other Jonathan who voted 9 times for this :)
Then it must be some other issue that I voted multiple times on. I know that I did it for something recently. I _was_ pretty ticked though when I reported this, because I'd just figured out that static, private, etc. couldn't go on the right, which meant that the whole argument that const was allowed on the left for consistency was bogus.
Is this for real ? We are getting rid of the left hand side qualifiers ? Am i dreaming ?
Comment #14 by k.hara.pg — 2014-10-04T05:08:25Z
(In reply to deadalnix from comment #13)
> Is this for real ? We are getting rid of the left hand side qualifiers ? Am
> i dreaming ?
There's no decision yet, but my PR can indicate that it's implementable.
Comment #15 by ketmar — 2014-10-04T05:15:53Z
whom i should kill to make this accepted in mainline? ;-)
Comment #16 by monarchdodra — 2014-10-04T07:36:15Z
(In reply to bearophile_hugs from comment #1)
> Walter changes his mind when the evidence and need are strong.
This issue just keeps and keeps and keeps comming up. New and experienced users just keep getting hit by this issue.
People get had by it all the time.
http://forum.dlang.org/thread/[email protected]#post-llwyuftyblrjphnyenmf:40forum.dlang.org
It's a known trap that's never going to get better. It should be fixed.
Comment #17 by code — 2014-10-15T20:02:12Z
Just had to fix openssl bindings.
https://github.com/MartinNowak/openssl/commit/b3a334b5bcea8afc7a68573d4363891e7e0bc422
Translating
const EVP_CIPHER *EVP_rc4_hmac_md5(void);
to
const EVP_CIPHER *EVP_rc4_hmac_md5();
instead of
const(EVP_CIPHER)* EVP_rc4_hmac_md5();
It's a common mistake during C header translation.
Since 2.066.0 the compiler at least warns that const can only be applied to member functions.
Comment #18 by pro.mathias.lang — 2019-08-11T17:16:02Z
*** Issue 12930 has been marked as a duplicate of this issue. ***
Comment #19 by dlang-bot — 2020-02-03T09:24:10Z
@Geod24 created dlang/phobos pull request #7389 "[Trivial] Issue 12931: Move shared to the RHS" mentioning this issue:
- Issue 12931: Move shared to the RHS
https://github.com/dlang/phobos/pull/7389
Comment #20 by dlang-bot — 2020-02-03T09:28:53Z
@Geod24 created dlang/dmd pull request #10757 "Fix issue 12931: Make ambiguous qualifiers illegal on the LHS of a function" fixing this issue:
- Fix issue 12931: Make ambiguous qualifiers illegal on the LHS of a function
This has been a pain point for many D users for years,
both new and old, as can be seen from the discussions on the issue.
It is however a potentially disruptive deprecation.
Note: The test for issue 5962 in test/runnable/xtest46.d has been
removed as the issue was only present with prefix syntax.
https://github.com/dlang/dmd/pull/10757
Comment #21 by dlang-bot — 2020-02-03T10:19:50Z
dlang/phobos pull request #7389 "[Trivial] Issue 12931: Move shared to the RHS" was merged into master:
- 3140fb9e3aa2b6b6eabc1ce718cc88f8830d36d5 by Geod24:
Issue 12931: Move shared to the RHS
https://github.com/dlang/phobos/pull/7389
Comment #22 by pro.mathias.lang — 2020-02-17T07:22:51Z