Bug 7432 – DMD allows variables to be declared as pure
Status
RESOLVED
Resolution
WONTFIX
Severity
normal
Priority
P3
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2012-02-03T14:58:27Z
Last change time
2023-03-11T20:12:37Z
Keywords
accepts-invalid, pull
Assigned to
No Owner
Creator
Jonathan M Davis
Comments
Comment #0 by issues.dlang — 2012-02-03T14:58:27Z
This compiles:
void main()
{
pure foo = "hello";
}
It should be illegal. Variables can't be pure. Even worse, pure here is treated as if it were auto.
Comment #1 by smjg — 2012-02-12T11:42:21Z
It isn't pure that is treated as auto. What's treated as auto is the presence of any attribute (to turn it from an ExpressionStatement into a DeclarationStatement) combined with the absence of a type. But otherwise yes.
Comment #2 by andrej.mitrovich — 2012-10-26T17:22:02Z
The problem is there can be a pure block such as this one in object.di:
class TypeInfo_Struct : TypeInfo
{
@safe pure nothrow
{
uint function(in void*) xtoHash;
bool function(in void*, in void*) xopEquals;
int function(in void*, in void*) xopCmp;
string function(in void*) xtoString;
uint m_flags; // << problem
}
}
I don't know whether the front-end makes any difference between declarations in attribute blocks and those who have a direct attribute in one statement. If not, it's probably not fixable without breaking code.
Comment #3 by bearophile_hugs — 2012-10-26T17:42:12Z
(In reply to comment #2)
> I don't know whether the front-end makes any difference between declarations in
> attribute blocks and those who have a direct attribute in one statement. If
> not, it's probably not fixable without breaking code.
Moving the variable out of that block should be harmless :-) Automatic testing is there for similar purposes.
Comment #4 by andrej.mitrovich — 2012-10-26T17:43:00Z
(In reply to comment #3)
> (In reply to comment #2)
>
> > I don't know whether the front-end makes any difference between declarations in
> > attribute blocks and those who have a direct attribute in one statement. If
> > not, it's probably not fixable without breaking code.
>
> Moving the variable out of that block should be harmless :-) Automatic testing
> is there for similar purposes.
Yes but there's no telling how much more code it would break.
Comment #5 by smjg — 2012-10-27T08:56:07Z
(In reply to comment #2)
> The problem is there can be a pure block such as this one in object.di:
<snip>
> I don't know whether the front-end makes any difference between
> declarations in attribute blocks and those who have a direct
> attribute in one statement. If not, it's probably not fixable
> without breaking code.
Of course it's fixable - by changing it so that the front-end does make this difference. See the long-debated issue 3118.
Comment #6 by maxim — 2013-08-17T10:44:23Z
This is a feature of D - in general case any attribute is legal (except those for which there are arbitrary checks and rejections) and auto can be replaced by other attributes to launch type inference. Since pure is harmless here I think this is resolved-wontfix.
Comment #7 by temtaime — 2013-08-17T12:36:11Z
Pure variables it's strange.
D is young lang so i think it's welcome to fix the bugs and change behavior even with breaking the code.
Comment #8 by smjg — 2013-08-18T09:24:53Z
(In reply to comment #6)
> This is a feature of D
According to which bit of the spec?
> - in general case any attribute is legal (except those for which
> there are arbitrary checks and rejections) and auto can be replaced
> by other attributes to launch type inference. Since pure is
> harmless here I think this is resolved-wontfix.
Maybe, but it doesn't seem to me to make much sense. If it's intended behaviour, this needs to be stated in the spec.
Comment #9 by maxim — 2013-08-18T09:35:09Z
(In reply to comment #8)
> (In reply to comment #6)
> > This is a feature of D
>
> According to which bit of the spec?
>
> > - in general case any attribute is legal (except those for which
> > there are arbitrary checks and rejections) and auto can be replaced
> > by other attributes to launch type inference. Since pure is
> > harmless here I think this is resolved-wontfix.
>
> Maybe, but it doesn't seem to me to make much sense. If it's intended
> behaviour, this needs to be stated in the spec.
Decl:
StorageClasses Decl
StorageClasses:
StorageClass
StorageClass StorageClasses
StorageClass:
abstract
auto
TypeCtor
deprecated
enum
extern
final
nothrow
override
pure
__gshared
Property
scope
static
synchronized
from Declaration page.
Am not telling that pure variables make much sense (I tried to clarity relation between auto and type inference), the problem is follows:
1) pure int foo; is legal by spec and grammar
2) Despite of 1) dmd arbitrary rejects some wired combinations, sometimes not.
3) There are other issues in Bugzilla like "storage class X is accepted in context Y" (but don't ask which numbers, I don't remember them now). So, situation is totally sporadic right now and it needs comprehensive solution. Adding one check to ban pure in variable declaration is not a solution to the problem.
Comment #10 by smjg — 2013-08-18T13:54:30Z
Yes, that was the essence of bug 3118. It seems Walter wontfix'd it because he feels each attribute needs to be considered individually.
The only explanation of pure that I've managed to find in the specs relates to functions.
http://dlang.org/function.html#pure-functions
In the absence of any explanation of what pure means applied to variables, I can only be assumed that pure cannot be applied to variables, and therefore any attempt to apply pure to a variable is supposed to fail with a compile error.
Comment #11 by issues.dlang — 2013-08-18T14:14:17Z
> In the absence of any explanation of what pure means applied to variables, I
> can only be assumed that pure cannot be applied to variables, and therefore
> any attempt to apply pure to a variable is supposed to fail with a compile
> error.
Except that in most cases, an invalid attribute doesn't result in a compilation error - it's ignored. The argument for this is generally that it helps generic code, and it makes it easier to do stuff like
attribute:
...
or
attribute
{
}
without caring about the items that it doesn't apply to. For instance, you can do that with attributes like @safe or @trusted, which have zero effect on variables and yet have lots of variables declared in that code. The same goes for pure.
I don't know what the best way to handle this is given that sometimes it is useful to have an attribute ignored when it doesn't apply, but it also can be quite misleading, and the case where a symbol is explicitly marked with an attribute and then that attribute is ignored is particularly bad. Maybe we could petition for that particular case to always be an error (which would cover this bug), but I don't see it changing for attribute: or attribute {}. I don't see a good argument for
pure foo = "hello";
being legal though unless the argument is that all invalid attributes are ignored (which is not the case).
Comment #12 by smjg — 2013-08-18T17:00:48Z
(In reply to comment #11)
>> In the absence of any explanation of what pure means applied to
>> variables, I can only be assumed that pure cannot be applied to
>> variables, and therefore any attempt to apply pure to a variable
>> is supposed to fail with a compile error.
>
> Except that in most cases, an invalid attribute doesn't result in a
> compilation error - it's ignored.
You're talking about what the compiler actually does, which is a different matter from what the spec indicates it should do.
> The argument for this is generally that it helps generic code, and
> it makes it easier to do stuff like
>
> attribute:
> ...
>
> or
>
> attribute
> {
> }
>
> without caring about the items that it doesn't apply to.
You mean it's easier to implement if (a), (b) and (c) in the description of bug 3118 are *always* either all legal or all illegal? To me there doesn't seem to be much in it.
> For instance, you can do that with attributes like @safe or
> @trusted, which have zero effect on variables and yet have lots of
> variables declared in that code. The same goes for pure.
Maybe. And you could possibly argue that the criteria for purity are trivially true for variables (since a variable cannot read or write state, or call functions, or override, or perform I/O), but the spec speaks only of pure _functions_.
> I don't see a good argument for
>
> pure foo = "hello";
>
> being legal though unless the argument is that all invalid
> attributes are ignored (which is not the case).
Indeed, the point of pure seems to be to indicate that something is suitable for use within a purely functional programming paradigm. So unless we make pure equivalent to immutable when applied to variables....
Comment #13 by issues.dlang — 2013-08-18T17:17:33Z
> You're talking about what the compiler actually does, which is a different
> matter from what the spec indicates it should do.
Honestly, it really doesn't matter what the spec says. In general, if there's a disagreement between the spec and the compiler, the spec loses. The spec and the compiler should be in agreement, but the fact that the spec says something doesn't necessarily mean much. The spec is generally written after the fact to match the compiler rather than the compiler being written to match the spec. So, yes, the situation there needs to be improved, but complaining that the compiler is wrong because it doesn't match the spec will likely get you nowhere.
> Indeed, the point of pure seems to be to indicate that something is suitable
> for use within a purely functional programming paradigm. So unless we make
> pure equivalent to immutable when applied to variables....
pure makes no sense whatsoever on variables. Neither do @safe, @trusted, or nothrow. The fact that you can at least sometimes marks variables that way is a side effect of the fact that the compiler tends to ignore invalid attributes. I really don't think that we should even consider making it so that any of those make sense on variables. All we should be doing is determining where the compiler should ignore invalid attributes and where it should give an error, and then we need to make sure that both the spec and the compiler agree.
Comment #14 by maxim — 2013-08-18T21:48:57Z
(In reply to comment #10)
> Yes, that was the essence of bug 3118. It seems Walter wontfix'd it because he
> feels each attribute needs to be considered individually.
>
> The only explanation of pure that I've managed to find in the specs relates to
> functions.
> http://dlang.org/function.html#pure-functions
>
> In the absence of any explanation of what pure means applied to variables, I
> can only be assumed that pure cannot be applied to variables, and therefore any
> attempt to apply pure to a variable is supposed to fail with a compile error.
This is not a good way of reasoning.
Also, as described above there are cases like in attribute: or attribute {} where ignoring storage class helps.
Comment #15 by maxim — 2013-08-18T21:52:09Z
(In reply to comment #11)
> > In the absence of any explanation of what pure means applied to variables, I
> > can only be assumed that pure cannot be applied to variables, and therefore
> > any attempt to apply pure to a variable is supposed to fail with a compile
> > error.
>
> Except that in most cases, an invalid attribute doesn't result in a compilation
> error - it's ignored. The argument for this is generally that it helps generic
> code, and it makes it easier to do stuff like
>
> attribute:
> ...
>
> or
>
> attribute
> {
> }
>
> without caring about the items that it doesn't apply to. For instance, you can
> do that with attributes like @safe or @trusted, which have zero effect on
> variables and yet have lots of variables declared in that code. The same goes
> for pure.
>
> I don't know what the best way to handle this is given that sometimes it is
> useful to have an attribute ignored when it doesn't apply, but it also can be
> quite misleading, and the case where a symbol is explicitly marked with an
> attribute and then that attribute is ignored is particularly bad. Maybe we
> could petition for that particular case to always be an error (which would
> cover this bug), but I don't see it changing for attribute: or attribute {}. I
> don't see a good argument for
>
> pure foo = "hello";
>
> being legal though unless the argument is that all invalid attributes are
> ignored (which is not the case).
Perhaps allow to apply storage classes to variables in block declarations like attribute: or attribute { } and ban them in single variable declarations?
Comment #16 by issues.dlang — 2013-08-18T22:59:59Z
> Perhaps allow to apply storage classes to variables in block declarations like
> attribute: or attribute { } and ban them in single variable declarations?
That's basically what I was thinking (though I would want to apply that to all symbols, not just variables). At the moment, I can't think of why that would be a problem (though someone may be able to come up with a reason why it would be).
Comment #17 by smjg — 2013-08-18T23:05:47Z
(In reply to comment #13)
>> You're talking about what the compiler actually does, which is a
>> different matter from what the spec indicates it should do.
>
> Honestly, it really doesn't matter what the spec says. In general,
> if there's a disagreement between the spec and the compiler, the
> spec loses.
What you're basically saying here is that the language is _defined_ by the compiler, and consequently the compiler has no bugs.
So what is the meaning of the word "spec" in your mind?
Comment #18 by issues.dlang — 2013-08-18T23:30:45Z
> What you're basically saying here is that the language is _defined_ by the
> compiler, and consequently the compiler has no bugs.
No, I'm not saying that the compiler has no bugs. If there is a disagreement between the spec, the compiler, or TDPL, then it has to be discussed which is correct, but in general, TDPL wins, then the compiler, and then the spec. Yes, the spec _should_ define what the language is, but it's not that precise or that complete, and the language is still under enough development that the spec has to change from time to time even if it's compeletely correct, and the reality of the matter is that the spec is often incorrect if nothing else because it frequently doesn't get updated properly when language design decisions are made, whereas the compiler almost always does get updated.
It's not like the spec was written, and then a compiler was written to match it. The language has evolved over time, and on the whole, the compiler has defined what the language is, and Walter has defined what the language is supposed to be when questions come up. The spec attempts to define what the language is based on that, but it doesn't always manage it, primarily because it isn't maintained well enough.
Comment #19 by safety0ff.bugz — 2013-10-30T16:23:17Z
*** Issue 11391 has been marked as a duplicate of this issue. ***
Comment #20 by dlang-bot — 2022-06-11T10:57:33Z
@dkorpel created dlang/dmd pull request #14199 "Fix Issue 7432 - DMD allows variables to be declared as pure" fixing this issue:
- Fix Issue 7432 - DMD allows variables to be declared as pure
https://github.com/dlang/dmd/pull/14199
Comment #21 by dkorpel — 2023-03-11T13:40:12Z
I've tried to 'fix' this (see the linked PR), but it turns out function attributes do have a meaning on variable declarations: the function/delegate type inherits them. Existing code relies on this.
If the variable doesn't have such a callable type, applying function attributes could still be made an error, but this isn't straightforward: the type could be determined by a complex template instantiation. Figuring out whether the function attribute did end up affecting anything is:
- complex to specify
- difficult to implement
- hampered by generic code (e.g. when you give a variable either a callable or non-callable type depending on static introspection)
Because of this, I'm closing this as WONTFIX. I suggest Dscanner may catch trivial cases like `pure int x = 0;` if this turns out to be a helpful warning, though I don't think it's a big problem if a variable is accidentally declared `pure`.
Comment #22 by smjg — 2023-03-11T16:54:41Z
I was beginning to think this makes it part of the function type rather than being a declaration attribute. I make out from what you say that, for reasons of parsing convenience, syntactically it's a declaration attribute but the semantic of it thereas is to pass it through so that it becomes part of the function type. Have I got this right?
Comment #23 by dkorpel — 2023-03-11T20:12:37Z
(In reply to Stewart Gordon from comment #22)
> Have I got this right?
Yes