Author Topic: All variables should be Global  (Read 19676 times)

0 Members and 1 Guest are viewing this topic.

Online tggzzz

  • Super Contributor
  • ***
  • Posts: 20752
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: All variables should be Global
« Reply #50 on: March 01, 2017, 09:16:39 am »
Remind me, is it possible to "cast away constness" now?
Yes, and it has been the case since the very first standard, so I'm not sure why you added the word "now".

Because the committee discussed/argued about that for at least a year.

Now, if you can cast away constness, how can you guarantee that code designed+compiled+optimised assuming constness will continue to function correctly alongside code compiled optimised assuming it can ignore that specification.

Quote
Quote
Quote
I'm not sure what the source of a feature has to do with anything. I evaluate language features by their merit. If a good feature was proposed by a random ganster on the streets, I would want it to be added, too.

I don't see how that is relevant to anything I wrote.

Quote
the template language "features" you mention, because they were discovered and the design committee did not believe it until someone rubbed their noses in it. I prefer my tools to be designed, not discovered

Unless you literally meant someone wrote a C++ compiler, didn't write code to support templates, and it turned out to magically support templates? (this would be equivalent to your multimeter and soldering example)

While templates were being "designed" the language designers didn't realise their construction had become so complex that it had become Turing complete, and even refused to believe people that tried to point it out. It was only when someone took that compiler (multimeter), wrote a small valid program (measured voltage), and demonstrated that the compilation process emitted the sequence of primes (soldered wires), that the language designers woke up and smelled the coffee. I remember this emerging; see https://en.wikibooks.org/wiki/C%2B%2B_Programming/Templates/Template_Meta-Programming#History_of_TMP and http://www.erwin-unruh.de/primorig.html

If the language designers didn't understand their creation, what chance to expert programmers have (let alone normal programmers). We don't live in a "Lake Wobegone world" where all children are above average! The need for language lawyers in ordinary programming situations is a damning indictment.

IMNSHO it is a very bad starting point to use a language where it is provably impossible to determine whether a valid program will even complete compilation!
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline tatus1969

  • Super Contributor
  • ***
  • Posts: 1273
  • Country: de
  • Resistance is futile - We Are The Watt.
    • keenlab
Re: All variables should be Global
« Reply #51 on: March 01, 2017, 09:41:30 am »
browsed through the comments and did not see one hard reason why the scope of each and every variable should be as short as possible:

When you make everything global, then the compiler has to allocate enough memory to hold all of them simultaneously. But if you restrict yourself to making only those global that need it (need to be static, or need to be accessed from multiple modules), and make all others function ("dynamic") scope, then you will have less total memory consumption in most cases.

I am assuming that all dynamic variables are allocated on the stack and freed again after use (valid for most architectures). I also assume that the application has more than one call nesting "branch". Imagine that you call one branch from main(). The machine executes it and eventually reaches the deepest nesting level. At this time, all dynamic variables for this branch are present on the stack. The machine continues to work through that code and eventually returns back to main(). It then has deallocated again all these dynamic variables from the stack. Imagine that it then jumps into and down another branch, again allocating dynamic variables on the stack. This is the important moment: all the new variables share the same memory as the others from the first branch.

Generally spoken, the maximum stack space required is determined by the one of all the independent branches, that has the largest set of dynamic variables. Plus overhead from parameter / return value passing and return address storage. Modern compilers can calculate this value, which gives you the ability to set the stack size right.
« Last Edit: March 01, 2017, 09:43:30 am by tatus1969 »
We Are The Watt - Resistance Is Futile!
 

Online Kjelt

  • Super Contributor
  • ***
  • Posts: 6576
  • Country: nl
Re: All variables should be Global
« Reply #52 on: March 01, 2017, 09:51:11 am »
A lot of good arguments already given, going to add two:

- Some processor architectures like the STM8 have a "zero page" RAM of 128 bytes or so that are accessible in a single cycle, all other RAM locations are two or more cycles.
  So let the compiler use this fast RAM for where it is best used: local variables in for or while loops.

- Security: Global variables for all possible variables are a hackers heaven.
 

Online mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 14001
  • Country: gb
    • Mike's Electric Stuff
Re: All variables should be Global
« Reply #53 on: March 01, 2017, 09:51:21 am »
browsed through the comments and did not see one hard reason why the scope of each and every variable should be as short as possible:

When you make everything global, then the compiler has to allocate enough memory to hold all of them simultaneously. But if you restrict yourself to making only those global that need it (need to be static, or need to be accessed from multiple modules), and make all others function ("dynamic") scope, then you will have less total memory consumption in most cases.

I am assuming that all dynamic variables are allocated on the stack and freed again after use (valid for most architectures). I also assume that the application has more than one call nesting "branch". Imagine that you call one branch from main(). The machine executes it and eventually reaches the deepest nesting level. At this time, all dynamic variables for this branch are present on the stack. The machine continues to work through that code and eventually returns back to main(). It then has deallocated again all these dynamic variables from the stack. Imagine that it then jumps into and down another branch, again allocating dynamic variables on the stack. This is the important moment: all the new variables share the same memory as the others from the first branch.

