The Benefits of Constants
I understand one of the big deals about constants is that you don't have to go through and update code where that constant is used all over the place. Thats great, but let's say you don't explicitly declare it as a constant. What benefit(s) exist(s) to take a variable that HAPPENS to actually not be changed and make it a constant, will this save on processing, and/or size of 开发者_开发技巧code...etc?
Basically I have a program that the compiler is saying that a particular variable is not changed and thus can be declared a constant, I just wanted to know what the benefit to adding the constant qualifier to it would be, if it makes no difference then making that change adds no value and thus no point wasting time (this same scenario occurs in more then one place) going back and "fixing" all these variables.
If you declare a variable to be a constant, then the optimizer can often eliminate it via 'constant folding' and thus both speed up your program and save you space. As an example, consider this:
var int a = 5;
const int b = 7;
...
c = process(a*b);
The compiler will end up creating an instruction to multiply a by 7, and pass that to 'process', storing the results in c. However in this case:
const int a = 5;
const int b = 7;
...
c = process(a*b);
The compiler will simply pass 35 to process, and not even code the multiply. In addition, if the compiler knows that process has no side effects (ie, is a simple calculation) then it won't even call process. It will just set c to be the return value of process(35), saving you a function call.
If you declare something as a constant, and then accidentally attempt to modify its value in your code, the compiler will tell you about your mistake. This form of static type checking is actually the main reason for using constants.
A lot of this depends on how good your optimizer is.
A good optimizer will replace const references with literal values during compilation. This saves processor cycles since the generated machine code is working with immediate values instead of having to load a value from memory.
Some optimizers will recognize that a value is not modified after it is declared, and convert it to a constant for you. Do not rely on this behavior.
Also, whenever possible, your code should enforce the assumptions you've made during development. If a "variable" should never be changed, declaring it as a constant will help ensure that neither yourself nor any other developers that come along later will unwittingly modify a "constant".
Marking a variable as constant declares your intent as a programmer that this will be a consistent value whenever it's accessed during the execution of the code. Consider it a form of documentation that also causes the compiler to enfore your design.
As you point out, you may not gain any direct benefit from changing the unchanging variables into explicit constants. However, in analysing a program one check that is made is to look at the point of declaration of a variable to the point of reference of the variable. So metrics such as variables that are being accessed before declaration, or set and reset before reference etc can indicate probably bugs.
By explicitly declaring constants as constants the compiler and analysis tools know that you do not intend to reset the variable at any time.
This is also true for other developers that work with your code. They may inadvertently set a variable and you may not be aware of it. Declaring constants will avoid these types of errors.
It's possible that the compiler could reduce code size .. for example, in package System
you'll find (on an x86 machine)
type Bit_Order is (High_Order_First, Low_Order_First);
Default_Bit_Order : constant Bit_Order := Low_Order_First;
so that given
case System.Default_Bit_Order is
when System.High_Order_First =>
-- Big-endian processing
when System.Low_Order_First =>
-- Little-endian processing
end case;
the compiler can completely eliminate the 'wrong' branch while your code retains its portability. With GNAT you need to use non-default optimisation for this to happen: -O2
I think.
Both branches have to be compilable -- this is an optimisation, not #ifdef
processing.
One benefit is that if it is truly a constant value, you wouldn't accidentally change it. The constant keeps you from screwing stuff up later. As a variable, anyone could come along and change it later when updating the code.
It should be clear which values can never change and which values can change. Constants reinforce your intention.
Real world example from my youth:
We didn't have a built-in PI value on a system I was working on so someone created a VARIABLE called PI and somewhere along the way, someone (me) modified that value to 3.14519 (or something there abouts) in a procedure I wrote... not the approximation of pi 3.14159). It had been set elsewhere in the code, and all sorts of calculations were off from that point forward. Had that PI been a constant (it was changed later, of course), I wouldn't have been able to make that error... at least not easily.
In addition to whatever has been already said, declaring the variable as a constant gives more freedom for the optimizer. It can eliminate reading its values, it can eliminate need to create a temporary copy, it can eliminate the variable itself (this is especially true for the numeric constants).
Another big use case for the constants is constant objects. Having a constant object (or giving away a reference to a constant object in a function) you can be sure your object is not modified, and only methods (called const
methods) of that object are allowed to be called. This is however true for C++, I am not sure if the same concept is valid in Ada as well.
Another possibility, depending on the language, is that the compiler may be able to do some optimizations in a multi-threading environment that would not otherwise be possible. Like if you say:
int b=x*f;
int c=y*f;
In a multi-threaded environment, if f is a variable, the compiler may have to generate a reload of f before the second operation. If f is a constant and the compiler knows it's still in the register, it wouldn't need to reload.
Certainly for a language like C and Ada, the compiler will put the value from the constant directly into the assembler instruction, meaning that no swapping of registers or reading from memory will be necessary over and above what is required to run the program. This means two things: the main one is speed (probably not so noticeably in many applications, unless they are embedded) and the second is memory usage (of both the program's final binary size and its runtime memory footprint).
This behaviour will come down to the language and the compiler, as the language will dictate any assumptions made by you (the programmer) and therefore the constraints to the efficiency of the language; and the compiler because its behaviour could change from treating your constant like any other variable to pre-processing your code and optimising the binary speed and footprint as much as possible.
Secondly, as was stated by itsmatt and jball, it enables you to logically consider the item as a constant configuration item rather than a 'variable'; especially in higher level programming languages and interpreted languages.
There is another benefit, stack and data segment sizes.
Consider:
function Recurser(i : Integer) return Integer is
ia : array(0..9) of Integer
:= (1, 2, 3, 4, 5, 6, 7, 8, 9, 1000);
r : Integer;
begin
if i = 0 then return 0; end if;
r := ia(i mod 10);
return r + Recurser(i - 1);
end;
Every time that function recurses you create a 320 byte structure on the Stack. But since the value of a doesn't change the stack is increasing to hold a variable that is constant. This can be very important on embedded platforms with small stacks.
Package level variables also increase the size of the data segment. Pushing up your memory requirements.
This isn't really an Ada-specific question.
The general benifits of constants over variables:
- Prevents code errors from "constant" accidentally getting modified.
- Informs the compiler that it can assume the value will not change when optimizing.
Ada specific benifits:
- For numeric constants, you don't have to specify a type (named numbers). If you declare it this way, it will be usable in any expression for that kind of number. If you use a variable instead, it can only be used in expressions of that variable's exact type.
Example:
Seconds_Per_Minute : constant := 60;
Secs_Per_Min : Integer := 60;
type Seconds_Offset is 0 .. Integer'last; --'
Min1, Secs1 : Integer;
Min2, Secs2 : Seconds_Offset;
...
--// Using the named number, both of these compile no problem.
Secs1 := Min1 * Seconds_Per_Minute;
Secs2 := Min2 * Seconds_Per_Minute;
--// The second line here gives an error, since Integer is a
--// different type than Seconds_Offset.
Secs1 := Min1 * Secs_Per_Min;
Secs2 := Min2 * Secs_Per_Min;
Constants are usually stored in Read Only Memory, which prevents changing them during the execution and accessing them might be faster, or at least as fast as accessing RAM.
Constants are immutable values which are known at compile time and do not change for the life of the program.
Constants differ from variables in one significant way in that once a value has been assigned to a constant it cannot subsequently be changed.
At runtime you can be sure that the value defined in a constant won't change and consequently your program won't break.
精彩评论