From: Grant Edwards on
On 2009-09-28, Jon Kirwan <jonk(a)infinitefactors.org> wrote:

> [First off, I want to make sure no one reading this is conflating the
> idea of 'global' with 'static'. A global definition (in c) is always
> a static definition. But not all static definitions are global.]

The overloading of the 'static' keyword in the C language to
modify lexical scope in one case and lifetime in another was a
huge mistake IMO.

--
Grant


From: Vladimir Vassilevsky on


David Brown wrote:


> This is comp.arch.embedded - a great many of the projects here do not
> grow "large" because they are for small systems. The code is small
> enough that is not a big problem to keep track of modules and their
> interfaces, and that includes global variables. On the other hand, the
> waste of runtime and code space caused by unnecessary accessor functions
> /can/ be significant.

Unfortunately, I've seen quite a few projects which were started as
"small" and then overgrew into "large". It was too late to change the
interfaces, so they ended up duplicating the entire modules by
copy/paste and renaming the global variables by find/replace.
"Code efficiency" is a very common excuse for sloppy practices.


> To take another example, suppose you have a module that collects samples
> from somewhere and puts it in an array dataSamples[]. Should that only
> be accessible through a function "int GetDataSample(int n)" ? That
> would make a summation function very slow. Should you have a
> "CopyDataSamples(int * dest, int n)" to let users have a local copy?
> Again, it's slow, and a waste of data space. Perhaps just "const int *
> AccessDataSamples(void)" to return a pointer to the data - it's fast,
> but loses the compile-time checking you get with simple clear access to
> the raw global data.

The notions of "Slow" and "Fast" are meaningless without respect to the
particular application. A function either works or not works. If it
works, I would do it in the most clear, portable and modular way. If
there are the *real* constraints in size/speed, then I may have to
resort to globals.


Vladimir Vassilevsky
DSP and Mixed Signal Design Consultant
http://www.abvolt.com
From: Jon Kirwan on
On Tue, 29 Sep 2009 16:25:36 +0000 (UTC), Grant Edwards wrote:

>On 2009-09-28, Jon Kirwan <jonk(a)infinitefactors.org> wrote:
>
>> [First off, I want to make sure no one reading this is conflating the
>> idea of 'global' with 'static'. A global definition (in c) is always
>> a static definition. But not all static definitions are global.]
>
>The overloading of the 'static' keyword in the C language to
>modify lexical scope in one case and lifetime in another was a
>huge mistake IMO.

hehe. Okay. I don't remember the history of it well, but I seem to
recall that c derived the use within function bodies from FORTRAN. In
other words, the use of 'static' for lifetime came from there. I
think that use started at the very beginning. At least, it seems to
me it did (and I've been using it since 1978.) However, the use of
'static' for scoping seems to me to have been a little later. (I
really could be wrong, here.) And if so, it may have been used for
reasons similar to those stroustrup gave for some choices made in c++
-- the desire to keep the keyword list changes to a minimum, in order
to avoid breaking code to the extent possible. In other words,
practical considerations.

It is what it is.

Jon
From: Dombo on
John Devereux schreef:
> Vladimir Vassilevsky <nospam(a)nowhere.com> writes:
>
>> David Brown wrote:
>>
>>
>>> What I take issue with is when people get obsessive about globals
>>> and think that it is somehow better to have functions called
>>> "SetUartTimeout" and "GetUartTimeout",
>> Yes it is better.
>>
>> * Perhaps it could be necessary to add flushing the UART before
>> changing timeouts. You just have to modify one function.
>>
>> * What if there is a need to have more then one uart? How about
>> accessing N uarts?
>>
>> * What if there is a need to access the timeouts from more then one thread?
>>
>> * What if there is a name conflict due to the use of the global objects?
>>
>>> doing nothing but accessing a static variable, instead of just using
>>> a globally visible variable "uartTimeout".
>> I do require all access to such variables via member functions. I like
>> an overloaded function UART.Timeout() instead of separate Set.. and
>> Get.. functions.
>
> How does that work, like:
>
> timeout = UART.Timeout(GET,UART1);
>
> ...
>
> UART.Timeout(SET,10000);


Since Vladimir mentioned overloaded member functions I expect he means
something like:

class UART
{
public:
void Timeout(int amount); // Set UART timeout
int Timeout(); // Get UART timeout


};

From: David Brown on
Vladimir Vassilevsky wrote:
>
>
> David Brown wrote:
>
>
>> This is comp.arch.embedded - a great many of the projects here do not
>> grow "large" because they are for small systems. The code is small
>> enough that is not a big problem to keep track of modules and their
>> interfaces, and that includes global variables. On the other hand,
>> the waste of runtime and code space caused by unnecessary accessor
>> functions /can/ be significant.
>
> Unfortunately, I've seen quite a few projects which were started as
> "small" and then overgrew into "large". It was too late to change the
> interfaces, so they ended up duplicating the entire modules by
> copy/paste and renaming the global variables by find/replace.

Projects that start small and then grow large is a bad sign in the first
place. A common cause of this sort of problem is when people take
"test" or "prototype" code and designs, and try to turn it into a
finished product.

It is always important to understand what you are aiming for in your
code. Are you trying to write something specific for one application,
or do you want it for general use? Are you trying to write something
small and fast, or is that low importance for this particular piece of
code? Does it need to be very portable? Does it need to be easily
understood by others? You should not write code if you don't know
/what/ you are targeting, and /why/ you are doing it in a particular
way. Then you can (mostly!) avoid overgrowth issues.

And of course, the use of global variables is a small issue in such
cases - if you make a duplicate module with find/replace, you have the
same issues with global functions or structures as with global variables.

> "Code efficiency" is a very common excuse for sloppy practices.
>

"Premature optimisation is the root of all evil". However, too many
abstractions is just as bad. Pick a happy medium, suited to the code in
question.

>
>> To take another example, suppose you have a module that collects
>> samples from somewhere and puts it in an array dataSamples[]. Should
>> that only be accessible through a function "int GetDataSample(int n)"
>> ? That would make a summation function very slow. Should you have a
>> "CopyDataSamples(int * dest, int n)" to let users have a local copy?
>> Again, it's slow, and a waste of data space. Perhaps just "const int
>> * AccessDataSamples(void)" to return a pointer to the data - it's
>> fast, but loses the compile-time checking you get with simple clear
>> access to the raw global data.
>
> The notions of "Slow" and "Fast" are meaningless without respect to the
> particular application. A function either works or not works. If it
> works, I would do it in the most clear, portable and modular way. If
> there are the *real* constraints in size/speed, then I may have to
> resort to globals.
>

I use global variables when they are appropriate - the choice can often
be because they make the code clearer (and perhaps also more portable
and modular). Building fine oo interfaces and other abstractions /may/
make the code better (in the sense of making it clear, portable and
modular), but it can also make it worse. If it is done as part of a
consistent design pattern, it will help. If it is done simply because
someone said that global variables were bad, it will make it worse.

Of course, there is no doubt that code correctness is much more
important than code speed, and also that clarity of code (which heavily
influences its correctness, especially during later maintenance) is
generally more important than raw speed. But given the choice of
writing clear, efficient code or clear, inefficient code, I know which I
choose.