Generally spoken, the maximum stack space required is determined by the one of all the independent branches, that has the largest set of dynamic variables. Plus overhead from parameter / return value passing and return address storage. Modern compilers can calculate this value, which gives you the ability to set the stack size right.
I think that in some cases, e.g. PIC8, locals are statically allocated in a pool, the size being determined by the call tree, so the memory usage will only be that needed by the deepest call path. The compiler can figure out how to safely re-use memory that can't be used by multiple procedures at the same time.
This is probably going to be more efficient than using a stack, especially on small systems, as all the addresses are fixed at compile time, and avoids the uncertainty of knowing whether the stack allocation is big enough.
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 

Offline forrestc

  • Supporter
  • ****
  • Posts: 708
  • Country: us
Re: All variables should be Global
« Reply #54 on: March 01, 2017, 10:27:01 am »
I think that in some cases, e.g. PIC8, locals are statically allocated in a pool, the size being determined by the call tree, so the memory usage will only be that needed by the deepest call path. The compiler can figure out how to safely re-use memory that can't be used by multiple procedures at the same time.
This is probably going to be more efficient than using a stack, especially on small systems, as all the addresses are fixed at compile time, and avoids the uncertainty of knowing whether the stack allocation is big enough.

This is exactly what I was going to say, more or less.

By declaring locals, the compiler is able to better understand the scope of the variable usage, and re-use the storage space accordingly.   In a call tree with no recursion, variables can be statically allocated in memory and the space can be reused across functions which are never active at the same time (i.e. are in different parts of the call tree) - hope that was clear.

With recursion, the compiler can switch to a stack-based memory model for those functions which are in the recursive part of the call tree.

One other related point is optimizations for speed vs size vs storage space.   These should be easier with local variables, as the compiler is free to use registers where appropriate, and memory where appropriate.



 

Offline madires

  • Super Contributor
  • ***
  • Posts: 8177
  • Country: de
  • A qualified hobbyist ;)
Re: All variables should be Global
« Reply #55 on: March 01, 2017, 10:42:42 am »
Another thing to consider when using global variables is the way you organize and access the variables. The best method depends on the addressing commands of the MCU.
 

Offline cyberfish

  • Regular Contributor
  • *
  • Posts: 240
  • Country: gb
Re: All variables should be Global
« Reply #56 on: March 01, 2017, 11:24:39 am »
Remind me, is it possible to "cast away constness" now?
Yes, and it has been the case since the very first standard, so I'm not sure why you added the word "now".

Because the committee discussed/argued about that for at least a year.

Now, if you can cast away constness, how can you guarantee that code designed+compiled+optimised assuming constness will continue to function correctly alongside code compiled optimised assuming it can ignore that specification.


I'm glad they spent a lot of time debating a feature that is obviously controversial.

const_cast is one of those things that shouldn't be used unless you know exactly what you are doing - most reference materials make that clear. It's for casting away const-ness in a const reference type when you know the object it refers to wasn't const to begin with. There are a few situations where it's useful. Casting const-ness away when the object was actually const results in undefined behaviour, as you would expect.

Quote
Quote
Quote
Quote
I'm not sure what the source of a feature has to do with anything. I evaluate language features by their merit. If a good feature was proposed by a random ganster on the streets, I would want it to be added, too.

I don't see how that is relevant to anything I wrote.

Quote
the template language "features" you mention, because they were discovered and the design committee did not believe it until someone rubbed their noses in it. I prefer my tools to be designed, not discovered

Unless you literally meant someone wrote a C++ compiler, didn't write code to support templates, and it turned out to magically support templates? (this would be equivalent to your multimeter and soldering example)

While templates were being "designed" the language designers didn't realise their construction had become so complex that it had become Turing complete, and even refused to believe people that tried to point it out. It was only when someone took that compiler (multimeter), wrote a small valid program (measured voltage), and demonstrated that the compilation process emitted the sequence of primes (soldered wires), that the language designers woke up and smelled the coffee. I remember this emerging; see https://en.wikibooks.org/wiki/C%2B%2B_Programming/Templates/Template_Meta-Programming#History_of_TMP and http://www.erwin-unruh.de/primorig.html

If the language designers didn't understand their creation, what chance to expert programmers have (let alone normal programmers). We don't live in a "Lake Wobegone world" where all children are above average! The need for language lawyers in ordinary programming situations is a damning indictment.

IMNSHO it is a very bad starting point to use a language where it is provably impossible to determine whether a valid program will even complete compilation!

That's really not the same at all. They didn't "discover" a new feature. They "discovered" a new use for a feature they designed. It would be equivalent to figuring out that you can use multimeters' sample and hold capacitors to display CPU utilization of a microcontroller by having the microcontroller turn a GPIO on in the active part of an event loop, and off when sleeping. It's cool, but of little practical significance. People discover new ways to use existing things all the time, and I wouldn't say that's a sign of bad design. I would say it's a sign of good design when mechanisms turn out to be more capable than the designers imagined.
 

Offline DJohn

  • Regular Contributor
  • *
  • Posts: 103
  • Country: gb
Re: All variables should be Global
« Reply #57 on: March 01, 2017, 12:44:12 pm »
There's no performance difference in this case. Structs (of sizes larger than the largest int type usually) are always passed by pointers anyways (copies are made by caller if necessary).

