This question already has an answer here:
- How do you initialise a const array of TGUID from Interface type data, in Delphi? 7 answers
I have KnownFolderPath IDs declared as consts:
I want to define an ordered list of folder ids at compile time. I know I can do the following:
But this is not convenient maintainable code so I would like to rather use the names defined before. But this gives me compiler errors in Delphi XE3 (const expression expected):
I could define the FOLDERIDs as const strings like
but than I would have to convert the ids with StringToGUID()
everywehere in the code. Isn't it somehow possible to define an ordered static / const list of const objects before runtime in Delphi?
marked as duplicate by Disillusioned, David Heffernan delphiJan 31 '17 at 16:05
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
2 Answers
In order to use the ID constants by name in the array declaration, you need to remove the TGuid
type from the ID constant declarations, making them 'True constants' instead of 'Typed constants':
This is covered in Embarcadero's documentation:
True Constants
A true constant is a declared identifier whose value cannot change. For example:
declares a constant called MaxValue
that returns the integer 237. The syntax for declaring a true constant is:
where identifier
is any valid identifier and constantExpression
is an expression that the compiler can evaluate without executing your program.
..
Constant Expressions
A constant expression is an expression that the compiler can evaluate without executing the program in which it occurs. Constant expressions include numerals; character strings; true constants; values of enumerated types; the special constants True
, False
, and nil
; and expressions built exclusively from these elements with operators, typecasts, and set constructors.
..
Typed Constants
Typed constants, unlike true constants, can hold values of array, record, procedural, and pointer types. Typed constants cannot occur in constant expressions.
..
Array Constants
To declare an array constant, enclose the values of the elements of the array, separated by commas, in parentheses at the end of the declaration. These values must be represented by constant expressions.
It is often useful to declare typed constants as well, which you can do without repeating the values, eg:
Alternatively, so the TGuid
typed constants can match the Win32 API naming scheme:
Sadly the answer appears to be no. You an do the following
but then you would need to assign like this
Not sure if that is acceptable. You could put a class wrapper around it if you wish.
Not the answer you're looking for? Browse other questions tagged arrayslistdelphiconst or ask your own question.
A most common construct in a Delphi application would be a procedure or a function. Known as routines, procedures or functions are statement blocks you call from different locations in a program.
Simply put a procedure is a routine not returning a value while a function returns a value.
A return value from a function is defined by the return type. In most cases you would write a function to return a single value that would be an integer, string, boolean or some other simple type, also return types could be an array, a string list, an instance of a custom object or alike.
Note that even if your function returns a string list (a collection of strings) it still returns a single value: one instance of the string list.
Further, Delphi routines can really have many faces: Routine, Method, Method Pointer, Event Delegate, Anonymous method..
Can a Function Return Multiple Values?
The first answer that comes to mind is no, simply because when we think of a function, we think of a single return value.
Certainly, the answer to the above question is, however, yes. A function can return several values. Let's see how.
Var Parameters
How many values can the following function return, one or two?
Delphi Array Bound
The function obviously returns a boolean value (true or false). How about the second parameter 'valueOut' declared as a 'VAR' (variable) parameter?
Var parameters are passed to the function by reference meaning that if the function changes the value of the parameter—a variable in the calling block of code—the function will change the value of the variable used for the parameter.
To see how the above works, here's the implementation:
The 'valueIn' is passed as a constant parameter—function cannot alter it, and it is treated as read-only.
If 'valueIn' or greater than zero, the 'valueOut' parameter is assigned the reciprocal value of 'valueIn' and the result of the function is true. If valueIn is <= 0 then the function returns false and 'valueOut' is not altered in any way.
Here's the usage:
Therefore, the PositiveReciprocal actually can 'return' 2 values! Using var parameters you can have a routine return more than one value.
Out Parameters
There's another way to specify a by-reference parameter—using the 'out' keyword, as in:
The implementation of PositiveReciprocalOut is the same as in PositiveReciprocal, there's only one difference: the 'valueOut' is an OUT parameter.
With parameters declared as 'out', the initial value of the referenced variable 'valueOut' is discarded.
Here's the usage and the results:
Note how in the second call the value of the local variable 'r' is set to '0'. The value of 'r' was set to 5 before the function call but since the parameter in declared as 'out,' when 'r' reached the function the value was discarded and the default 'empty' value was set for the parameter (0 for real type).
As a result, you can safely send uninitialized variables for out parameters—something that you should not do with 'var' parameters. Parameters are used to send something to the routine, except here with 'out' parameters :), and therefore uninitialized variables (used for VAR parameters) could have weird values.
Returning Records?
The above implementations where a function would return more than one value are not nice. The function actually returns a single value, but also returns, better to say alters, the values of the var/out parameters.
Fairy tail season 3 dubbed. Because of this, you may very rarely want to use by-reference parameters. If more results from a function are required, you can have a function return a record type variable.
Consider the following:
and a hypothetical function:
The function WhereAmI would return the Latitude and Longitude for a given town (city, area, ..).
The implementation would be:
And here we have a function returning 2 real values. Ok, it does return 1 record, but this record has 2 fields. Note that you can have a very complex record mixing various types to be returned as a result of a function.
That's it. Therefore, yes, Delphi functions can return multiple values.
This is a tough one for VCL and inline assembly gurus.I need to dynamically create the Value parameter to pass to the Format function. (Or rewrite Format's existing functionality - ugh)
Review of common knowledge:
Format has the following declaration:
Function Format (const aFormat: String; const values: array of const);
Problem:
The desired functionality is along the lines of:
function TMyRule.ResultString (fmt: String): String;
begin
Params := BuildParams;
aString := Format (fmt, Params);
end;
I have determined that the array of const is implemented as an array of TVarRec's. I am uncertain about whether it is actually a variant array or not. Either way, I can build it. Any input?
BUT .. there is no syntactic model to pass the created array to the function. The Pascal syntax only allows the array to be compiled in.
A review of the format function in SysUtils.pas suggests that it should be possible to write the call with an inline assembly call. This is the real meat of the problem.
Editing my Question.
I'll be specific.
How can I declare the code below as const
instead of var
?(I couldn't get Cube example)
2 Answers
The specific problem in your code is that the array you are declaring is dynamic. That is, the bounds are not fixed and can be changed at run-time.
In older versions of Delphi (XE6 and earlier) is it simply not possible to declare dynamic array constants. In XE7 and later it is possible but the syntax is different than for fixed array constants.
In all versions, if you declare a constant array with specified (and therefore fixed) bounds you can then specify the contents of the constant array thus:
If your array needs to be dynamic in a version of Delphi earlier than XE6 then you cannot initialise such an array with a declaration like this.
If you are using Delphi XE7 or later, then you can use the alternate syntax for declaring a dynamic array constant. This is very similar to the syntax for a fixed array constant but uses square braces []
instead of regular parentheses ()
:
Hybrid Solution for Older Delphi Versions
If you are using an older version of Delphi then even with a dynamic array, if you have some initial state (bounds and content) that you would like to initialise it with then you could use a fixed array constant to define that initial state and then initialise your dynamic array at run-time from that constant, something like:
The documentation shows how to declare constant arrays
Array Constants
To declare an array constant, enclose the values of the elements of the array, separated by commas, in parentheses at the end of the declaration. These values must be represented by constant expressions. For example:
declares a typed constant called Digits that holds an array of characters.
To define a multidimensional array constant, enclose the values of each dimension in a separate set of parentheses, separated by commas. For example:
creates an array called Maze where:
These examples are for one dimensional and three dimensional arrays. For a two dimensional array it would be: