Post by bartcPost by David BrownPost by bartcWhy this obsession with these tiny scopes?
The obsession is with clear and easily understood code. If a variable
has a small scope, it is easy to see where it starts, what it does, and
where it ends.
It would have to be an extremely small scope for that. With real uses of
such block scopes (eg. see the pastebin examples I posted recently), the
code is chaotic, and finding the boundaries of a variable's scope is
harder. Not helped by using the same name for two instances of the
variable within a function.
The code you showed is an absolute mess. It may have come from a
popular open source project, but it is still a total disaster for
readability and maintainability. The second link, with smaller scopes
for variables, is marginally less bad - but it too has massive numbers
of variables declared in all the wrong places.
The standard since the dawn of time has been that if a function is too
big to fit comfortably in a screen on your editor, then it is probably
too big.
Now, in some code long functions can make sense. Typically that would
be a function where you simply have a long list of things to do, and the
use of parameters and/or some common local variables means it is easier
to have the bits sequentially in one function rather than splitting it
up and passing lots of data between the sub-functions. In such cases,
local variables with small block scopes is a massive win for readability.
And for more normal-sized functions, well, small block scopes are also a
massive win for readability.
Post by bartcWhereas with my variables, you /know/ they have function scope.
(To save others the effort - only labels can have "function scope" in C.
You mean they have block scope in the outer block of the function.)
Post by bartcYou
/know/ there is at most one of each. And if functions are kept small as
you yourself suggest, then that is not a problem.
Yes, and you /know/ their definitions are separate from their uses so
that you don't know how they will be used when you define them, and you
don't know how their are defined when you use them. You /know/ you have
to jump back and forth in your editor when trying to find them or add
new variables, rather than seeing them a line or two away from where you
are. You /know/ that you are going to see a variable with a meaningless
name like "temp" used repeatedly for different purposes. You /know/
there are going to be left-overs as code changes, where the use of a
variable has been removed but its declaration is still there.
You know lots of things when you write functions that way.
Post by bartcWriting large functions with big collections of variable
Post by David Browndefinitions at the start means you are jumping all over the function to
see what it does, or while writing it. It is even worse when your
language allows you to put the definition later on, after the variable
has been in use (as your language does, AFAIUI).
That is invaluable when you are adding a function. You don't need to
worry about whether references to the function are before or after the
place where you're going to put it, or both, and whether a forward
declaration is needed.
I don't worry - I just define my functions before I use them. Some
people prefer to declare their functions so that they can define them in
different orders - that works too, and I don't imagine they worry too
much either.
That said, I would not object to C being able to accept function
definitions within a translation unit in any order, without having
forward declarations. It would be fine for structs and unions too. But
allowing variables to be used before defining or declaring them is
asking for trouble, IMHO.
Post by bartcWithin functions, out-of-order declarations are unusual for normal code
(sometimes used for temporary or test code).
Post by David Brownint a = 1;
if (a == 1) {
int a = 2; // New a
foo(a); // a == 2 here
int b = 3; // Local b
// The scope for the new a (a == 2) ends here
int a = 4; // Yet another new a
A dangerous feature I think. Currently it's an error to redeclare a name
twice within a block. You're proposing to do away with that check.
Yes, it is a new feature that I am proposing. It is not "doing away
with a check" - it is a new feature. Making a new definition with the
same name as an existing identifier is not doing away with a check, but
specifically ending the scope of the old identifier in this case. (That
makes it a little different from the translation into extra blocks.)
There are details to work out and specify in how this works - it could
be an issue if a reference to a variable is taken earlier on and that
variable is then replaced by a new one of the same name. Should the
lifetime of the old one carry on to the end of the block, or should it
stop at the declaration of the new one?
Post by bartcI assume that the second 'a' can have a different type from the first.
Yes. (An alternative proposal would be to simply make the second
declaration redundant, and not introduce a new variable, but obviously
the type would have to be the same.)
Post by bartcBut is the a==2 version still accessible, within the scope of a==4,
through a pointer for example? (In your equivalent version below, it is.)
In the conversion below, it is still alive even though its scope is
hidden. I am in two minds about whether or not it should be that way,
or whether it should "die" when the new one takes effect. For C, there
is little disadvantage in letting it remain alive - if you don't access
it via a pointer, the compiler can see that it is dead and re-use the
space. For C++, it is a bit different - there is the question of when
the destructor is run. So this is a question that would have to be
considered and defined carefully.
Post by bartcIf not then I can't see the advantage of this over just writing 'a=4'
instead of 'int a=4'. Or is this part of some campaign where you are
only allowed to assign to a variable once, or can only initialise it at
declaration (effectively doing away with assignment)?
Different types would be allowed. Redefinition with the same type would
be mostly for convenience when moving code sections around or copying them.
Post by bartcPost by David Brownbar(a, b); // a == 4, b == 3
}
foobar(a); // Back to the old a == 1
int a = 1;
if (a == 1) {
int a; // New a
a = 2; // The new a
foo(a); // a == 2 here
{
int b; // Local b
b = 3;
{
int a; // Yet another new a
a = 4; // The YAN a
bar(a, b); // a == 4, b == 3
} // end of scope for YAN a
} // end of scope for b
} // end of scope for "new" a
foobar(a); // Back to the old a == 1
Is that clear enough?
I can see it. But I'm struggling to see the benefit.
I can appreciate the advantages of more controlled scope on a larger
scale. If modules A and B want to share functions and variables, for
example, then those names will be accessible to C, D and E as well.
That is a different matter entirely - and I agree that it would be nice
to have a solution to that. Namespaces (from C++) go some way to
solving that problem, and I see no reason why C could not copy that
feature from C++.
Post by bartcWith some languages (a couple of mine for example), those names can be
kept private between A and B or least they will not clash with anything
exported by C or D.
But with your in-function examples, especially in real code with longer
names and more elaborate expressions, you're always going to be trying
to see what name is what.
No, you would not.
If you actually tried working in a "small variable scope" manner, I
believe you would see its advantages. My proposal here just makes it a
little nicer.