This is roughly true for parameters passed by value (it's very ABI-dependant).

Indeed.  And sometimes it's not even the ABI.  I've worked on a platform on which small structs passed by value would be passed in registers, despite the ABI saying they must go on the stack.  The compiler knew that the callee would not be placed in a library (which would have to use the official ABI), and could use its own calling convention.

In the case of the non-inlined pass-by-global example on PIC32, it's not necessarily just the extra store and load instructions that are making it so much slower.  That code will be storing data to memory, jumping to the function, then immediately loading the data back.  What actually happens is that the store happens, then while the data is making its way to the cache (or to main memory if you're unlucky), the jump and load instructions will start. The load will recognise the data dependency and stall until the load has finished.  It will then start loading (hopefully from cache this time).  But then the next instruction tries to use the data, and stalls again.

Caches are fast, but their latency can still be surprisingly high.  That's the dirty secret of CPU design: high latency is often the price you pay for high throughput.

On 8 bit processors with no cache and few registers, things will of course be completely different.  If you care about performance, there is no substitute for knowing your processor and knowing your compiler.  Read the disassembly.  And trust only the profiler.
 

Offline tatus1969

  • Super Contributor
  • ***
  • Posts: 1273
  • Country: de
  • Resistance is futile - We Are The Watt.
    • keenlab
Re: All variables should be Global
« Reply #58 on: March 01, 2017, 12:49:06 pm »
I think that in some cases, e.g. PIC8, locals are statically allocated in a pool, the size being determined by the call tree, so the memory usage will only be that needed by the deepest call path. The compiler can figure out how to safely re-use memory that can't be used by multiple procedures at the same time.
This is probably going to be more efficient than using a stack, especially on small systems, as all the addresses are fixed at compile time, and avoids the uncertainty of knowing whether the stack allocation is big enough.
agree, the 8051 is another candidate from which I know this. These architectures do not provide efficient [indirect + offset] addressing schemes, so the compiler designers had to go that route. I like that strategy, but it adds complexity because only the linker can do that optimization, and it needs to know all dependencies. And that can become a sever limitation of it. As soon as you start using function pointers that are calculated at runtime, it really depends on the compiler/linker cleverness to "see" that dependency. I went into this problem long ago and it really tooke me a lot of time to detect it.
We Are The Watt - Resistance Is Futile!
 

Online tggzzz

  • Super Contributor
  • ***
  • Posts: 20752
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: All variables should be Global
« Reply #59 on: March 01, 2017, 01:37:14 pm »
Remind me, is it possible to "cast away constness" now?
Yes, and it has been the case since the very first standard, so I'm not sure why you added the word "now".

Because the committee discussed/argued about that for at least a year.

Now, if you can cast away constness, how can you guarantee that code designed+compiled+optimised assuming constness will continue to function correctly alongside code compiled optimised assuming it can ignore that specification.

I'm glad they spent a lot of time debating a feature that is obviously controversial.

const_cast is one of those things that shouldn't be used unless you know exactly what you are doing - most reference materials make that clear. It's for casting away const-ness in a const reference type when you know the object it refers to wasn't const to begin with. There are a few situations where it's useful. Casting const-ness away when the object was actually const results in undefined behaviour, as you would expect.

Just so. The problem is that any observed effect can be subtle and is not necessarily visible in the source code, since it is a property of the source code, the compiler version, the compiler flags, the specific processor, and also the data. While one might accept such "random failures" in a generic application, they are often not acceptable in embedded systems, especially anything related to safety.

It is insufficient to simply say "you have to use the tool correctly" when in practice it is very difficult to ensure/check that it is used "correctly", and there are alternative tools where no such problem exists.

Quote
Quote
Quote
Quote
Quote
I'm not sure what the source of a feature has to do with anything. I evaluate language features by their merit. If a good feature was proposed by a random ganster on the streets, I would want it to be added, too.

I don't see how that is relevant to anything I wrote.

Quote
the template language "features" you mention, because they were discovered and the design committee did not believe it until someone rubbed their noses in it. I prefer my tools to be designed, not discovered

Unless you literally meant someone wrote a C++ compiler, didn't write code to support templates, and it turned out to magically support templates? (this would be equivalent to your multimeter and soldering example)

While templates were being "designed" the language designers didn't realise their construction had become so complex that it had become Turing complete, and even refused to believe people that tried to point it out. It was only when someone took that compiler (multimeter), wrote a small valid program (measured voltage), and demonstrated that the compilation process emitted the sequence of primes (soldered wires), that the language designers woke up and smelled the coffee. I remember this emerging; see https://en.wikibooks.org/wiki/C%2B%2B_Programming/Templates/Template_Meta-Programming#History_of_TMP and http://www.erwin-unruh.de/primorig.html

If the language designers didn't understand their creation, what chance to expert programmers have (let alone normal programmers). We don't live in a "Lake Wobegone world" where all children are above average! The need for language lawyers in ordinary programming situations is a damning indictment.

IMNSHO it is a very bad starting point to use a language where it is provably impossible to determine whether a valid program will even complete compilation!

