Bug 7724 – 'final:' causes error if any variable declarations are placed between it and the end of its scope
Status
RESOLVED
Resolution
DUPLICATE
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2012-03-18T05:55:00Z
Last change time
2013-02-04T14:06:55Z
Keywords
spec
Assigned to
nobody
Creator
turkeyman
Comments
Comment #0 by turkeyman — 2012-03-18T05:55:52Z
Placing 'final:' at the top of a class produces many of these:
Error: variable demu.memmap.MemoryRange.name final cannot be applied to variable
Comment #1 by bearophile_hugs — 2012-03-18T05:57:58Z
It seems it's working too much :-)
Comment #2 by lovelydear — 2012-04-21T07:01:54Z
Where is it said in the spec that this should be possible ?
Comment #3 by turkeyman — 2012-04-21T07:06:33Z
(In reply to comment #2)
> Where is it said in the spec that this should be possible ?
As I've been lead to believe, final shouldn't be applicable to data members.
Apparently the reason you can't use 'final:' (because it complains when it encounters a variable) is a remnant of D1.
Comment #4 by dejan.lekic — 2012-04-21T07:30:33Z
This is not a bug - you can't use final with variables.
Examine following D2 code:
import std.stdio;
class Issue7724 {
/+--------------------------+
| Uncomment to get "...someValue final cannot be applied to variable" error.
final:
int someValue;
int setValue(int argValue) { someValue = argValue; }
int getValue() { return someValue; }
+--------------------------+/
// Correct:
int someValue;
final:
void setValue(int argValue) { someValue = argValue; }
int getValue() { return someValue; }
}
int main() {
return 0;
}
Comment #5 by smjg — 2012-04-21T08:58:12Z
The debate is one of whether an attribute specified with the colon syntax is meant to apply to _everything_ that follows it until the end of the scope, or only those members to whose entity type it is applicable. When I filed issue 3118, I argued that the latter is reasonable.
Comment #6 by turkeyman — 2012-04-21T09:39:11Z
(In reply to comment #4)
> This is not a bug - you can't use final with variables.
>
> Examine following D2 code:
>
> import std.stdio;
>
> class Issue7724 {
> /+--------------------------+
> | Uncomment to get "...someValue final cannot be applied to variable" error.
> final:
> int someValue;
> int setValue(int argValue) { someValue = argValue; }
> int getValue() { return someValue; }
> +--------------------------+/
>
> // Correct:
> int someValue;
> final:
> void setValue(int argValue) { someValue = argValue; }
> int getValue() { return someValue; }
> }
>
> int main() {
> return 0;
> }
It's inconsistent to allow superfluous instance of some attributes, but not others.
static int x; at global scope is silently ignored.
final applied to data members should be equally ignored, but rather, attributes with colon probably just shouldn't be applied to things that they're not applicable to. Otherwise you'll end up with all sorts of class organisation mess when you consider a few attributes together.
I'm not into the idea that the language should insist I break my class up according to arbitrary attributes, rather than keeping related things together, which I find far preferable.
Also, declaring 'final:' at some arbitrary point in a class is hard to spot, and error prone (it might be missing). If it's the first thing in a class (like 'public:' often is in C++), then it's very easy to spot and validate.
Comment #7 by dejan.lekic — 2012-04-21T10:28:29Z
@Manu:
I see your point.
However, I disagree - one should learn the language, and understand where and how "final:" can be used. I have no problems with the current situation.
Compiler also generates a helpful error message that can be understood by anyone. I personally never use public: final: private: etc... I prefer public{}, private{}, etc. or use these per-declaration.
@Stewart Gordon
Neither are good - the second approach makes it possible to easily make a mistake if developer is not pedantic enough. Say a class has buch of various methods - and in the middle of it developer decides to add a variable... I know - bad programming practice but still possible... However, developers typically group variables and methods, so I guess it is OK.
As I said, I like the current approach when compiler generates a descriptive error.
Comment #8 by turkeyman — 2012-04-21T11:30:09Z
(In reply to comment #7)
> @Manu:
> I see your point.
> However, I disagree - one should learn the language, and understand where and
> how "final:" can be used. I have no problems with the current situation.
> Compiler also generates a helpful error message that can be understood by
> anyone. I personally never use public: final: private: etc... I prefer
> public{}, private{}, etc. or use these per-declaration.
I think it's safe to say that the preference of keeping associated stuff together is nothing to do with learning the language or not. This is culture, taste, and company standards.
I need to reiterate the consistency issue. Other superfluous attributes appear to be silently ignored where they are not applicable. __gshared makes no sense on a function, but it doesn't complain, as is static, shared, immutable, etc. It's only final that complains, and that's very annoying, because it's the only one I'm passionately insistent about.
I'd like to think it should be fixed to be consistent with all the others for consistency's sake alone. Making me happy would be a nice side effect :)
From a subjective point of view, I don't like the introduction of an extra indentation level by attribute{}, and why supply 2 ways if not to support user preference?
I'd prefer the language forcefully dictate how I arrange my code as little as possible. 95% of functions are final, and as such, for us, it should always be within the first couple of lines in the class.
It would be a company policy that it were the first line in every class if I could explicitly state virtual. However as is now, we ideally declare 1-2 virtuals, then final:, and then everything else, with the class laid out however is most naturally readable, and logical to follow.
Comment #9 by lovelydear — 2012-04-21T12:21:57Z
I'm not fond of the C++ syntax either. But it's a matter of taste, I guess.
Either way, unless you can point it in the spec, I think this issue should be reduced from "critical" to "enhancement".
Comment #10 by turkeyman — 2012-04-21T12:30:41Z
(In reply to comment #9)
> I'm not fond of the C++ syntax either. But it's a matter of taste, I guess.
>
> Either way, unless you can point it in the spec, I think this issue should be
> reduced from "critical" to "enhancement".
It's clearly a bug. All other attributes work as expected. This is the odd one out.
Comment #11 by b.helyer — 2012-04-21T12:34:19Z
Seeing as DMD ignores most no-op attributes, I have no idea why this is the one where it suddenly decides that it should generate an error. I think final on variables should just be ignored, in keeping with other attributes.
Comment #12 by smjg — 2012-04-21T16:38:03Z
(In reply to comment #8)
> I need to reiterate the consistency issue. Other superfluous
> attributes appear to be silently ignored where they are not
> applicable. __gshared makes no sense on a function, but it doesn't
> complain, as is static, shared, immutable, etc.
By "superfluous", do you mean "redundant" or "not making sense in the context"? This is an important distinction to consider.
(In reply to comment #10)
> It's clearly a bug. All other attributes work as expected.
Not sure what you mean by that....
(In reply to comment #11)
> Seeing as DMD ignores most no-op attributes, I have no idea why
> this is the one where it suddenly decides that it should generate
> an error. I think final on variables should just be ignored, in
> keeping with other attributes.
What particular "other attributes" are you talking about?
Thinking about it now, variables can't be overridden, and so essentially are already final. Banning them from being declared final might be considered silly on this basis. So final on member variables is redundant, as opposed to (for example) __gshared on functions which doesn't make sense.
Comment #13 by turkeyman — 2012-04-22T04:02:16Z
(In reply to comment #12)
> (In reply to comment #8)
> > I need to reiterate the consistency issue. Other superfluous
> > attributes appear to be silently ignored where they are not
> > applicable. __gshared makes no sense on a function, but it doesn't
> > complain, as is static, shared, immutable, etc.
>
> By "superfluous", do you mean "redundant" or "not making sense in the context"?
> This is an important distinction to consider.
Both are true for other attributes. __gshared makes no sense applied to a function, static applied at the global scope however is at least redundant, maybe both.
I think it depends how you look at it. The colon syntax isn't really an explicit application of an attribute to everything that follows (at least, it doesn't seem to be that way for all other attributes at this time). The policy already seems to be be defined as applying the attribute only those items it is applicable to, the only exclusion at this time seems to be final.
> (In reply to comment #10)
> > It's clearly a bug. All other attributes work as expected.
>
> Not sure what you mean by that....
'__gshared:' doesn't cause errors, neither does 'immutable:', or any others I tried. They all have cases where they are not applicable, but they are silently ignored, as final should be.
> (In reply to comment #11)
> > Seeing as DMD ignores most no-op attributes, I have no idea why
> > this is the one where it suddenly decides that it should generate
> > an error. I think final on variables should just be ignored, in
> > keeping with other attributes.
>
> What particular "other attributes" are you talking about?
shared, __gshared, immutable at least.
> Thinking about it now, variables can't be overridden, and so essentially are
> already final. Banning them from being declared final might be considered
> silly on this basis. So final on member variables is redundant,
Excellent point :)
Comment #14 by smjg — 2012-04-23T02:05:59Z
(In reply to comment #13)
> I think it depends how you look at it. The colon syntax isn't
> really an explicit application of an attribute to everything that
> follows (at least, it doesn't seem to be that way for all other
> attributes at this time).
That's indeed the point I was making in comment 5.
> The policy already seems to be be defined as applying the attribute
> only those items it is applicable to, the only exclusion at this
> time seems to be final.
But it's generally doing this with all ways of applying an attribute, not just the colon syntax.
>>> It's clearly a bug. All other attributes work as expected.
>>
>> Not sure what you mean by that....
>
> '__gshared:' doesn't cause errors, neither does 'immutable:', or
> any others I tried. They all have cases where they are not
> applicable, but they are silently ignored, as final should be.
So in your mind, if the compiler just ignored an ExpressionStatement that is a call to an undefined function (skipped over it without generating any code), this would constitute the call working? :)
Comment #15 by bugzilla — 2012-04-24T11:53:49Z
The compiler behavior here is obviously deliberate, so this isn't a bug but an enhancement request.
'final' in Java for a variable means it is assigned once in the constructor, and never again. The equivalent is achieved in D using 'const' and not supplying an initializer.
'final' in D1 has similar semantics to Java.
The reason 'final' applied to fields in D2 is an error is so that the user transferring code from D1 to D2 will be notified of changes required, rather than silently breaking his code.
Silently breaking code is very, very bad. There are still a lot of D users who are moving from D1 to D2, and while that's going on I don't think implementing this is a good idea.
Comment #16 by turkeyman — 2012-04-24T13:36:22Z
(In reply to comment #15)
> Silently breaking code is very, very bad. There are still a lot of D users who
> are moving from D1 to D2, and while that's going on I don't think implementing
> this is a good idea.
Fair enough. Are there other instances of treatment of this sort?
Perhaps a compiler switch that enables warnings for D1->D2 porting, similar to how many x32 compilers make noise about 64bit portability issues?
Comment #17 by smjg — 2012-04-24T13:51:22Z
(In reply to comment #15)
> 'final' in Java for a variable means it is assigned once in the constructor,
> and never again. The equivalent is achieved in D using 'const' and not
> supplying an initializer.
>
> 'final' in D1 has similar semantics to Java.
I can't see it anywhere in the D1 docs as anything other than an attribute applied to methods to prevent them being overridden. I had made out that Java's meaning of final on fields just didn't exist in D, what with D having const for things like that.
Moreover, given that "final" was overloaded to denote two very different attributes, it would seem silly that a single use of the word could apply both these attributes. But if people actually did it....
Comment #18 by andrej.mitrovich — 2013-02-04T14:06:55Z
*** This issue has been marked as a duplicate of issue 7071 ***