Hi Folks!
Porting a library to a GNU Pascal Unit sometimes means putting a variable instead of a constant.
Like this:
foo.c: --------- int _c_konstant = DEFINED_CONSTANT_IN_C; ---------
foo.pas: ----------- unit Foo;
interface
{!! Treat them as constant !!} var Konstant: Integer; asmname '_c_konstant'; external;
implementation
{$L foo.c}
end. -----------
Doing it this way means a lack of using these "constants" in a "case" statement. It would be nice to have a feature like:
const Konstant = _c_konstant;
or similar.
Eike Lange wrote:
Porting a library to a GNU Pascal Unit sometimes means putting a variable instead of a constant.
Like this:
foo.c:
int _c_konstant = DEFINED_CONSTANT_IN_C;
Do you mean `const int _c_konstant ...'? Otherwise, it's not a constant in C.
foo.pas:
unit Foo;
interface
{!! Treat them as constant !!} var Konstant: Integer; asmname '_c_konstant'; external;
implementation
{$L foo.c}
end.
Doing it this way means a lack of using these "constants" in a "case" statement. It would be nice to have a feature like:
const Konstant = _c_konstant;
or similar.
Better similar. ;-) Your suggested syntax would put an asmname in the place where a value is expected if I understand it correctly. Furthermore, an untyped constant won't work because somehow the Pascal compiler must know the type.
So I'd favour something like
const Konstant: Integer; external; asmname '_c_konstant';
(i.e., mostly like a variable). But maybe also something like this would be better:
var Konstant: const Integer; external; asmname '_c_konstant';
This would probably require less syntax contortions. But in both cases, I'd have to check if it causes any parsing difficulties.
Frank
Frank Heckenbach wrote:
... snip ...
So I'd favour something like
const Konstant: Integer; external; asmname '_c_konstant';
(i.e., mostly like a variable). But maybe also something like this would be better:
var Konstant: const Integer; external; asmname '_c_konstant';
This would probably require less syntax contortions. But in both cases, I'd have to check if it causes any parsing difficulties.
I think it would be an impossibility. Think of something like:
CONST maxindex = 123;
TYPE anindex = 1..maxindex; myarray = array[anindex] OF whatever;
VAR array1, array2 : myarray;
and think about how you can test assignment compatability at compile time, let alone indexing range checks, if that constant can be external and defined at run-time.
I expect that:
x := array1[maxindex + 1];
should generate a compile time error.
If maxindex is a variable, then it can be external, but we can't declare the anindex and myarray types.
CBFalconer wrote:
Frank Heckenbach wrote:
... snip ...
So I'd favour something like
const Konstant: Integer; external; asmname '_c_konstant';
(i.e., mostly like a variable). But maybe also something like this would be better:
var Konstant: const Integer; external; asmname '_c_konstant';
This would probably require less syntax contortions. But in both cases, I'd have to check if it causes any parsing difficulties.
I think it would be an impossibility. Think of something like:
CONST maxindex = 123;
That's an untyped constant. That's another reason why we need a typed constant as I said. As far as you are concerned, typed constants don't exist (i.e., they're not defined in 7185), so you don't need to worry. ;-)
TYPE anindex = 1..maxindex; myarray = array[anindex] OF whatever;
VAR array1, array2 : myarray;
and think about how you can test assignment compatability at compile time,
Assignment compatibility (as far as I understand it) is no problem. array1 and array2 are of the same type and therefore compatible, and any other array type is not compatible. Remember that two identical looking structured type declarations are not compatible in Pascal, e.g.:
var a: array [1 .. 10] of Integer; b: array [1 .. 10] of Integer; [...] a := b { WRONG }
let alone indexing range checks, if that constant can be external and defined at run-time.
Then the range checks must be done at run-time as well (just like most other range checks).
I expect that: x := array1[maxindex + 1];
should generate a compile time error.
Yes, this would be nice and in principle possible I think, though also a run-time check would satisfy the requirements AFAIK.
In more complicated cases (e.g. `array1[2 * maxindex - 5]') one would need a run-time check, anyway (maxindex <= 5), and I also think that's alright then.
If maxindex is a variable, then it can be external, but we can't declare the anindex and myarray types.
Yes, we can (i.e., according to 10206). GPC currently doesn't allow it at global level (because it allocates static storage for global variables which is not suitable in these cases; we'll have to fix this sometime), but it does locally.
Frank
Frank Heckenbach wrote:
CBFalconer wrote:
Frank Heckenbach wrote:
... snip ...
So I'd favour something like
const Konstant: Integer; external; asmname '_c_konstant';
(i.e., mostly like a variable). But maybe also something like this would be better:
var Konstant: const Integer; external; asmname '_c_konstant';
This would probably require less syntax contortions. But in both cases, I'd have to check if it causes any parsing difficulties.
I think it would be an impossibility. Think of something like:
CONST maxindex = 123;
That's an untyped constant. That's another reason why we need a typed constant as I said. As far as you are concerned, typed constants don't exist (i.e., they're not defined in 7185), so you don't need to worry. ;-)
No, even in 7185 constants have a type. It is derived from their definition. The above would always be an integer constant. They are just not alterable a la TP.
realvar := maxindex; (* Would involve automatic conversion *) realvar := realvar * maxindex; (* involves same conversion *) charvar := maxindex; (* is an error *) charvar := chr(maxindex); (* is just fine *)
TYPE anindex = 1..maxindex; myarray = array[anindex] OF whatever;
VAR array1, array2 : myarray;
and think about how you can test assignment compatability at compile time,
Assignment compatibility (as far as I understand it) is no problem. array1 and array2 are of the same type and therefore compatible, and any other array type is not compatible. Remember that two identical looking structured type declarations are not compatible in Pascal, e.g.:
var a: array [1 .. 10] of Integer; b: array [1 .. 10] of Integer; [...] a := b { WRONG }
True, although I always forget that. Back in the days of the first standards there were long arguments about the definition of assignment compatibility. The other attack is that they are compatible if all their components are compatible (and declared in the same order for records).
let alone indexing range checks, if that constant can be external and defined at run-time.
Then the range checks must be done at run-time as well (just like most other range checks).
That is the area where efficiencies come up. The more that can be done at compile time the more efficient you can make the final program. Use of tight subranges helps. The compiler can often deduce the possible range, and skip the check. In the above, if the index variable is of type anindex, the compiler knows it is valid, and need generate no checking code. This sort of thing cuts the checking overhead down by a large factor.
I expect that: x := array1[maxindex + 1];
should generate a compile time error.
Yes, this would be nice and in principle possible I think, though also a run-time check would satisfy the requirements AFAIK.
Yes it would, but that involves making sure that code is exercized in testing. I hate the very idea.
In more complicated cases (e.g. `array1[2 * maxindex - 5]') one would need a run-time check, anyway (maxindex <= 5), and I also think that's alright then.
Same comment about making sure the code is exercized. I for one don't want to give up the warm fuzzy from compile time checks.
If maxindex is a variable, then it can be external, but we can't declare the anindex and myarray types.
Yes, we can (i.e., according to 10206). GPC currently doesn't allow it at global level (because it allocates static storage for global variables which is not suitable in these cases; we'll have to fix this sometime), but it does locally.
Boggles my mind. I tend to think about 'how do we verify this' rather than 'how do we implement this'.
CBFalconer wrote:
No, even in 7185 constants have a type. It is derived from their definition.
Yes, under "typed constants" I normally understand constants whose type is explicitly declared. EP knows this only for structured types, BP for any type, and the syntax is different, but that's not the main issue.
The above would always be an integer constant. They are just not alterable a la TP.
That's another issue (and I dislike it as much as you do). I assume here that the "external constants" are really constant and never altered by the Pascal code nor by the external code.
TYPE anindex = 1..maxindex; myarray = array[anindex] OF whatever;
VAR array1, array2 : myarray;
and think about how you can test assignment compatability at compile time,
Assignment compatibility (as far as I understand it) is no problem. array1 and array2 are of the same type and therefore compatible, and any other array type is not compatible. Remember that two identical looking structured type declarations are not compatible in Pascal, e.g.:
var a: array [1 .. 10] of Integer; b: array [1 .. 10] of Integer; [...] a := b { WRONG }
True, although I always forget that. Back in the days of the first standards there were long arguments about the definition of assignment compatibility. The other attack is that they are compatible if all their components are compatible (and declared in the same order for records).
I'm glad they chose the other route. Makes type-checking quite a bit easier and, more importantly, possible at compile-time, even in such complex situations.
That is the area where efficiencies come up. The more that can be done at compile time the more efficient you can make the final program. Use of tight subranges helps. The compiler can often deduce the possible range, and skip the check. In the above, if the index variable is of type anindex, the compiler knows it is valid, and need generate no checking code. This sort of thing cuts the checking overhead down by a large factor.
[...]
Yes it would, but that involves making sure that code is exercized in testing. I hate the very idea.
[...]
Same comment about making sure the code is exercized. I for one don't want to give up the warm fuzzy from compile time checks.
All true. Just don't use "external constants" then. I mean, they're not meant to replace ordinary constants, only for special situations where the alternative (having them as an external variable) would be even worse.
You basically lose all the advantages of doing things at compile-time when you use them, but you still keep the safety that some code doesn't accidentally modify the constant (unlike BP's "constants"!).
If maxindex is a variable, then it can be external, but we can't declare the anindex and myarray types.
Yes, we can (i.e., according to 10206). GPC currently doesn't allow it at global level (because it allocates static storage for global variables which is not suitable in these cases; we'll have to fix this sometime), but it does locally.
Boggles my mind. I tend to think about 'how do we verify this' rather than 'how do we implement this'.
AFAICS, the only thing we need (besides the range-checks done at runtime) is a check if the actual array size is positive (which GPC currently doesn't check, but should). Again, type compatibility should be rather easy thanks to the strict rules.
Frank
Frank Heckenbach wrote:
CBFalconer wrote:
... snip ...
Assignment compatibility (as far as I understand it) is no problem. array1 and array2 are of the same type and therefore compatible, and any other array type is not compatible. Remember that two identical looking structured type declarations are not compatible in Pascal, e.g.:
var a: array [1 .. 10] of Integer; b: array [1 .. 10] of Integer; [...] a := b { WRONG }
True, although I always forget that. Back in the days of the first standards there were long arguments about the definition of assignment compatibility. The other attack is that they are compatible if all their components are compatible (and declared in the same order for records).
I'm glad they chose the other route. Makes type-checking quite a bit easier and, more importantly, possible at compile-time, even in such complex situations.
PascalP (out of P4) took the compatible components route, and it was quite a simple recursive function, something like:
IF primitive THEN compatible := (t1 = t2) AND (t1.lim = t2.lim) ELSE IF arrt THEN compatible := compatible(t1.ixt, t2.ixt) AND compatible(t1.ct, t2.ct) ELSE IF rect THEN ...
CBFalconer wrote:
I'm glad they chose the other route. Makes type-checking quite a bit easier and, more importantly, possible at compile-time, even in such complex situations.
PascalP (out of P4) took the compatible components route, and it was quite a simple recursive function, something like:
IF primitive THEN compatible := (t1 = t2) AND (t1.lim = t2.lim) ELSE IF arrt THEN compatible := compatible(t1.ixt, t2.ixt) AND compatible(t1.ct, t2.ct) ELSE IF rect THEN ...
Yes, but if you apply this to dynamic types (conformant arrays, schemata, arrays declared with non-constant bounds), it will require runtime checks.
Frank