That's really not the same at all. They didn't "discover" a new feature. They "discovered" a new use for a feature they designed.

It is more than that. Initially the language designers refused to accept that it was Turing complete until someone rubbed their noses in it and they could no longer wish/pretend the "feature" didn't exist.

Quote
It would be equivalent to figuring out that you can use multimeters' sample and hold capacitors to display CPU utilization of a microcontroller by having the microcontroller turn a GPIO on in the active part of an event loop, and off when sleeping. It's cool, but of little practical significance. People discover new ways to use existing things all the time, and I wouldn't say that's a sign of bad design. I would say it's a sign of good design when mechanisms turn out to be more capable than the designers imagined.

That's different. It is entirely acceptable and desirable that tool designers don't anticipate all the uses for their tool. It is unacceptable that the designers don't understand their own tool.

Do you think it is beneficial that valid programs can fail to complete compilation?
Do you think it is beneficial that you cannot tell whether valid programs can be compiled?
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline bookaboo

  • Frequent Contributor
  • **
  • Posts: 758
  • Country: ie
Re: All variables should be Global
« Reply #60 on: March 01, 2017, 01:49:20 pm »
Scrolled through most of this and didn't see one of the major reasons listed yet and that's portability. If you write a function with a few arguments and returning a value it's usually a cut/paste job to port it to another project. Whereas if you use globals you need to make sure there's no clash in variable names between new and ported code.
It's also more readable and easier to debug.
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4533
  • Country: nz
Re: All variables should be Global
« Reply #61 on: March 01, 2017, 02:16:56 pm »
While templates were being "designed" the language designers didn't realise their construction had become so complex that it had become Turing complete, and even refused to believe people that tried to point it out.

C++ templates are far from being the only thing that has accidentally turned out to be Turing complete.

Some other examples:

- Java generics. Opps! They even knew about C++ templates in advance!

- x86 MMU fault handling

- Magic, The Gathering

- HTML5+CSS

http://beza1e1.tuxen.de/articles/accidentally_turing_complete.html

Also: vi key macros https://github.com/divVerent/vi-turing

Also: x86, even without using any registers (not even the condition code register and branches) http://mainisusuallyafunction.blogspot.ru/2014/02/x86-is-turing-complete-with-no-registers.html
 

Online tggzzz

  • Super Contributor
  • ***
  • Posts: 20752
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: All variables should be Global
« Reply #62 on: March 01, 2017, 03:08:51 pm »
While templates were being "designed" the language designers didn't realise their construction had become so complex that it had become Turing complete, and even refused to believe people that tried to point it out.
C++ templates are far from being the only thing that has accidentally turned out to be Turing complete.
Some other examples:
- Java generics. Opps! They even knew about C++ templates in advance!

I'm not a fan of Java's generics, but I haven't seen any solid evidence they are accidentally Turing complete, let alone that the designers (initially) denied that. Mind you, I haven't looked.

Quote
- x86 MMU fault handling

Surprising, but not something that a developer could invoke using the tools they use as part of their day-to-day job.

Quote
- Magic, The Gathering
- HTML5+CSS

I don't think Magic's objective is to develop programs!

As for HTML5+CSS, it doesn't surprise me since that whole area is a mutated mess! Given the net and graphic designers are involved, I'm not sure anyone would notice grossly slow and abnormal behaviour :)

Quote
http://beza1e1.tuxen.de/articles/accidentally_turing_complete.html

Asserts rather than proves accidental Turing Completeness.

Quote
Also: vi key macros https://github.com/divVerent/vi-turing

Also: x86, even without using any registers (not even the condition code register and branches) http://mainisusuallyafunction.blogspot.ru/2014/02/x86-is-turing-complete-with-no-registers.html

Sure; unsurprising.

But it remains that the baroque complexity of C++ baffled even the language designers. That's indicative of something that is out of control.
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline @rtTopic starter

  • Super Contributor
  • ***
  • Posts: 1071
Re: All variables should be Global
« Reply #63 on: March 01, 2017, 03:20:00 pm »
Where a function setpixel() is used most in a graphics library, no matter whether drawing lines or circles,
and no matter their arguments, setpixel is going to be called the most by those functions, so there should be a difference
that could be measured by only changing that function to pass arguments setpixel(int x, int y);

Then if you drew a whole bunch of lines and circles, and measured the time with hardware timer,
is just that one change to code a fair measurement of anything?
 

Offline cyberfish

  • Regular Contributor
  • *
  • Posts: 240
  • Country: gb
Re: All variables should be Global
« Reply #64 on: March 01, 2017, 03:26:47 pm »
Just so. The problem is that any observed effect can be subtle and is not necessarily visible in the source code, since it is a property of the source code, the compiler version, the compiler flags, the specific processor, and also the data. While one might accept such "random failures" in a generic application, they are often not acceptable in embedded systems, especially anything related to safety.

It is insufficient to simply say "you have to use the tool correctly" when in practice it is very difficult to ensure/check that it is used "correctly", and there are alternative tools where no such problem exists.

It does not depend on the compiler, hardware, or data at all. Correctly written code will work with any correctly written compiler.

