Discussion on using module-scoped variables (was 'with' bug?)
Chris Cain
clcain at uncg.edu
Mon Nov 5 22:46:01 PST 2012
On Monday, 5 November 2012 at 08:37:49 UTC, Faux Amis wrote:
> Ok, good to see that you are replying to incorrectly scoped
> variables, but this is not the point I am trying to make. I
> know you should always keep the scope as small as possible.
Eh? I'm confused. The second half of my post certainly was a bit
of a rant on incorrectly scoped variables (which is related to
the discussion, but it was my response to bearophile), but the
first part of my post is supporting the viewpoint that you should
avoid using module-scoped variables (and even static struct
member variables) and suggesting an alternative.
> Can you think of a setting in which we have legitimate private
> struct members? If so, then add to this setting that you only
> want one instantiation of the data in this struct. As a
> solution, what is wrong with dropping the struct encapsulation?
> There is no other code except the struct in the module.
>
> I sincerely want to know if there is any difference. As I
> understand it the scope is exactly the same or even smaller as
> you can't leak instances of modules as you can structs.
From my understanding, you're trying to get a specific viewpoint
on this idea?
> From a good-coding standpoint, do you think there is a
> difference between these two options?
>
> --
> module a;
>
> int a;
> --
> module b;
>
> struct S{//otherwise unused wrapper
> static int b;
> }
> --
I think the first option is "better" than the second. The second
seems to be a misuse of struct to me. I can't see why you'd use a
struct in the second option.
That said, they're effectively equivalent pieces of code. That
is, they're both static data that is a shared resource among all
functions that have access to them. And, thus, they're both
"equally bad" in terms of how they will affect the
understandability and testability of the code. It's possible that
it would cause the code to have more bugs in it than it would
otherwise.
That is, both of them are not as good of choices as this:
---
void good(ref int b) pure {
// code using/setting b
}
void good2(int b) pure {
// code using b, but not setting it
}
// No b in module scope or statically allocated
// Sometimes a better idea, depending on circumstances:
int better(int b) pure {
// code using b, and putting changes into changedB
return changedB;
}
// example uses:
void main() {
int a = 1, b = 2, c = 3;
good(a);
good2(b);
c = better(c);
}
---
Because this creates code that is honest about its dependencies
and allows for the overall state of the program to be consistent
between runs of functions. This is essential for testability, but
it's also important for a programmer to reason about the behavior
of their code.
Of course, I'm sure you can give examples of code that couldn't
be written like that, and that's okay. I'm only arguing that you
should avoid static data when it's realistic to do so, not that
it will open a black hole in your living room if you use it under
any circumstances :-). Though if you're using it as your "primary
data encapsulation," I have to wonder whether you're using it in
instances it could have been avoided.
More information about the Digitalmars-d
mailing list