Re: Ugly inconsistence betw. for and for/in
OCsite <[email protected]>
| Newsgroups | gmane.comp.lang.groovy.devel |
|---|---|
| Message-ID | <[email protected]> |
Jochen, thanks for a quick answer! > On 10. 9. 2025, at 0:57, Jochen Theodorou <[email protected]> wrote: > On 07.09.25 15:20, Ondra Cada wrote: > [...] >>> because it would invalidate how local variable scoping works in general: we do no allow shadowing of local variables, every local variable name must be unique! >> Quite. That's another very bad thing which should be fixed to work the way normal languages (which obviously does not include Java[*]) always did. >> Shadowing local variables is a normal and very reasonable thing which worked perfectly and without a glitch from the Pascal up, or perhaps even Algol, I am not quite sure, it's far far ago :) Forbidding it is wrong, for it prevents e.g. copy/pasting small code snippets which just happen to contain an inner variable (most typically something like for (int i...) which just happens to be used in the code into which the snippet goes as well. The developer is then forced to change the old and well-tested code renaming the variable, which for one takes time which can be used much better elsewhere, what's worse, it brings a danger the changes would cause new bugs :( > > but if the scope is lexical, then renaming the variables can be done safe. Well, if the IDE does it by the same rules the language scoping has, then yes; but when done manually through regexp or so, very definitely not. Not all IDEs understand Groovy scoping. Mine (Xcode) does not, for one. > And then suddenly people want to access variables that are hidden. When they do, well, then they would rename (or use another approach). When they do not want that — which is, in my personal experience, a vast majority of cases — there's no need to rename at all if the language does scoping and shadowing properly. > What would be the rules? I would simply use the well-established and decades-tested rules of C (I believe precisely same as Pascal and other languages have). Would there be a problem in some cases which C does not support at all, e.g., closures? Not sure of that, there might be some I did not think of. > make the symbol the new variable till the end of the block and in all of its sub blocks? Just simply till the end of the block. Sub-blocks would see the variable unless they shadow it themselves, of course, but they should be unimportant. > Like for example > > def i = 10 > 10.times {def i=it+i*i; assert i == it+100;} I believe “def i=it+i*i” should not work here. It should lead to the very same result as if you write “def i=i*i” in a code where there's no other i at all. For the inner i is completely independent on the outer one. > assert i == 10 Precisely, this one should work like that. Here we are back to the outer i, which was completely untouched by whatever we did with the inner one. > or like... a declaration of a variable makes it existing from there one: Does not sound reasonable, though of course I can be overlooking something of importance here. [1] > if (true) { > def i = 10 // [2] > } > assert i == 10 In my opinion, this should fail (compile-time for static, runtime for dynamic), since there's no i in this place at all. More precisely, the [2] i does not exist anymore at this place. There might possibly be another i declared at [1]; if so, it will be used here. > if (false) { > def i = 100 > def j = 10 > } > assert i == 10 > assert j == 10 // error Again, neither i nor j exist here, unless declared at [1]. > there are too many possible rules to talk about. I don't really think so. As always, I can be missing something of importance, but it seems to me that the rules are plain, completely intuitive and quite reasonable: (i) a variable can be declared in any lexical scope (almost always it's a { ... } block, be it a function body or a block nested inside of it). About the only exceptions I can think of at this moment are -- function arguments, which belong inside of the function body although declared outside -- declarations inside of the for statement, which belong inside of the for body, although declared outside. I might have forgot something, but I am pretty sure it would not be anything of great importance. (ii) such a variable exists in the whole scope (iii) for self-evident reasons, it is invisible and inaccessible before its declaration (iv) it completely disappears at the end of that scope. Nothing more, nothing less. > Makes no sense if I do not know which set we are talking about now... and yes... Groovy had something like the last one initially.... and it was driving the people mad. If by “the last one” you mean if (foo) { def bar=666 /*1*/ } assert bar==666 // the very same variable of /*1*/ still exists here! then I bet. That's a terrible mess, to leave a variable survive its scope (well unless captured by a closure in that very scope — but then it survives for that closure only, definitely not for the outer scope/s). >> Note also this creates another weird inconsistence — with the default it, Groovy does support shadowing all right; try e.g., >> === >> 2.times { >> println "outer it=$it" >> 666.each { >> println "inner it=$it" >> } >> println "outer it back to $it, as it should!" >> } >> === >> I'ts completely strange and counter-intuitive that soon as I use an explicit declaration (e.g., just { int it ->, to make sure the type's right, without touching the inner code inside of the closure), I'm SOL. > > I agree, it is a bit counter-intuitive, but it is practical. Absolutely. Just the same way shadowing all the other variables would be practical, if available :) > I would not say Groovy has a better design than Java. Groovy has different design goals than Java. Perhaps, but in my personal POV Groovy primarily just fixes most of the Java terrible howlers. Not worth to pursue this, I'd say :) Thanks and all the best, OC