If you cannot guarantee that the object is not const, you cannot use const_cast. Practically, that means const_cast cannot be used except in very specific cases. The only such specific case I have seen is to provide an overloaded accessor function that returns a const reference if "this" pointer is const, and a non-const reference if it isn't. It saves code duplication in this case, and the behaviour is completely defined, and will work with any standard-compliant compiler. This is the only use of const_cast I have seen in high quality code.

Code: [Select]
class A {
public:
  const int& f() const {
    /* do a bunch of stuff */
    return x;
  }

  int& f() {
    const &A const_this = *this;
    return const_cast<const A*>(const_this->GetX());
  }

private:
  int x;
}

Yes, it's convoluted, and shouldn't be used unless you know exactly what you are doing.

This problem doesn't exist in alternative tools, because alternative tools don't allow you to do this at all. You have to write two different functions if you want a const and a non-const version. You can do that in C++ too if you want (and people who don't know how const_cast works should).

Java solves it by not supporting const (final) references. You can disallow assigning another object to the reference, but not make the object itself final. If you don't use const references in C++ (which makes things safer, without adding any overhead), you won't have this problem either.

Quote
That's different. It is entirely acceptable and desirable that tool designers don't anticipate all the uses for their tool. It is unacceptable that the designers don't understand their own tool.
Even if that's true, it's something that happened decades ago. Again, I evaluate language features by their merit, and not by where/how it came about.

Quote
Do you think it is beneficial that valid programs can fail to complete compilation?
Do you think it is beneficial that you cannot tell whether valid programs can be compiled?
No, but I think it is beneficial to have a powerful meta-programming system that allows people to do things like compile-time optimization of expressions in a linear algebra library that is not possible in languages without a meta-programming system (http://eigen.tuxfamily.org/dox/TopicLazyEvaluation.html).

If you have a powerful meta-programming system, those properties are unavoidable side effects.

And I think the fact that you can abuse it in a way to write a valid program that fails to compile is an acceptable downside to that, because I am not going to do that.
 

Offline TNorthover

  • Contributor
  • Posts: 42
  • Country: us
Re: All variables should be Global
« Reply #65 on: March 01, 2017, 03:54:57 pm »
Allowing casting constness away is also a necessary for C compatibility. And the template horrors are gradually being reduced by constexpr in newer standards.
 

Online tggzzz

  • Super Contributor
  • ***
  • Posts: 20752
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: All variables should be Global
« Reply #66 on: March 01, 2017, 04:18:52 pm »
Just so. The problem is that any observed effect can be subtle and is not necessarily visible in the source code, since it is a property of the source code, the compiler version, the compiler flags, the specific processor, and also the data. While one might accept such "random failures" in a generic application, they are often not acceptable in embedded systems, especially anything related to safety.

It is insufficient to simply say "you have to use the tool correctly" when in practice it is very difficult to ensure/check that it is used "correctly", and there are alternative tools where no such problem exists.

It does not depend on the compiler, hardware, or data at all. Correctly written code will work with any correctly written compiler.

Well, doh. That's a trivially true statement since it depends on the definitions of "correct". From listening to echoes of what happened in and after some of the standardisation attempts, that was non-trivial since the committee members disagreed about what some of the wording meant. Without such agreement, any definition of "correct" is moot. And then similar things happened when the commercial  compiler writers asked what sections of the standard meant, because there were, apparently and remarkably, conflicting sections.

I also remember somewhere around 2005 somebody triumphantly announcing the first complete compiler. Now I forget whether it was for C or C++, but since it was 6 years after the standard was fixed, it is plausible that it was for C99. Sorry I can't be more specific.

However, looking at https://en.wikipedia.org/wiki/C99#Implementations it appears that even GCC doesn't fully implement C99 after 15 years!

Of course mere users also have to try and figure out which compilers do/don't "correctly implement" the language - which is an impossible task.

Quote
If you cannot guarantee that the object is not const, you cannot use const_cast. Practically, that means const_cast cannot be used except in very specific cases. The only such specific case I have seen is to provide an overloaded accessor function that returns a const reference if "this" pointer is const, and a non-const reference if it isn't. It saves code duplication in this case, and the behaviour is completely defined, and will work with any standard-compliant compiler. This is the only use of const_cast I have seen in high quality code.

Again, you are saying "in correctly written code you get correct results", carefully avoiding the issue of whether it is practical to assume that all the code in your system is "correct".

Quote
This problem doesn't exist in alternative tools, because alternative tools don't allow you to do this at all. You have to write two different functions if you want a const and a non-const version. You can do that in C++ too if you want (and people who don't know how const_cast works should).

Yes, alternative tools don't allow such things, principally because they have a simpler better foundation where such things aren't necessary.

Quote
Java solves it by not supporting const (final) references. You can disallow assigning another object to the reference, but not make the object itself final. If you don't use const references in C++ (which makes things safer, without adding any overhead), you won't have this problem either.

Comparing with Java isn't helpful in this case, for the above reason.

Quote
Quote
That's different. It is entirely acceptable and desirable that tool designers don't anticipate all the uses for their tool. It is unacceptable that the designers don't understand their own tool.
Even if that's true, it's something that happened decades ago. Again, I evaluate language features by their merit, and not by where/how it came about.

Understanding history is a useful way of determining where skeletons are still concealed, or alternatively of determining that the skeletons have been properly removed.

Quote
Quote
Do you think it is beneficial that valid programs can fail to complete compilation?
Do you think it is beneficial that you cannot tell whether valid programs can be compiled?
No, but I think it is beneficial to have a powerful meta-programming system that allows people to do things like compile-time optimization of expressions in a linear algebra library that is not possible in languages without a meta-programming system (http://eigen.tuxfamily.org/dox/TopicLazyEvaluation.html).

I agree.

But those benefits (and many other) should be embodied either in a library, or in a well-defined special-purpose language - possibly one that is converted to plain-vanilla C/C++ for compilation and execution.

Accidentally including them in a general purpose language is a specification and design smell.

Quote
If you have a powerful meta-programming system, those properties are unavoidable side effects.

And I think the fact that you can abuse it in a way to write a valid program that fails to compile is an acceptable downside to that, because I am not going to do that.

I'm sure you and your compiler always produce correct code. Unfortunately most people don't even realise that they are subtly screwing up - and C/C++ baroque complexity is part of that problem.
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Online tggzzz

  • Super Contributor
  • ***
  • Posts: 20752
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: All variables should be Global
« Reply #67 on: March 01, 2017, 04:21:49 pm »
Allowing casting constness away is also a necessary for C compatibility. And the template horrors are gradually being reduced by constexpr in newer standards.

Just so. Of course that amelioration presumes that compiler writers and developers will correctly implement and use such features.

Unfortunately there is a mass of important code in the wild that will never be rewritten, so the current problems will remain for the foreseeable future.
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline cyberfish

  • Regular Contributor
  • *
  • Posts: 240
  • Country: gb
Re: All variables should be Global
« Reply #68 on: March 02, 2017, 04:33:03 pm »
Well, doh. That's a trivially true statement since it depends on the definitions of "correct". From listening to echoes of what happened in and after some of the standardisation attempts, that was non-trivial since the committee members disagreed about what some of the wording meant. Without such agreement, any definition of "correct" is moot. And then similar things happened when the commercial  compiler writers asked what sections of the standard meant, because there were, apparently and remarkably, conflicting sections.
Yes, standards as big as the C++ standards will inevitably have ambiguity in places. They are to be fixed in future standards. Many things were cleared up in C++11 for example. The C++ standard is not perfect, and that's why it's still being revised.

Quote
I also remember somewhere around 2005 somebody triumphantly announcing the first complete compiler. Now I forget whether it was for C or C++, but since it was 6 years after the standard was fixed, it is plausible that it was for C99. Sorry I can't be more specific.

However, looking at https://en.wikipedia.org/wiki/C99#Implementations it appears that even GCC doesn't fully implement C99 after 15 years!

And then you have languages like Objective-C or Python that don't even have a standard, only a reference implementation. Obviously in this case you'll have a perfect implementation and a perfectly-defined language, by definition! In theory that means all other implementation must also reproduce bugs in the reference implementation.

Quote
Of course mere users also have to try and figure out which compilers do/don't "correctly implement" the language - which is an impossible task.
All compilers for all languages have bugs. Are you claiming otherwise?

Quote
Again, you are saying "in correctly written code you get correct results", carefully avoiding the issue of whether it is practical to assume that all the code in your system is "correct".
Can you assume that all the code in your system involved in Obj-C compilation are correct? If you can, so can I. All C++ standard libraries included in major compilers have been extensively tested, and finding a bug in the field is extremely rare.

Quote
Yes, alternative tools don't allow such things, principally because they have a simpler better foundation where such things aren't necessary.

Like in Objective-C, by basically making const useless?

What, concretely, are you referring to?

Quote
Comparing with Java isn't helpful in this case, for the above reason.
Java can definitely be made safer by having a good const ref implementation.

You have an ArrayList of large objects, and you want to let the caller access one element, read-only, without making any copies. How do you go about doing that?

You can't. You have to either trust the caller to not modify the reference you return, or make a copy.

Quote
Understanding history is a useful way of determining where skeletons are still concealed, or alternatively of determining that the skeletons have been properly removed.
The language is fully defined by the current standard. All the skeletons are listed, no matter where or how they came about.

Quote
I agree.

But those benefits (and many other) should be embodied either in a library, or in a well-defined special-purpose language - possibly one that is converted to plain-vanilla C/C++ for compilation and execution.

Accidentally including them in a general purpose language is a specification and design smell.
Template metaprogramming IS mostly done in libraries (like Eigen). You will rarely see that in application code.

Well, yes, the special-purpose language is the template language. The compiler does convert it to plain-vanilla C++ for compilation.

Would it be better if it was just called a different name and described in a separate document?

Quote
I'm sure you and your compiler always produce correct code. Unfortunately most people don't even realise that they are subtly screwing up - and C/C++ baroque complexity is part of that problem.
Yes, C++ is difficult to learn. I don't think anyone is arguing otherwise.

It's a powerful language that can be used to write very elegant (and at the same time, high performance) code by proficient programmers, but it does require more training than most other languages.

Still, there are at least a million C++ developers in the world better than I am, and I can already use C++ effectively and write more elegant code than I can in any other language. So learning C++ to a very practically useful level is far from impossible.
 

Offline @rtTopic starter

  • Super Contributor
  • ***
  • Posts: 1071
Re: All variables should be Global
« Reply #69 on: March 03, 2017, 06:42:20 am »
This will draw two identical patterns in the same y position.
It would appear the top one will save significant program memory.
For the extra memory, will the second one be faster?

I’m aware you could loop through these values in an array of indexes,
and there are a number of other ways to save memory on it.

Code: [Select]
x = 13; y = 39; setpixel();
x = 114; setpixel(); // global y is already 39.
x = 12; y = 40; setpixel();
x = 115; setpixel();
x = 11; y = 41; setpixel();
x = 116; setpixel();
x = 11; y = 42; setpixel();
x = 116; setpixel();
x = 11; y = 43; setpixel();
x = 116; setpixel();
x = 11; y = 44; setpixel();
x = 116; setpixel();
x = 11; y = 45; setpixel();
x = 116; setpixel();
x = 12; y = 46; setpixel();
x = 115; setpixel();
x = 13; y = 47; setpixel();
x = 114; setpixel();


Code: [Select]
setpixel(13,39);
setpixel(114,39);
setpixel(12,40);
setpixel(115,40);
setpixel(11,41);
setpixel(116,41);
setpixel(11,42);
setpixel(116,42);
setpixel(11,43);
setpixel(116,43);
setpixel(11,44);
setpixel(116,44);
setpixel(11,45);
setpixel(116,45);
setpixel(12,46);
setpixel(115,46);
setpixel(13,47);
setpixel(114,47);
« Last Edit: March 03, 2017, 06:46:43 am by @rt »
 

Offline janekm

  • Supporter
  • ****
  • Posts: 515
  • Country: gb
Re: All variables should be Global
« Reply #70 on: March 03, 2017, 07:10:33 am »
This will draw two identical patterns in the same y position.
It would appear the top one will save significant program memory.
For the extra memory, will the second one be faster?

I’m aware you could loop through these values in an array of indexes,
and there are a number of other ways to save memory on it.

Code: [Select]
x = 13; y = 39; setpixel();
x = 114; setpixel(); // global y is already 39.
x = 12; y = 40; setpixel();
x = 115; setpixel();
x = 11; y = 41; setpixel();
x = 116; setpixel();
x = 11; y = 42; setpixel();
x = 116; setpixel();
x = 11; y = 43; setpixel();
x = 116; setpixel();
x = 11; y = 44; setpixel();
x = 116; setpixel();
x = 11; y = 45; setpixel();
x = 116; setpixel();
x = 12; y = 46; setpixel();
x = 115; setpixel();
x = 13; y = 47; setpixel();
x = 114; setpixel();


Code: [Select]
setpixel(13,39);
setpixel(114,39);
setpixel(12,40);
setpixel(115,40);
setpixel(11,41);
setpixel(116,41);
setpixel(11,42);
setpixel(116,42);
setpixel(11,43);
setpixel(116,43);
setpixel(11,44);
setpixel(116,44);
setpixel(11,45);
setpixel(116,45);
setpixel(12,46);
setpixel(115,46);
setpixel(13,47);
setpixel(114,47);

You seem to be forgetting that optimising compilers exist.
Your first example compiles to the following with ARM gcc 5.4.1 with -Os https://godbolt.org/g/c8O0nw (-O3 is better in this case, but still worse than the version with parameters):
Code: [Select]
setpixel():
        ldr     r2, .L2
        ldr     r0, [r2]
        ldr     r1, [r2, #4]
        mov     r2, #320
        ldr     r3, .L2+4
        ldr     r3, [r3]
        mla     r3, r2, r0, r3
        mvn     r2, #0
        strb    r2, [r3, r1]
        bx      lr
.L2:
        .word   .LANCHOR1
        .word   .LANCHOR0
main:
        stmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, lr}
        mov     r3, #39
        mov     r8, #13
        mov     r7, #114
        ldr     r4, .L6
        mov     r10, #12
        stmia   r4, {r3, r8}
        mov     r9, #115
        bl      setpixel()
        str     r7, [r4, #4]
        bl      setpixel()
        mov     r3, #40
        mov     r6, #11
        mov     r5, #116
        stmia   r4, {r3, r10}
        bl      setpixel()
        str     r9, [r4, #4]
        bl      setpixel()
        mov     r3, #41
        stmia   r4, {r3, r6}
        bl      setpixel()
        str     r5, [r4, #4]
        bl      setpixel()
        mov     r3, #42
        str     r6, [r4, #4]
        str     r3, [r4]
        bl      setpixel()
        str     r5, [r4, #4]
        bl      setpixel()
        mov     r3, #43
        str     r6, [r4, #4]
        str     r3, [r4]
        bl      setpixel()
        str     r5, [r4, #4]
        bl      setpixel()
        mov     r3, #44
        str     r6, [r4, #4]
        str     r3, [r4]
        bl      setpixel()
        str     r5, [r4, #4]
        bl      setpixel()
        mov     r3, #45
        str     r6, [r4, #4]
        str     r3, [r4]
        bl      setpixel()
        str     r5, [r4, #4]
        bl      setpixel()
        mov     r3, #46
        str     r10, [r4, #4]
        str     r3, [r4]
        bl      setpixel()
        str     r9, [r4, #4]
        bl      setpixel()
        mov     r3, #47
        str     r8, [r4, #4]
        str     r3, [r4]
        bl      setpixel()
        str     r7, [r4, #4]
        bl      setpixel()
        mov     r0, #0
        ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, lr}
        bx      lr
.L6:
        .word   .LANCHOR1
mem:
        .word   1073745920
y:
x:

Your second example becomes this with the same options https://godbolt.org/g/O4qx6Z :
Code: [Select]
setpixel(int, int):
        ldr     r3, .L2
        ldr     r2, [r3]
        mov     r3, #320
        mla     r1, r3, r1, r2
        mvn     r3, #0
        strb    r3, [r1, r0]
        bx      lr
.L2:
        .word   .LANCHOR0
main:
        mvn     r2, #0
        ldr     r3, .L5
        ldr     r3, [r3]
        add     r3, r3, #12288
        strb    r2, [r3, #205]
        strb    r2, [r3, #306]
        strb    r2, [r3, #524]
        strb    r2, [r3, #627]
        strb    r2, [r3, #843]
        strb    r2, [r3, #948]
        strb    r2, [r3, #1163]
        strb    r2, [r3, #1268]
        strb    r2, [r3, #1483]
        strb    r2, [r3, #1588]
        strb    r2, [r3, #1803]
        strb    r2, [r3, #1908]
        strb    r2, [r3, #2123]
        strb    r2, [r3, #2228]
        strb    r2, [r3, #2444]
        strb    r2, [r3, #2547]
        mov     r0, #0
        bx      lr
.L5:
        .word   .LANCHOR0
mem:
        .word   1073745920

 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4533
  • Country: nz
Re: All variables should be Global
« Reply #71 on: March 03, 2017, 08:27:43 am »
Brilliant!!
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: All variables should be Global
« Reply #72 on: March 03, 2017, 09:34:23 pm »
some guy with a suit & tie said: “Variables should be private unless global in their nature”.
He was right. The purpose of using a HLL is so the programmer can concentrate on program structure and let the compiler worry about implementation.

Quote
Code: [Select]
x = 13; y = 39; setpixel();
x = 114; setpixel(); // global y is already 39
...
In this trivial example it may be more efficient to do setpixel(x,y) but it could be a different story if the coordinates are variable.

Write code that reflects what you are trying to do, not contortions that you think might help the compiler to do a better job. If you want to display a fixed array of pixels then write appropriate code to do that. Hard-coding an image into a sequence of instructions is just awful programming style, whatever language you use.

If at the end you find that the compiled code is too inefficient, then consider what to do about it. But don't create a hack unless you are willing to accept the consequences (obtuse and unmaintainable code, lack of portability, compiler-specific results etc.). Most modern CPUs are optimized for C, and modern compilers are pretty good at optimizing away the 'fluff'. If you need to squeeze the absolute maximum out of a low-end chip and the compiler isn't up to it then program in assembler - then you will have complete control!   
 
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 22436
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: All variables should be Global
« Reply #73 on: March 04, 2017, 01:43:31 am »
Here's an optimization you probably won't get from the compiler: read it as an array.

In both above examples, the values are used in sequence, and not assigned to any memory (beyond a single pair of local variables, or registers).  That incurs a lot of MOV reg,imm instructions, which usually aren't very efficient: you have to encode the instruction itself, plus the data.

If instead we put the values in an array (usually a const array), then they can be "streamed" out with an auto-increment pointer (if such operations are available on the platform, that is).  So it turns into:
Code: [Select]
MOV ptr,&points_array
cycle:
MOV reg1,[ptr+]
MOV reg2,[ptr+]
CALL PlotPoint
LOOP cycle

Rolling things up into a loop saves code space, and the array can be inlined with code (Von Neumann architecture) or stuffed away in the data segment.  It probably executes slower, though -- loops being what they are.

On Harvard architectures, this saves space nicely.  AVR for example.  Loading registers is one thing, but having the compiler do it is doubly worse: C only knows how to read and write from SRAM.  You have to go out of your way to implement a const array in program memory, and you can't just pass it around, you have to use stub functions to read it into SRAM.  Whereas you can write something like,
Code: [Select]
movw Z,offset(points_array) << 1
cycle:
lpm r16, z+
lpm r17, z+
rcall PlotPoint
brne cycle

Takes up 6 words of PROGMEM, and only one byte (half word) per uint8_t sized parameter (two byte minimum).

Of course making the optimization of in-register parameter passing, for both cases.  Pushing and popping things only adds overhead, but it's a constant adder for both examples.

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline Feynman

  • Regular Contributor
  • *
  • Posts: 199
  • Country: ch
Re: All variables should be Global
« Reply #74 on: March 04, 2017, 08:43:08 am »
I know the obvious reason of the Human programmer making a mess, but is there a real reason?
Why shouldn't "not making a mess" be a real reason? That's probably the most siginificant reason as a professional.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf