Hi Folks!
The following program fails to compile:
program Foo;
var Integer: Integer = 2; Real: Integer = 3 ; { this works: Real, Integer: Integer = 3; }
begin Integer := Real; Real := Integer end.
Btw: using the decalaration as given in the comment works.
Eike
This is NOT a bug. The compiler is correct.
It is exactly as it should be. In the first declaration, you redefine 'Integer' to be a variable, not a type. Then when you reach the second one (for 'Real'), Integer is no longer a type, and you get an error.
In your second form, 'Integer' is still a type, since both variables are being defined simultaniously. Therefore that one works.
Question: Why would you want to do this anyway? It is confusing.
If I were writing a Pascal compiler, I would be tempted to make some of these identifiers into keywords, for this very reason. Of course, then I would not meet the Pascal standards...
--- Eike Lange eike.lange@uni-essen.de wrote:
Hi Folks!
The following program fails to compile:
program Foo;
var Integer: Integer = 2; Real: Integer = 3 ; { this works: Real, Integer: Integer = 3; }
begin Integer := Real; Real := Integer end.
Btw: using the decalaration as given in the comment works.
Eike
===== ======= Frank D. Engel, Jr.
__________________________________________________ Do you Yahoo!? Yahoo! Mail Plus - Powerful. Affordable. Sign up now. http://mailplus.yahoo.com
Hi!
On Wed, Dec 04, 2002 at 05:56:09AM -0800, Frank D. Engel, Jr. wrote:
It is exactly as it should be. In the first declaration, you redefine 'Integer' to be a variable, not a type. Then when you reach the second one (for 'Real'), Integer is no longer a type, and you get an error. In your second form, 'Integer' is still a type, since both variables are being defined simultaniously. Therefore that one works.
I ever thought, that all things right of the colon must be types. Therfore, my example is right. A redifinition of a type is IMO of the following form:
type Integer = Cardinal (7);
Where var Integer: Integer; defines a vaiable called "Integer" of type Integer, which is completly different.
Question: Why would you want to do this anyway? It is confusing.
I just wanted to test this feature. Never thought of using it in "real programs", but it should be possible.
I really should read the standards... But this way, I'm learning Pascal.
Eike
Eike Lange wrote:
On Wed, Dec 04, 2002 at 05:56:09AM -0800, Frank D. Engel, Jr. wrote:
It is exactly as it should be. In the first declaration, you redefine 'Integer' to be a variable, not a type. Then when you reach the second one (for 'Real'), Integer is no longer a type, and you get an error. In your second form, 'Integer' is still a type, since both variables are being defined simultaniously. Therefore that one works.
I ever thought, that all things right of the colon must be types. Therfore, my example is right. A redifinition of a type is IMO of the following form:
type Integer = Cardinal (7);
Where var Integer: Integer; defines a vaiable called "Integer" of type Integer, which is completly different.
Question: Why would you want to do this anyway? It is confusing.
I just wanted to test this feature. Never thought of using it in "real programs", but it should be possible.
Maybe you had the idea that an identifier could have different meanings as a type and a variable at the same time. That's not so. In Pascal, an identifier can have (at most ;-) one meaning in a scope, so when it's declared as a variable, the type declaration is "shadowed".
In your second form, 'Integer' is still a type, since both variables are being defined simultaniously. Therefore that one works.
Actually, I'm not sure. I'd have to check the standards again, but ISTR that an identifier cannot in one scope be used with an outer-scope meaning and be redefined. So if I'm not mistaken, GPC is not correct -- the second example should also fail. (But this might be harder to fix ... one might have to flag each identifier which is used in the current scope, so a later redeclaration in the same scope could be recognized as erroneous ...)
If I were writing a Pascal compiler, I would be tempted to make some of these identifiers into keywords, for this very reason. Of course, then I would not meet the Pascal standards...
Well, I wouldn't try this. We have enough problems with actual keywords from different standards/dialects (most prominently proably `value' which is a keyword in EP, but is often used as an identifier otherwise).
And if you think noone would ever want to redefine `Integer' ... well, for very strict BP compatiblity we even have to do this (define it as a 16 bit type, though only in the `System' unit with a special conditional) ...
Frank
Frank Heckenbach wrote:
Eike Lange wrote:
Frank D. Engel, Jr. wrote:
... snip ...
If I were writing a Pascal compiler, I would be tempted to make some of these identifiers into keywords, for this very reason. Of course, then I would not meet the Pascal standards...
Well, I wouldn't try this. We have enough problems with actual keywords from different standards/dialects (most prominently proably `value' which is a keyword in EP, but is often used as an identifier otherwise).
And if you think noone would ever want to redefine `Integer' ... well, for very strict BP compatiblity we even have to do this (define it as a 16 bit type, though only in the `System' unit with a special conditional) ...
Since 'integer' is pre-defined in the encompassing level 0 block (outside the global declarations) it is perfectly legal to redefine it. Thus if you want to ensure your code ports to a 16 bit system you might write:
PROGRAM whatever(...);
CONST maxint = 32767; (* redefine *) minint = -32768;
TYPE integer = minint .. maxint; (* redefine *) ...
and away you go! These are NOT reserved words.
On Thu, Dec 05, 2002 at 05:12:49AM +0100, Frank Heckenbach wrote:
Eike Lange wrote:
On Wed, Dec 04, 2002 at 05:56:09AM -0800, Frank D. Engel, Jr. wrote:
It is exactly as it should be. In the first declaration, you redefine 'Integer' to be a variable, not a type. Then when you reach the second one (for 'Real'), Integer is no longer a type, and you get an error. In your second form, 'Integer' is still a type, since both variables are being defined simultaniously. Therefore that one works.
I ever thought, that all things right of the colon must be types. Therfore, my example is right. A redifinition of a type is IMO of the following form:
type Integer = Cardinal (7);
Where var Integer: Integer; defines a vaiable called "Integer" of type Integer, which is completly different.
Question: Why would you want to do this anyway? It is confusing.
I just wanted to test this feature. Never thought of using it in "real programs", but it should be possible.
Maybe you had the idea that an identifier could have different meanings as a type and a variable at the same time. That's not so. In Pascal, an identifier can have (at most ;-) one meaning in a scope, so when it's declared as a variable, the type declaration is "shadowed".
In your second form, 'Integer' is still a type, since both variables are being defined simultaniously. Therefore that one works.
Actually, I'm not sure. I'd have to check the standards again, but ISTR that an identifier cannot in one scope be used with an outer-scope meaning and be redefined. So if I'm not mistaken, GPC is
Indeed. Here are the relevant sections of the standard:
6.2.2.4
The scope of each defining-point shall be its region(s) (including all regions enclosed by those regions) subject to 6.2.2.5 and 6.2.2.6.
6.2.2.5
When an identifier or label has a defining-point for region A and another identifier or label having the same spelling has a defining-point for some region B enclosed by A, then region B and all regions enclosed by B shall be excluded from the scope of the defining-point for region A.
6.2.2.8
Within the scope of a defining-point of an identifier or label, each occurrence of an identifier or label having the same spelling as the identifier or label of the defining-point shall be designated an applied occurrence of the identifier or label of the defining-point, except for an occurrence that constituted the defining-point; such an occurrence shall be designated a defining occurrence. No occurrence outside that scope shall be an applied occurrence.
6.2.2.10
Required identifiers that denote the required values, types, schemata, procedures, and functions shall be used as if their defining-points have a region enclosing the program (see 6.1.3, 6.4.2.2, 6.4.3.4, 6.4.3.6, 6.4.3.3.3, 6.7.5, 6.7.6, and 6.10).
6.2.2.11
Whatever an identifier or label denotes at its defining-point shall be denoted at all applied occurrences of that identifier or label.
6.4.1 Type-definitions
[...]
The occurrence of an identifier in a type-definition of a type-definition-part of a block, a module-heading, or a module-block shall constitute its defining-point for the region that is the block, the module-heading, or the module-block. Each applied occurrence of that identifier shall be a type-identifier. [...]
6.5.1 Variable-declarations
[...]
The occurrence of an identifier in the identifier-list of a variable-declaration of the variable-declaration-part of a block, a module-heading, or a module-block shall constitute its defining-point for the region that is the block, the module-heading, or the module-block, respectively. [...]
So, following these rules,
var Integer: Integer;
is invalid: "Integer" denotes a variable in the whole block containing this declaration, and in particular, on the right-hand side of this declaration, where a type-name is expected instead.
not correct -- the second example should also fail. (But this might be harder to fix ... one might have to flag each identifier which is used in the current scope, so a later redeclaration in the same scope could be recognized as erroneous ...)
If I were writing a Pascal compiler, I would be tempted to make some of these identifiers into keywords, for this very reason. Of course, then I would not meet the Pascal standards...
Well, I wouldn't try this. We have enough problems with actual keywords from different standards/dialects (most prominently proably `value' which is a keyword in EP, but is often used as an identifier otherwise).
And if you think noone would ever want to redefine `Integer' ... well, for very strict BP compatiblity we even have to do this (define it as a 16 bit type, though only in the `System' unit with a special conditional) ...
The way it is done in the System unit is invalid as well :-)
type
Integer = Integer (16);
As above, this should mean an attempt to make a circular definition. (Of course, the System unit is full of nonstandard features anyway, so this is not a real problem.)
Emil
On 6 Dec 2002 at 14:29, Emil Jerabek wrote:
[...]
And if you think noone would ever want to redefine `Integer' ... well, for very strict BP compatiblity we even have to do this (define it as a 16 bit type, though only in the `System' unit with a special conditional) ...
The way it is done in the System unit is invalid as well :-)
type
Integer = Integer (16);
As above, this should mean an attempt to make a circular definition. (Of course, the System unit is full of nonstandard features anyway, so this is not a real problem.)
No. Indeed, any "unit" is non-standard by definition, since, IIUIC, neither 7185 nor 10206 understand the concept of a "unit". Therefore anyone who wants to be standards-compliant would stay well away from any source file that describes itself as a "unit".
Best regards, The Chief --------- Prof. Abimbola Olowofoyeku (The African Chief) Web: http://www.bigfoot.com/~african_chief/
CBFalconer wrote:
Frank Heckenbach wrote:
Well, I wouldn't try this. We have enough problems with actual keywords from different standards/dialects (most prominently proably `value' which is a keyword in EP, but is often used as an identifier otherwise).
And if you think noone would ever want to redefine `Integer' ... well, for very strict BP compatiblity we even have to do this (define it as a 16 bit type, though only in the `System' unit with a special conditional) ...
Since 'integer' is pre-defined in the encompassing level 0 block (outside the global declarations) it is perfectly legal to redefine it.
Of course, it is. I was only addressing the question why someone might want to do so.
Thus if you want to ensure your code ports to a 16 bit system you might write:
PROGRAM whatever(...);
CONST maxint = 32767; (* redefine *) minint = -32768; TYPE integer = minint .. maxint; (* redefine *)
...
and away you go! These are NOT reserved words.
To be pedantic, you might want to write `MinInt = -MaxInt;' since the standard demands a symmetric range of Integer.
However, in GPC that's not exactly the same as `Integer (16)'. A subrange would still be a type of the same size as `Integer' (usually 32 bits) which is generally preferable for performance reasons, while strict BP compatibility sometimes requires a 16 bit type because some BP code relies on record layout etc.
Frank
Emil Jerabek wrote:
On Thu, Dec 05, 2002 at 05:12:49AM +0100, Frank Heckenbach wrote:
In your second form, 'Integer' is still a type, since both variables are being defined simultaniously. Therefore that one works.
Actually, I'm not sure. I'd have to check the standards again, but ISTR that an identifier cannot in one scope be used with an outer-scope meaning and be redefined. So if I'm not mistaken, GPC is
Indeed. Here are the relevant sections of the standard:
[...]
So, following these rules,
var Integer: Integer;
is invalid: "Integer" denotes a variable in the whole block containing this declaration, and in particular, on the right-hand side of this declaration, where a type-name is expected instead.
Yep. Thanks for confirming with the standard quotes.
And if you think noone would ever want to redefine `Integer' ... well, for very strict BP compatiblity we even have to do this (define it as a 16 bit type, though only in the `System' unit with a special conditional) ...
The way it is done in the System unit is invalid as well :-)
type
Integer = Integer (16);
As above, this should mean an attempt to make a circular definition. (Of course, the System unit is full of nonstandard features anyway, so this is not a real problem.)
Prof. A Olowofoyeku (The African Chief) wrote:
No. Indeed, any "unit" is non-standard by definition, since, IIUIC, neither 7185 nor 10206 understand the concept of a "unit". Therefore anyone who wants to be standards-compliant would stay well away from any source file that describes itself as a "unit".
(True, though substituting a module for the unit would make no difference WRT the other issues here.)
In fact, `Integer (16)' is non-standard already. (Is this a competition who finds the most basic non-standard usage in this statement? ;-)
Now, seeing this, I'm starting to doubt whether this syntax is useful. AFAICS, there is no easy and clean way to achieve what's wanted here. The following would be just as wrong, of course:
type Int16 = Integer (16); Integer = Int16;
The only way out might be to define Int16 in another module (here probably in the GPC module) and use it in the System unit.
For this reason (and also because `Integer (16)' is a little ambiguous, it can mean a BP-style type-cast in other contexts), I suggest to change the syntax. (IIRC, it was me who suggested it originally, so I can change it, can't I? ;-)
I guess it will affect some low-level units/modules (those that come with GPC which I'll change accordingly, of course, and maybe some of other's projects), hopefully not too many ...
Currently, we have:
Integer (n) Cardinal (n) Word (n) Boolean (n)
This could be changeg, e.g., to:
TypeOfSize (Integer, n) TypeOfSize (Word, n) TypeOfSize (Cardinal, n) TypeOfSize (Boolean, n)
This way, there would be only one new syntax, clearly distinguished from other types, and it would be extensible (e.g., someone suggested something similar for floating point types; it will probably be a little different internally and might require more parameters, but they can then fit within the parentheses, not to be confused with any other types).
Any opinions on this? (Again, all of this is meant to be used only in special situations and at the lowest possible level. Any code that uses such declarations throughout would seem quite broken to me, so this feature is not meant to support any non-standard coding practices, but rather a "fine-tuning" of some types at a low level.)
Frank
On 11 Dec 2002 at 3:27, Frank Heckenbach wrote:
[...]
The way it is done in the System unit is invalid as well :-)
type
Integer = Integer (16);
As above, this should mean an attempt to make a circular definition. (Of course, the System unit is full of nonstandard features anyway, so this is not a real problem.)
Since it is already working, is there really a need to change it?
[...]
Now, seeing this, I'm starting to doubt whether this syntax is useful. AFAICS, there is no easy and clean way to achieve what's wanted here. The following would be just as wrong, of course:
type Int16 = Integer (16); Integer = Int16;
The only way out might be to define Int16 in another module (here probably in the GPC module) and use it in the System unit.
For this reason (and also because `Integer (16)' is a little ambiguous, it can mean a BP-style type-cast in other contexts), I suggest to change the syntax. (IIRC, it was me who suggested it originally, so I can change it, can't I? ;-)
Yes, you can - but I can't see the point. Anyone who wants to be standards-compliant will not use either the existing or the proposed new syntax. For other people, the existing syntax does the job. There is nothing ambiguous in "Type foo = integer (n)", because if it is used in a type declaration (and that is the only place that it can be used), then it is clearly not a BP-style type-cast.
I guess it will affect some low-level units/modules (those that come with GPC which I'll change accordingly, of course, and maybe some of other's projects), hopefully not too many ...
Currently, we have:
Integer (n) Cardinal (n) Word (n) Boolean (n)
This could be changeg, e.g., to:
TypeOfSize (Integer, n) TypeOfSize (Word, n) TypeOfSize (Cardinal, n) TypeOfSize (Boolean, n)
This is fine - as (IMHO) is the original one. Both are non-standard. The original has 2 advantages - it is already working and being used, and, it doesn't require a new identifier. The new one might be "clearer" (it isn't, IMHO) and might be more "Pascalish" (I don't understand how, but others might). But we are really talking of replacing one non-standard feature with another. I say, let sleeping dogs lie.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
Frank Heckenbach wrote:
CBFalconer wrote:
... snip ...
PROGRAM whatever(...);
CONST maxint = 32767; (* redefine *) minint = -32768; TYPE integer = minint .. maxint; (* redefine *)
...
and away you go! These are NOT reserved words.
To be pedantic, you might want to write `MinInt = -MaxInt;' since the standard demands a symmetric range of Integer.
However, in GPC that's not exactly the same as `Integer (16)'. A subrange would still be a type of the same size as `Integer' (usually 32 bits) which is generally preferable for performance reasons, while strict BP compatibility sometimes requires a 16 bit type because some BP code relies on record layout etc.
While there is nothing wrong with that practice, I was always under the impression that the system was allowed to reduce the storage requirements for a subrange to whatever was needed. Without range checking the result is extremely dangerous, of course.
This is one reason I see no purpose in extensions that supply other integral forms. Internal operations then remain on integers, only storage is affected. I guess an exception would have to be made for integral forms that can handle things larger than the system optimum integer, but that doesn't apply to gpc since, AFAIK, it doesn't have any integral forms larger than 32 bits.
On Wed, Dec 11, 2002 at 03:27:22AM +0100, Frank Heckenbach wrote: [...]
In fact, `Integer (16)' is non-standard already. (Is this a competition who finds the most basic non-standard usage in this statement? ;-)
Now, seeing this, I'm starting to doubt whether this syntax is useful. AFAICS, there is no easy and clean way to achieve what's wanted here. The following would be just as wrong, of course:
type Int16 = Integer (16); Integer = Int16;
The only way out might be to define Int16 in another module (here probably in the GPC module) and use it in the System unit.
If System were a module rather than unit, export renaming would do the job, IMHO:
export System = (Borland_Integer => Integer, ...)
...
type Borland_Integer = Integer (16);
Emil
On 11 Dec 2002 at 3:27, Frank Heckenbach wrote:
AFAICS, there is no easy and clean way to achieve what's wanted here. The following would be just as wrong, of course:
type Int16 = Integer (16); Integer = Int16;
Is there a semantic difference between:
type Int16 = Integer (16);
and:
type Int16 = packed -32768..32767;
That is, can the packed subrange form replace the specified-size form in all cases?
-- Dave
Prof A Olowofoyeku (The African Chief) wrote:
On 11 Dec 2002 at 3:27, Frank Heckenbach wrote:
[...]
The way it is done in the System unit is invalid as well :-)
type
Integer = Integer (16);
As above, this should mean an attempt to make a circular definition. (Of course, the System unit is full of nonstandard features anyway, so this is not a real problem.)
Since it is already working, is there really a need to change it?
As Emil pointed out, it's not really working (only due to another bug of GPC).
Yes, you can - but I can't see the point. Anyone who wants to be standards-compliant will not use either the existing or the proposed new syntax.
It's not really a question of standard-compliance, rather a plain bug. E.g., even BP doesn't allow this:
var Integer: Integer;
or this (which comes somewhat close to `Integer = Integer (16)'):
type Integer = record a: Integer end;
For other people, the existing syntax does the job. There is nothing ambiguous in "Type foo = integer (n)", because if it is used in a type declaration (and that is the only place that it can be used), then it is clearly not a BP-style type-cast.
There is a problem with the way the System unit redeclares `Integer'.
Besides, consider:
type foo = Integer (16) .. 18;
Here it can only be a type-cast. Though not really ambiguous, it's hard to parse because you need much lookahead to tell the two cases apart.
That's part of a bigger problem with expressions as lower subrange-bounds which is still unsolved (in fact, it's the biggest parsing problem in GPC currently). `Integer (n)' is not alone responsible for it, but it adds to it and will not make a solution easier.
This could be changeg, e.g., to:
TypeOfSize (Integer, n) TypeOfSize (Word, n) TypeOfSize (Cardinal, n) TypeOfSize (Boolean, n)
This is fine - as (IMHO) is the original one. Both are non-standard. The original has 2 advantages - it is already working and being used, and, it doesn't require a new identifier.
But an ambiguous (or at least context-dependent) meaning with four identifiers.
CBFalconer wrote:
However, in GPC that's not exactly the same as `Integer (16)'. A subrange would still be a type of the same size as `Integer' (usually 32 bits) which is generally preferable for performance reasons, while strict BP compatibility sometimes requires a 16 bit type because some BP code relies on record layout etc.
While there is nothing wrong with that practice, I was always under the impression that the system was allowed to reduce the storage requirements for a subrange to whatever was needed. Without range checking the result is extremely dangerous, of course.
Sure it's allowed to. But GPC choses not to do so for normal subranges. I think in most cases that's preferable since often subranges are not declared to reduce storage (at the cost of performance), but to declare proper array indices etc.
This is one reason I see no purpose in extensions that supply other integral forms. Internal operations then remain on integers, only storage is affected. I guess an exception would have to be made for integral forms that can handle things larger than the system optimum integer, but that doesn't apply to gpc since, AFAIK, it doesn't have any integral forms larger than 32 bits.
It has 64 bit integers (on 32 bit systems), but that's no problem here, since subranges that exceed the 32 bit integer range become subranges of a 64 bit integer type automatically.
Emil Jerabek wrote:
If System were a module rather than unit, export renaming would do the job, IMHO:
export System = (Borland_Integer => Integer, ...)
...
type Borland_Integer = Integer (16);
That might be an option. It should be no problem to turn System into a module (since both units and modules can be used like units or imported as modules, this doesn't break compatibility).
One disadvantage would be that one would have to list all exported identifiers in the `...' part. That quite redundant IMHO. Of course, that's generally so with modules, but I don't like this very much. GPC has the extension `export foo = all', but it doesn't allow for export renaming, so it wouldn't be usable here, or we add renaming to it -- something like
export foo = all (BP_Integer => Integer);
J. David Bryan wrote:
On 11 Dec 2002 at 3:27, Frank Heckenbach wrote:
AFAICS, there is no easy and clean way to achieve what's wanted here. The following would be just as wrong, of course:
type Int16 = Integer (16); Integer = Int16;
Is there a semantic difference between:
type Int16 = Integer (16);
and:
type Int16 = packed -32768..32767;
That is, can the packed subrange form replace the specified-size form in all cases?
Internally, they're handled differently, so I'd have to check carefully if both yield exactly the same types in the end (but if not, it can maybe be fixed).
If so, this might justify dropping `Integer/Cardinal/Word (n)' entirely.
However, `Boolean (n)' cannot be done this way. It may be used for interfaces to other languages. But I'm not sure how widespread it is. Maybe we should also drop it (along with `ShortBool' etc.), and use integer types instead (and explicit `<> 0' comparisons or so) ...
Frank
The Chief wrote:
The way it is done in the System unit is invalid as well :-)
type
Integer = Integer (16);
As above, this should mean an attempt to make a circular definition. (Of course, the System unit is full of nonstandard features anyway, so this is not a real problem.)
Since it is already working, is there really a need to change it?
As Emil pointed out, it's not really working (only due to another bug of GPC).
Yes, you can - but I can't see the point. Anyone who wants to be standards-compliant will not use either the existing or the proposed new syntax.
It's not really a question of standard-compliance, rather a plain bug. E.g., even BP doesn't allow this:
var Integer: Integer;
or this (which is somewhat similar to `Integer = Integer (16)'):
type Integer = record a: Integer end;
For other people, the existing syntax does the job. There is nothing ambiguous in "Type foo = integer (n)", because if it is used in a type declaration (and that is the only place that it can be used), then it is clearly not a BP-style type-cast.
There is a problem with the way the System unit redeclares `Integer'.
Besides, consider:
type foo = Integer (16) .. 18;
Here it can only be a type-cast. Though not really ambiguous, it's hard to parse because you need much lookahead to tell the two cases apart.
That's part of a bigger problem with expressions as lower subrange-bounds which is still unsolved (in fact, it's the biggest parsing problem in GPC currently). `Integer (n)' is not alone responsible for it, but it adds to it and will not make a solution easier.
This could be changeg, e.g., to:
TypeOfSize (Integer, n) TypeOfSize (Word, n) TypeOfSize (Cardinal, n) TypeOfSize (Boolean, n)
This is fine - as (IMHO) is the original one. Both are non-standard. The original has 2 advantages - it is already working and being used, and, it doesn't require a new identifier.
But an ambiguous (or at least context-dependent) meaning with four identifiers.
CBFalconer wrote:
However, in GPC that's not exactly the same as `Integer (16)'. A subrange would still be a type of the same size as `Integer' (usually 32 bits) which is generally preferable for performance reasons, while strict BP compatibility sometimes requires a 16 bit type because some BP code relies on record layout etc.
While there is nothing wrong with that practice, I was always under the impression that the system was allowed to reduce the storage requirements for a subrange to whatever was needed. Without range checking the result is extremely dangerous, of course.
Sure it's allowed to. But GPC choses not to do so for normal subranges. I think in most cases that's preferable since often subranges are not declared to reduce storage (at the cost of performance), but to declare proper array indices etc.
This is one reason I see no purpose in extensions that supply other integral forms. Internal operations then remain on integers, only storage is affected. I guess an exception would have to be made for integral forms that can handle things larger than the system optimum integer, but that doesn't apply to gpc since, AFAIK, it doesn't have any integral forms larger than 32 bits.
It has 64 bit integers (on 32 bit systems), but that's no problem here, since subranges that exceed the 32 bit integer range become subranges of a 64 bit integer type automatically.
Emil Jerabek wrote:
If System were a module rather than unit, export renaming would do the job, IMHO:
export System = (Borland_Integer => Integer, ...)
...
type Borland_Integer = Integer (16);
That might be an option. It should be no problem to turn System into a module (since both units and modules can be used like units or imported as modules, this doesn't break compatibility).
One disadvantage would be that one would have to list all exported identifiers in the `...' part. That quite redundant IMHO. Of course, that's generally so with modules, but I don't like this very much. GPC has the extension `export foo = all', but it doesn't allow for export renaming, so it wouldn't be usable here, or we add renaming to it -- something like
export foo = all (BP_Integer => Integer);
J. David Bryan wrote:
On 11 Dec 2002 at 3:27, Frank Heckenbach wrote:
AFAICS, there is no easy and clean way to achieve what's wanted here. The following would be just as wrong, of course:
type Int16 = Integer (16); Integer = Int16;
Is there a semantic difference between:
type Int16 = Integer (16);
and:
type Int16 = packed -32768..32767;
That is, can the packed subrange form replace the specified-size form in all cases?
Internally, they're handled differently, so I'd have to check carefully if both yield exactly the same types in the end (but if not, it can maybe be fixed).
If so, this might justify dropping `Integer/Cardinal/Word (n)' entirely.
However, `Boolean (n)' cannot be done this way. It may be used for interfaces to other languages. But I'm not sure how widespread it is. Maybe we should also drop it (along with `ShortBool' etc.), and use integer types instead (and explicit `<> 0' comparisons or so) ...
Frank
Frank Heckenbach wrote:
The Chief wrote:
... snip ...
Is there a semantic difference between:
type Int16 = Integer (16); and: type Int16 = packed -32768..32767;
That is, can the packed subrange form replace the specified-size form in all cases?
Internally, they're handled differently, so I'd have to check carefully if both yield exactly the same types in the end (but if not, it can maybe be fixed).
If so, this might justify dropping `Integer/Cardinal/Word (n)' entirely.
I like that solution. It is in the proper Pascal spirit, and not Cified. To me anything that cannot be cleanly parsed without one-char lookahead doesn't belong (with the usual 'else' proviso).
However, `Boolean (n)' cannot be done this way. It may be used for interfaces to other languages. But I'm not sure how widespread it is. Maybe we should also drop it (along with `ShortBool' etc.), and use integer types instead (and explicit `<> 0' comparisons or so) ...
What is this construct? You are aware that C99 has the _Bool reserved word, with stdbool.h to define 'bool' as _Bool, and values for true and false of 1 and 0? I think this is now a part of gcc.
CONST maxint = 32767; (* redefine *) minint = -32768;
To be pedantic, you might want to write `MinInt = -MaxInt;' since the standard demands a symmetric range of Integer.
Uh...
'-MaxInt' would imply -32767..32767, which wastes a potential stored value (and cannot accomidate interfacing with other languages, which do not have this restriction).
'-MinInt' would imply -32768 (yes, negative; run the negation in 2's compliment and you will see what I mean).
By 'symmetric,' do you mean that the Pascal standard actually calls for the INTEGER type to have the same negative range as positive?
===== ======= Frank D. Engel, Jr.
__________________________________________________ Do you Yahoo!? Yahoo! Mail Plus - Powerful. Affordable. Sign up now. http://mailplus.yahoo.com
Frank Heckenbach wrote:
However, in GPC that's not exactly the same as `Integer (16)'. A subrange would still be a type of the same size as `Integer' (usually 32 bits) which is generally preferable for performance reasons, while strict BP compatibility sometimes requires a 16 bit type because some BP code relies on record layout etc.
While there is nothing wrong with that practice, I was always under the impression that the system was allowed to reduce the storage requirements for a subrange to whatever was needed. Without range checking the result is extremely dangerous, of course.
Sure it's allowed to. But GPC choses not to do so for normal subranges. I think in most cases that's preferable since often subranges are not declared to reduce storage (at the cost of performance), but to declare proper array indices etc.
It is very debatable: AFAIKS gpc have no way to reduce storage requirements of standard-compliant code except if packing is used. Since packing involves breaking alignment rules it usually have big impact on performance. Reducing storage for subranges usually have very moderate impact on runtime and in realictic programs reduced memory usage may fully compensate for extensions and truncation (many benchmarks run in very small memory so they prefer bigger size). Promoting subranges to full size when handling expressions and temporaries (hard to do to full potential in current gpc) may give optimal performance, and I think such promotion should be done even if a subrange is packed
J. David Bryan wrote:
Is there a semantic difference between:
type Int16 = Integer (16);
and:
type Int16 = packed -32768..32767;
That is, can the packed subrange form replace the specified-size form in all cases?
In normal Pascal there should be no overflow, so compiler my better optimize the code ommiting truncation of intermediate expressions - IMHO the compiler is not doing it now, but I think it shoud have the right to optimize.
Frank Heckenbach wrote:
This could be changeg, e.g., to:
TypeOfSize (Integer, n)
I think better syntax would be:
type foo = Integer attribute(Size(n),...);
differences are: 1) attribute suggest much more general use (I think it could work for general extensions) 2) IMHO at the end of type it need to be only contextually reserved so someting like:
type attribute = Integer attribute(Size(5)); foo = attribute attribute(Volatile);
would work.
Frank D. Engel, Jr. wrote:
CONST maxint = 32767; (* redefine *) minint = -32768;
To be pedantic, you might want to write `MinInt = -MaxInt;' since the standard demands a symmetric range of Integer.
Uh...
'-MaxInt' would imply -32767..32767, which wastes a potential stored value
That's according to the Pascal standards.
(and cannot accomidate interfacing with other languages, which do not have this restriction).
Irrelevant here. Chuck suggested a way to make sure code worked with 16 bit compilers. Interfacing with other languages is compiler-unportable, anyway.
'-MinInt' would imply -32768 (yes, negative; run the negation in 2's compliment and you will see what I mean).
Nope. This is not C, talking of bit patterns, but Pascal, talking of values. `-MinInt' is either 32768 or (if that value can't be represented because you're working on 16 bit types) an error.
By 'symmetric,' do you mean that the Pascal standard actually calls for the INTEGER type to have the same negative range as positive?
EP, 6.4.2.2:
1) All integral values in the closed interval from Âmaxint to +maxint shall be values of the integerÂtype.
Well, that doesn't say that *only* those values are values of the integerÂtype (unless I've missed another part), but if you want to be compiler-portable, you can only assume what's demanded in the standard, not what may be allowed.
Frank
Waldek Hebisch wrote:
Sure it's allowed to. But GPC choses not to do so for normal subranges. I think in most cases that's preferable since often subranges are not declared to reduce storage (at the cost of performance), but to declare proper array indices etc.
It is very debatable: AFAIKS gpc have no way to reduce storage requirements of standard-compliant code except if packing is used. Since packing involves breaking alignment rules it usually have big impact on performance. Reducing storage for subranges usually have very moderate impact on runtime and in realictic programs reduced memory usage may fully compensate for extensions and truncation (many benchmarks run in very small memory so they prefer bigger size).
"packed subranges" as well as `Integer (n)' or `ShortInt' etc. (all non-standard, I know) should provide this, without breaking alignment (such as packed records and arrays would).
Frank Heckenbach wrote:
This could be changeg, e.g., to:
TypeOfSize (Integer, n)
I think better syntax would be:
type foo = Integer attribute(Size(n),...);
differences are:
- attribute suggest much more general use (I think it could
work for general extensions) 2) IMHO at the end of type it need to be only contextually reserved so someting like:
type attribute = Integer attribute(Size(5)); foo = attribute attribute(Volatile);
This might be a good idea. Actually, GPC allows `attribute' for variables already (though with a `;' before -- maybe it would be better to drop it if it doesn't cause problems), and it should be possible to also allow it for types.
Still, if it turns out that packed subranges are suitable, do we need this at all?
Frank
CBFalconer wrote:
That is, can the packed subrange form replace the specified-size form in all cases?
Internally, they're handled differently, so I'd have to check carefully if both yield exactly the same types in the end (but if not, it can maybe be fixed).
If so, this might justify dropping `Integer/Cardinal/Word (n)' entirely.
I like that solution. It is in the proper Pascal spirit, and not Cified. To me anything that cannot be cleanly parsed without one-char lookahead doesn't belong (with the usual 'else' proviso).
Unfortunately, that's already not the case in EP:
const a = 1;
procedure P; type Foo = (a); begin end;
procedure Q; type Foo = (a) .. 3; begin end;
So you need 3 tokens lookahead (and arbitrarily many chars, since the identifier `a' could be longer, not to mention whitespace), or some tricks (such as parsing `"(" identifier ")"' as a special construct and deciding later whether it's a single-valued enum type or a parenthesized expression).
However, `Boolean (n)' cannot be done this way. It may be used for interfaces to other languages. But I'm not sure how widespread it is. Maybe we should also drop it (along with `ShortBool' etc.), and use integer types instead (and explicit `<> 0' comparisons or so) ...
What is this construct? You are aware that C99 has the _Bool reserved word, with stdbool.h to define 'bool' as _Bool, and values for true and false of 1 and 0? I think this is now a part of gcc.
The construct is to define a Boolean type which has a certain size. Many C interfaces just use `int' for Boolean values, some (especially in tight structs) also `short' or `char' or whatever. (Maybe this will change in the future, but I think many C programmers are somewhat conservative in requiring newer standards.) So, in GPC you can use `WordBool' to interface to a C type `int' which is used as a Boolean in C.
BTW, I'm adding `CBoolean' in GPC now (that's rather harmless, just another predefined identifier which no maigc properties), to be compatible with C's `_Bool' (but as a Pascal Boolean type).
Frank
On 12 Dec 2002 at 16:28, Frank Heckenbach wrote:
Waldek Hebisch wrote:
[...]
I think better syntax would be:
type foo = Integer attribute(Size(n),...);
differences are:
- attribute suggest much more general use (I think it could
work for general extensions) 2) IMHO at the end of type it need to be only contextually reserved so someting like:
type attribute = Integer attribute(Size(5)); foo = attribute attribute(Volatile);
This might be a good idea. Actually, GPC allows `attribute' for variables already (though with a `;' before -- maybe it would be better to drop it if it doesn't cause problems), and it should be possible to also allow it for types.
I must confess that I still cannot understand why any of this is a "better" solution than leaving things the way they are. How does the above advance the situation over a simple "type foo=Integer (n)"?
Best regards, The Chief --------- Prof. Abimbola Olowofoyeku (The African Chief) Web: http://www.bigfoot.com/~african_chief/
On 12 Dec 2002 at 16:37, Frank Heckenbach wrote:
[...]
The construct is to define a Boolean type which has a certain size. Many C interfaces just use `int' for Boolean values, some (especially in tight structs) also `short' or `char' or whatever. (Maybe this will change in the future, but I think many C programmers are somewhat conservative in requiring newer standards.) So, in GPC you can use `WordBool' to interface to a C type `int' which is used as a Boolean in C.
BTW, I'm adding `CBoolean' in GPC now (that's rather harmless, just another predefined identifier which no maigc properties), to be compatible with C's `_Bool' (but as a Pascal Boolean type).
This is fine. But please let us retain the ability to specify sizes for data types. People often have to read files created by other applications and sometimes require data structures of specific sizes, and it should be possible to create a data structure of that size without too many contortions.
Best regards, The Chief --------- Prof. Abimbola Olowofoyeku (The African Chief) Web: http://www.bigfoot.com/~african_chief/
On 12 Dec 2002 at 2:27, Frank Heckenbach wrote:
If so, this might justify dropping `Integer/Cardinal/Word (n)' entirely.
That was my thought. If "Integer (n)" is simply a syntactic convenience for "packed -(2 pow (n - 1)) .. 2 pow (n - 1) - 1", then no functionality is lost by dropping the "Integer (n)" form, and it fixes a few problems at the same time.
However, `Boolean (n)' cannot be done this way. It may be used for interfaces to other languages.
I acknowledge that it is helpful to have foreign (e.g., C) semantics for interfacing. But is there any need for a general Boolean size, or only for "Boolean (8)", "Boolean (16)", etc.? If so, then the latter might be predefined, and the general mechanism dropped.
-- Dave
On 12 Dec 2002 at 11:16, J. David Bryan wrote:
On 12 Dec 2002 at 2:27, Frank Heckenbach wrote:
If so, this might justify dropping `Integer/Cardinal/Word (n)' entirely.
That was my thought. If "Integer (n)" is simply a syntactic convenience for "packed -(2 pow (n - 1)) .. 2 pow (n - 1) - 1", then no functionality is lost by dropping the "Integer (n)" form, and it fixes a few problems at the same time.
Does the construct "packed -(2 pow (n - 1)) .. 2 pow (n - 1) - 1" guarantee the size (in bits)? If it does, how is that construction better than "Integer (n)"?
However, `Boolean (n)' cannot be done this way. It may be used for interfaces to other languages.
I acknowledge that it is helpful to have foreign (e.g., C) semantics for interfacing. But is there any need for a general Boolean size, or only for "Boolean (8)", "Boolean (16)", etc.? If so, then the latter might be predefined, and the general mechanism dropped.
And when, one day, someone needs "Boolean (64)", "Boolean (128)", or "Boolean (24)", etc., then?
Best regards, The Chief --------- Prof. Abimbola Olowofoyeku (The African Chief) Web: http://www.bigfoot.com/~african_chief/
On 12 Dec 2002 at 16:43, Prof. A Olowofoyeku (The African Chief) wrote:
Does the construct "packed -(2 pow (n - 1)) .. 2 pow (n - 1) - 1" guarantee the size (in bits)?
That was the essence of my question to Frank. The examples given in the GPC manual under "packed" seem to imply that it does, e.g., packing a subrange of 0..31 is equivalent to "Cardinal (5)".
If it does, how is that construction better than "Integer (n)"?
"Integer (n)" is being allowed only due to a scoping bug in GPC. If that bug is fixed, then "Integer (n)" becomes illegal. That's why alternate ways of expressing "Integer (n)" are being discussed.
And when, one day, someone needs "Boolean (64)", "Boolean (128)", or "Boolean (24)", etc., then?
"Boolean (8)" is only a convenience; using "packed 0..255" (i.e., eight-bit cardinal) and a "To_Boolean" function would be equivalent.
Have you ever needed a "Boolean (13)", e.g.? ;-)
-- Dave
On 12 Dec 2002 at 12:01, J. David Bryan wrote:
[...]
If it does, how is that construction better than "Integer (n)"?
"Integer (n)" is being allowed only due to a scoping bug in GPC. If that bug is fixed, then "Integer (n)" becomes illegal. That's why alternate ways of expressing "Integer (n)" are being discussed.
Ok - fair enough.
And when, one day, someone needs "Boolean (64)", "Boolean (128)", or "Boolean (24)", etc., then?
"Boolean (8)" is only a convenience; using "packed 0..255" (i.e., eight-bit cardinal) and a "To_Boolean" function would be equivalent.
Perhaps - but not as straightforward to use ...
Have you ever needed a "Boolean (13)", e.g.? ;-)
Not yet (but that is not to say that it will never be needed). On the other hand, I have needed an "Integer (7)" before ...
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
"Prof. A Olowofoyeku (The African Chief)" wrote:
... snip ...
I must confess that I still cannot understand why any of this is a "better" solution than leaving things the way they are. How does the above advance the situation over a simple "type foo=Integer (n)"?
Because, I believe, "type foo = minval .. maxval;" is absolutely pure standard Pascal. In general the standards allow the attribute PACKED to be added to any type (this is hazy) so I believe "type foo = packed minval .. maxval;" remains completely legal anywhere. The compiler is always free to ignore the packed attribute.
The preparatory step is to accept the 'packed' reserved word in such statements, and discard it.
At some time in the future it would also be possible to implement offset non-symettric ranges with this syntax. E.G. "packed -64 .. 191;" could indicate a one byte quantity, whose zero value is actually represented by 0x40 (in C nomenclature). Such a mechanism can also handle unsigned ranges. This is pure blue-skying.
"J. David Bryan" wrote:
... snip ...
I acknowledge that it is helpful to have foreign (e.g., C) semantics for interfacing. But is there any need for a general Boolean size, or only for "Boolean (8)", "Boolean (16)", etc.? If so, then the latter might be predefined, and the general mechanism dropped.
The standard way to create an array of 1 bit booleans is with 'packed'. i.e. "packed array [0..31] of boolean" could occupy one 32 bit word. No need for C bitfields. A boolean is already a two valued enumeration.
On 12 Dec 2002 at 19:07, Prof A Olowofoyeku (The Afric wrote:
Perhaps - but not as straightforward to use ...
True, but given that "Integer (n)" must go away to fix the bug (at least, I presume the intent is for it to go away), then either an alternate syntax is needed, or a replacement method from the existing capability must be employed. For me, "packed x..y" is the next most straightforward construct (or more so, depending on the way that one views of subranges and the space they require). The proposed alternate syntaxes have been less clear, IMO.
Not yet (but that is not to say that it will never be needed).
I can't even think of a situation or a language where a Boolean would be expressed in some non-integral number of bytes. I'd be curious if anyone on this list has used, or even knows of a use of Boolean in this manner.
Regardless, treating the sized Boolean as a same-sized Cardinal (and explicitly converting to a Pascal Boolean if desired) would work.
On the other hand, I have needed an "Integer (7)" before ...
There is no question that specific bit sizes for integer types are very useful for interfacing, and that capability should be preserved.
-- Dave
J. David Bryan wrote:
On 12 Dec 2002 at 2:27, Frank Heckenbach wrote:
However, `Boolean (n)' cannot be done this way. It may be used for interfaces to other languages.
I acknowledge that it is helpful to have foreign (e.g., C) semantics for interfacing. But is there any need for a general Boolean size, or only for "Boolean (8)", "Boolean (16)", etc.? If so, then the latter might be predefined, and the general mechanism dropped.
I think only the latter -- or, more precisely, for types such as `WordBool' (int), `ByteBool' (char) etc. The difference may be small, but important. These types do not guarantee the size in bytes, but are guaranteed to be compatible with the mentioned C types on each platform. So, for C interfaces, they're the types of choice, and using `Boolean (8)' there would actually be slightly wrong (it would be right for a C bit-field like `int foo : 8', used as a Boolean, but then again, those who use bitfields in C do so usually for size reasons, and would consequently use a single bit for Booleans which corresponds to the regular Pascal Boolean type when used in a packed record/array).
Types such as `WordBool' are absolutely unproblematic (and also needed for BP/Delphi compatibility), so they won't be dropped.
Prof A Olowofoyeku (The African Chief) wrote:
And when, one day, someone needs "Boolean (64)", "Boolean (128)", or "Boolean (24)", etc., then?
"Boolean (8)" is only a convenience; using "packed 0..255" (i.e., eight-bit cardinal) and a "To_Boolean" function would be equivalent.
Perhaps - but not as straightforward to use ...
BTW, `To_Boolean' is just `<> 0'. I'm not sure we need a built-in function here. (And `From_Boolean' would be `Ord'.)
It is a little less convenient (than nothing), but since it's good practice to write a Pascal interface (wrappers) for C libraries, it should only affect small portions of code.
Frank
CBFalconer wrote:
I acknowledge that it is helpful to have foreign (e.g., C) semantics for interfacing. But is there any need for a general Boolean size, or only for "Boolean (8)", "Boolean (16)", etc.? If so, then the latter might be predefined, and the general mechanism dropped.
The standard way to create an array of 1 bit booleans is with 'packed'. i.e. "packed array [0..31] of boolean" could occupy one 32 bit word. No need for C bitfields. A boolean is already a two valued enumeration.
Indeed, and that works with GPC. A problem would be if someone used a field of more than 1 bit for a Boolean in C, but I can't imagine why anyone would do so (and this ever happens, one could still translate it as an integer range in Pascal).
Another issue is when a C function has, e.g., an `int' parameter with Boolean semantics. In this case, a Pascal program can (and should) translate it as `WordBool', not as `Boolean (n)', anyway.
"Prof. A Olowofoyeku (The African Chief)" wrote:
... snip ...
I must confess that I still cannot understand why any of this is a "better" solution than leaving things the way they are. How does the above advance the situation over a simple "type foo=Integer (n)"?
Because, I believe, "type foo = minval .. maxval;" is absolutely pure standard Pascal. In general the standards allow the attribute PACKED to be added to any type (this is hazy) so I believe "type foo = packed minval .. maxval;" remains completely legal anywhere. The compiler is always free to ignore the packed attribute.
The preparatory step is to accept the 'packed' reserved word in such statements, and discard it.
Maybe this wasn't clear in previous messages, but GPC allows and respects it for subranges already.
However, I fear it's non-standard. EP, 6.4.3.1:
newÂstructuredÂtype = [ `packed' ] unpackedÂstructuredÂtype . unpackedÂstructuredÂtype = arrayÂtype | recordÂtype | setÂtype | fileÂtype .
At some time in the future it would also be possible to implement offset non-symettric ranges with this syntax. E.G. "packed -64 .. 191;" could indicate a one byte quantity, whose zero value is actually represented by 0x40 (in C nomenclature). Such a mechanism can also handle unsigned ranges. This is pure blue-skying.
This should be possible. I'm not sure if the effort (internally subtracting/adding 64 before/after each operation) is worth it. But if someone wants to try it ...
Frank
Frank Heckenbach wrote:
CBFalconer wrote:
... snip ...
The preparatory step is to accept the 'packed' reserved word in such statements, and discard it.
Maybe this wasn't clear in previous messages, but GPC allows and respects it for subranges already.
However, I fear it's non-standard. EP, 6.4.3.1:
newÂstructuredÂtype = [ `packed' ] unpackedÂstructuredÂtype . unpackedÂstructuredÂtype = arrayÂtype | recordÂtype | setÂtype | fileÂtype .
At some time in the future it would also be possible to implement offset non-symettric ranges with this syntax. E.G. "packed -64 .. 191;" could indicate a one byte quantity, whose zero value is actually represented by 0x40 (in C nomenclature). Such a mechanism can also handle unsigned ranges. This is pure blue-skying.
This should be possible. I'm not sure if the effort (internally subtracting/adding 64 before/after each operation) is worth it. But if someone wants to try it ...
Shouldn't add much. Consider the equivalence to array indexing, when the base index is non-zero. It only has to be implemented at load/store of such a value, just like an array index.
CBFalconer wrote:
At some time in the future it would also be possible to implement offset non-symettric ranges with this syntax. E.G. "packed -64 .. 191;" could indicate a one byte quantity, whose zero value is actually represented by 0x40 (in C nomenclature). Such a mechanism can also handle unsigned ranges. This is pure blue-skying.
This should be possible. I'm not sure if the effort (internally subtracting/adding 64 before/after each operation) is worth it. But if someone wants to try it ...
Shouldn't add much. Consider the equivalence to array indexing, when the base index is non-zero. It only has to be implemented at load/store of such a value, just like an array index.
As I said, if you like to try it ...
I think a better analogy (in GPC, at least) would be packed arrays. For regular arrays, indexing means internally computing some address, and that's independent of whether it's used for loading or storing. For packed arrays that's different (loading means (roughly) `and' and `shift', storing means load, `and', `shift', `or'). There are two places (loading and storing) in GPC that deal with packed arrays. Maybe this could be done in their vicinity ...
Frank
On 12 Dec 2002 at 14:32, CBFalconer wrote:
"J. David Bryan" wrote:
... snip ...
I acknowledge that it is helpful to have foreign (e.g., C) semantics for interfacing. But is there any need for a general Boolean size, or only for "Boolean (8)", "Boolean (16)", etc.?
The standard way to create an array of 1 bit booleans is with 'packed'. i.e. "packed array [0..31] of boolean" could occupy one 32 bit word. No need for C bitfields.
Indeed. But "Boolean (32)" doesn't create 32 1-bit Booleans but rather a single 32-bit variable with roughly Boolean semantics ("roughly" meaning that 0 is FALSE and all other values are TRUE). There is no way to achieve that directly using "packed" and the standard Boolean type.
-- Dave
On 12 Dec 2002 at 21:25, Frank Heckenbach wrote:
BTW, `To_Boolean' is just `<> 0'.
Exactly so.
I'm not sure we need a built-in function here.
I agree; a built-in function is not necessary. I was thinking of a user- written (and likely inline) "To_Boolean" should manipulation of the cardinal interfacing variables as Pascal Booleans be desired.
-- Dave
"J. David Bryan" wrote:
On 12 Dec 2002 at 14:32, CBFalconer wrote:
"J. David Bryan" wrote:
... snip ...
I acknowledge that it is helpful to have foreign (e.g., C) semantics for interfacing. But is there any need for a general Boolean size, or only for "Boolean (8)", "Boolean (16)", etc.?
The standard way to create an array of 1 bit booleans is with 'packed'. i.e. "packed array [0..31] of boolean" could occupy one 32 bit word. No need for C bitfields.
Indeed. But "Boolean (32)" doesn't create 32 1-bit Booleans but rather a single 32-bit variable with roughly Boolean semantics ("roughly" meaning that 0 is FALSE and all other values are TRUE). There is no way to achieve that directly using "packed" and the standard Boolean type.
And there is no need for such an entity. A logical expression such as "X = 0" or "X <> 0" covers it quite nicely. It also avoids the eternal C confusion about what IS a logical expression.
It always annoys me that, in C, the preponderance of the evidence is true :-)
Frank Heckenbach wrote:
CBFalconer wrote:
At some time in the future it would also be possible to implement offset non-symettric ranges with this syntax. E.G. "packed -64 .. 191;" could indicate a one byte quantity, whose zero value is actually represented by 0x40 (in C nomenclature). Such a mechanism can also handle unsigned ranges. This is pure blue-skying.
This should be possible. I'm not sure if the effort (internally subtracting/adding 64 before/after each operation) is worth it. But if someone wants to try it ...
Shouldn't add much. Consider the equivalence to array indexing, when the base index is non-zero. It only has to be implemented at load/store of such a value, just like an array index.
As I said, if you like to try it ...
I think a better analogy (in GPC, at least) would be packed arrays. For regular arrays, indexing means internally computing some address, and that's independent of whether it's used for loading or storing. For packed arrays that's different (loading means (roughly) `and' and `shift', storing means load, `and', `shift', `or'). There are two places (loading and storing) in GPC that deal with packed arrays. Maybe this could be done in their vicinity ...
IIRC packed arrays have to be accessed with pack and unpack standard procedures for strict compliance. Many systems don't enforce this.
The primary purpose of packed is to save storage space, and to distinguish between text and arrays of char. In addition I believe a text file is a "PACKED FILE OF char", while a "FILE OF char" is a different animal.
On 13 Dec 2002 at 12:33, CBFalconer wrote:
[...]
Indeed. But "Boolean (32)" doesn't create 32 1-bit Booleans but rather a single 32-bit variable with roughly Boolean semantics ("roughly" meaning that 0 is FALSE and all other values are TRUE). There is no way to achieve that directly using "packed" and the standard Boolean type.
And there is no need for such an entity. A logical expression such as "X = 0" or "X <> 0" covers it quite nicely. It also avoids the eternal C confusion about what IS a logical expression.
So why does Pascal have the Boolean type if we can just discard it in favour of a numerical comparison?
If we are to retain a Boolean type (I don't know whether the standard requires it or not) then it makes sense to be able to have a 32-bit Boolean, depending on one's needs.
I for one would prefer not to have to change all occurrences of "foo (bar1, bool1, bool2, bool3)" to "foo (bar1, bar2 = 0, bar3 <> 0, bar4 = 0)"
And, assuming one of these booleans is a VAR parameter? I don't think that the resulting contortions would lead to more readable code.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
CBFalconer wrote:
Frank Heckenbach wrote:
CBFalconer wrote:
At some time in the future it would also be possible to implement offset non-symettric ranges with this syntax. E.G. "packed -64 .. 191;" could indicate a one byte quantity, whose zero value is actually represented by 0x40 (in C nomenclature). Such a mechanism can also handle unsigned ranges. This is pure blue-skying.
This should be possible. I'm not sure if the effort (internally subtracting/adding 64 before/after each operation) is worth it. But if someone wants to try it ...
Shouldn't add much. Consider the equivalence to array indexing, when the base index is non-zero. It only has to be implemented at load/store of such a value, just like an array index.
As I said, if you like to try it ...
I think a better analogy (in GPC, at least) would be packed arrays. For regular arrays, indexing means internally computing some address, and that's independent of whether it's used for loading or storing. For packed arrays that's different (loading means (roughly) `and' and `shift', storing means load, `and', `shift', `or'). There are two places (loading and storing) in GPC that deal with packed arrays. Maybe this could be done in their vicinity ...
IIRC packed arrays have to be accessed with pack and unpack standard procedures for strict compliance. Many systems don't enforce this.
I'm not aware of this. (And I think this would make huge packed array rather useless.) `Pack' and `Unpack' can be used for conversions between packed and unpacked arrays, but AFAIK component access to packed arrays is allowed as usual (except for `var' parameters, EP 6.7.3.3).
The primary purpose of packed is to save storage space, and to distinguish between text and arrays of char. In addition I believe a text file is a "PACKED FILE OF char", while a "FILE OF char" is a different animal.
According to EP 6.4.3.6 (note 6) `Text' is basically a `file of Char' with special additional properties. No mentioning of `packed' there at all. Maybe you're thinking of strings as packed arrays of Char, but I don't see this for `Text' files.
Frank
Prof A Olowofoyeku (The African Chief) wrote:
On 13 Dec 2002 at 12:33, CBFalconer wrote:
[...]
Indeed. But "Boolean (32)" doesn't create 32 1-bit Booleans but rather a single 32-bit variable with roughly Boolean semantics ("roughly" meaning that 0 is FALSE and all other values are TRUE). There is no way to achieve that directly using "packed" and the standard Boolean type.
And there is no need for such an entity. A logical expression such as "X = 0" or "X <> 0" covers it quite nicely. It also avoids the eternal C confusion about what IS a logical expression.
So why does Pascal have the Boolean type if we can just discard it in favour of a numerical comparison?
If we are to retain a Boolean type (I don't know whether the standard requires it or not) then it makes sense to be able to have a 32-bit Boolean, depending on one's needs.
Of course, we'll retain the `Boolean' type (it is standard, and also compatible to any Pascal compiler I know). The point about it is that is has only two values so no confusion can arise about what means True and what means False.
OTOH, any Boolean type with more than two values has such problems. E.g., in C:
typedef int MyBool; /* in Pascal: type MyBool = Integer; */
MyBool a, b; /* var a, b: MyBool; */
[...]
{ a = 1; /* i.e., true */ if (a) /* condition satisfied, as expected */ { ... }
b = 2; /* also "true" */ if (b) /* condition also satisfied */ { ... }
/* Now both a and b are "true", but ... */ if (a == b) /* wrong, oops ... */ { ... } }
This leads to situations where sometimes `!!foo' (i.e., `not not foo') is written to make sure the result is the "canonical" true or false value.
I for one would prefer not to have to change all occurrences of "foo (bar1, bool1, bool2, bool3)" to "foo (bar1, bar2 = 0, bar3 <> 0, bar4 = 0)"
And, assuming one of these booleans is a VAR parameter?
Well, if we really dropped `Boolean', there couldn't be any `Boolean' parameters, anyway. ;-)
But again, that's not the question here. As I said, I don't even plan to drop `WordBool' etc., in spite of the above-mentioned problems. It is only about the `Boolean (n)' syntax.
(BTW, this reminds me of when I recently suggested to remove one of two equivalent switches for the "classic Pascal" mode, and some argued that the CP mode (as a whole) should not be dropped ...)
Frank
Because, I believe, "type foo = minval .. maxval;" is absolutely pure standard Pascal. In general the standards allow the attribute PACKED to be added to any type (this is hazy) so I believe "type foo = packed minval .. maxval;" remains completely legal anywhere. The compiler is always free to ignore the packed attribute.
The grammar in the standard (as noted in other posts) do not accept packed on subranges, so program containing such constuct is non-conformat. Of course accepting packed on subranges is a valid extension, but any compiler with grammar taken from standard will recect it. In fact, I think that in strict ISO mode (--pedantic ??) gpc should reject non-conformat programs, so also packed on subranges. By the way, FPC do not accept packed on subranges (I do not want to discuss if FPC is a Pascal compiler, but I find it reasonable to compile the same program using gpc and FPC).
Waldek Hebisch wrote:
The grammar in the standard (as noted in other posts) do not accept packed on subranges, so program containing such constuct is non-conformat. Of course accepting packed on subranges is a valid extension, but any compiler with grammar taken from standard will recect it. In fact, I think that in strict ISO mode (--pedantic ??) gpc should reject non-conformat programs, so also packed on subranges.
And that's what it does (with any dialect switch except `--gnu-pascal', and with `--pedantic').
Frank
On 13 Dec 2002 at 12:33, CBFalconer wrote:
And there is no need for such an entity.
Need? No, granted, just as there is no need for, e.g., alternate number bases in specifying constants. It's simply a convenience for interfacing with external C routines that use that convention (e.g., a few thousand Windows API routines).
A logical expression such as "X = 0" or "X <> 0" covers it quite nicely.
Although with a bit more semantic fog. ;-)
-- Dave
J. David Bryan wrote:
On 13 Dec 2002 at 12:33, CBFalconer wrote:
[Boolean (32)]
And there is no need for such an entity.
Need? No, granted, just as there is no need for, e.g., alternate number bases in specifying constants. It's simply a convenience for interfacing with external C routines that use that convention (e.g., a few thousand Windows API routines).
Are you sure? Do they really write:
struct MyBool { int BoolField : 32; };
And not perhaps:
typedef int MyBool;
???
Frank
On 15 Dec 2002 at 0:49, Frank Heckenbach wrote:
Are you sure?
Am I sure of what? That the Windows API often returns integers with Boolean semantics? Yes, I'm fairly sure of that.
(Note that the reference to "Boolean (32)" that you quoted, but which was not a part of my message to Chuck, was part of an earlier example that had nothing to do with the Windows API.)
struct MyBool { int BoolField : 32; };
I'm afraid that I don't understand what this has to do with your question.
-- Dave
J. David Bryan wrote:
On 15 Dec 2002 at 0:49, Frank Heckenbach wrote:
Are you sure?
Am I sure of what? That the Windows API often returns integers with Boolean semantics? Yes, I'm fairly sure of that.
Yes, plain integers I suppose, not integers with a specified width of 32 bits.
(Note that the reference to "Boolean (32)" that you quoted, but which was not a part of my message to Chuck, was part of an earlier example that had nothing to do with the Windows API.)
You were replying to Chuck's statement: "And there is no need for such an entity." which was a comment about `Boolean (32)'.
struct MyBool { int BoolField : 32; };
I'm afraid that I don't understand what this has to do with your question.
Because only such a strange type (strange especially if used with Boolean semantics) would warrant using `Boolean (32)' in Pascal.
Frank
On 15 Dec 2002 at 3:33, Frank Heckenbach wrote:
J. David Bryan wrote:
On 15 Dec 2002 at 0:49, Frank Heckenbach wrote:
Are you sure?
Am I sure of what? That the Windows API often returns integers with Boolean semantics? Yes, I'm fairly sure of that.
Yes, plain integers I suppose, not integers with a specified width of 32 bits.
See my other post.
[...]
I'm afraid that I don't understand what this has to do with your question.
Because only such a strange type (strange especially if used with Boolean semantics) would warrant using `Boolean (32)' in Pascal.
Not at all. See my other post. You cannot use an 8-bit or 16-bit value when the WinAPI expects an argument (and sometimes, even function results) to be 32-bits in size. Borland's solution is to predefine 8- bit (Boolean and ByteBool), 16-bit (WordBool) and 32-bit (LongBool) boolean types, and then to define BOOL as LongBool, for the WinAPI routines. If GPC can predefine all these, plus things like LongLongBool (64-bit) and LongestBool (128-bit?) then, we can avoid "Boolean (32)". But the problem will still be there when we need to define a data type of a specific size that is not the default size.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
On 15 Dec 2002 at 0:49, Frank Heckenbach wrote:
J. David Bryan wrote:
[...]
Need? No, granted, just as there is no need for, e.g., alternate number bases in specifying constants. It's simply a convenience for interfacing with external C routines that use that convention (e.g., a few thousand Windows API routines).
Are you sure? Do they really write:
struct MyBool { int BoolField : 32; };
And not perhaps:
typedef int MyBool;
WinBool is defined as an "int". Many of the WinAPI routines that take a WinBool or BOOL parameter expect a 32-bit parameter. Long ago, I made the mistake of defining WinBool as "Boolean" instead of "Boolean (32)", and had no end of trouble with GUI Windows programs (e.g., endless loops with the messaging callbacks). It took me ages to discover what the problem was. Needless to say, I learnt my lesson.
The long and short of it: for as long as GPC expects to support Windows programmers, there is no way out of being able to declare a 32-bit Boolean type - and when Windows moves to 64-bits, we may well need a 64- bit Boolean type. Someone (not Frank) suggested a simple arithmetical expression (e.g., x =/<> 0). For reasons stated elsewhere, I personally would prefer to avoid the contortions necessary to use such constructs.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
"Prof A Olowofoyeku (The African Chief)" wrote:
On 15 Dec 2002 at 3:33, Frank Heckenbach wrote:
... snip ...
Because only such a strange type (strange especially if used with Boolean semantics) would warrant using `Boolean (32)' in Pascal.
Not at all. See my other post. You cannot use an 8-bit or 16-bit value when the WinAPI expects an argument (and sometimes, even function results) to be 32-bits in size. Borland's solution is to predefine 8- bit (Boolean and ByteBool), 16-bit (WordBool) and 32-bit (LongBool) boolean types, and then to define BOOL as LongBool, for the WinAPI routines. If GPC can predefine all these, plus things like LongLongBool (64-bit) and LongestBool (128-bit?) then, we can avoid "Boolean (32)". But the problem will still be there when we need to define a data type of a specific size that is not the default size.
VAR truth : boolean; .... sillywinapi(ord(truth));
which probably generates no extra code.
On 15 Dec 2002 at 3:33, Frank Heckenbach wrote:
Yes, plain integers I suppose, not integers with a specified width of 32 bits.
What is a "plain" integer? Is there a guarantee that a "plain" integer in GNU C or Pascal will be the same size as a "plain" integer in Microsoft C (e.g.)?
I take the point that a WordBool is guaranteed to be the same size as a Word in GNU Pascal or an unsigned int in GNU C and therefore should be used in preference to a sized type when interfacing to other GNU modules. But is that guarantee extended to Microsoft compilers? When interfacing to a module supplied by Microsoft (or any third party), the interface requires certain parameter sizes, regardless of how they were originally defined. They may happen to coincide with GNU Pascal's Word or GNU C's unsigned int, but that isn't given.
Indeed, the GPC manual admits as much:
"The following variants of Integer, Cardinal and Word are guaranteed to be compatible to the integer types of GNU C. The sizes given, however, are _not_ guaranteed."
and:
"If you want to be sure that you have a signed integer with 32 bits width, write Integer (32), not just Integer which might be bigger."
The Win32 documentation from Microsoft says explicitly, for example, that an INT (defined in "windef.h" as "typedef int INT") is a "32-bit signed integer," so when interfacing, an INT parameter _must_ be 32 bits. I can declare the Pascal equivalent to be an Integer, but that doesn't guarantee me 32 bits according to the GPC manual, whereas "Integer (32)" does.
I presume all of this extends to "Boolean (32)" as well, or does "Boolean (32)" behave differently from "Integer (32)" in this regard?
You were replying to Chuck's statement: "And there is no need for such an entity." which was a comment about `Boolean (32)'.
I was commenting on the need (such as it is) for integers with Boolean semantics in general, not specifically a need for "Boolean (32)".
-- Dave
Prof A Olowofoyeku (The African Chief) wrote:
Because only such a strange type (strange especially if used with Boolean semantics) would warrant using `Boolean (32)' in Pascal.
Not at all. See my other post. You cannot use an 8-bit or 16-bit value when the WinAPI expects an argument (and sometimes, even function results) to be 32-bits in size. Borland's solution is to predefine 8- bit (Boolean and ByteBool), 16-bit (WordBool) and 32-bit (LongBool) boolean types, and then to define BOOL as LongBool, for the WinAPI routines. If GPC can predefine all these, plus things like LongLongBool (64-bit) and LongestBool (128-bit?) then, we can avoid "Boolean (32)". But the problem will still be there when we need to define a data type of a specific size that is not the default size.
Short reality check: GPC already has WordBool etc. (though with 32 bits by default, but you could redefine it as ShortBool, which is in fact better suited than `Boolean (16)' if it's main use it to match `short' in C interfaces).
(LongBool and LongestBool are both 64 bits on IA32, there's no 128 bit type yet, and I don't know if there ever will be on 32 bit platforms (but if GCC will ever have it, so will GPC, of course).)
Prof A Olowofoyeku (The African Chief) wrote:
The long and short of it: for as long as GPC expects to support Windows programmers, there is no way out of being able to declare a 32-bit Boolean type - and when Windows moves to 64-bits, we may well need a 64- bit Boolean type.
Which we have ...
Someone (not Frank) suggested a simple arithmetical expression (e.g., x =/<> 0).
I think I did (but maybe Chuck as well). However, since I don't plan to drop WordBool etc., the only situation where you really couldn't avoid it then would be a Boolean type of strange size (5 or whatever ;-), and quite frankly, if such a strange thing is ever used anywhere seriously (I doubt it), it might justify adding `<> 0' in a few places ...
J. David Bryan wrote:
On 15 Dec 2002 at 3:33, Frank Heckenbach wrote:
Yes, plain integers I suppose, not integers with a specified width of 32 bits.
What is a "plain" integer?
`int'
Is there a guarantee that a "plain" integer in GNU C or Pascal will be the same size as a "plain" integer in Microsoft C (e.g.)?
The guarantee is that it's the same in GPC and GCC. I don't know if MS C guarantees anything.
AFAIK, there are GNU C interfaces? Which types do they use?
The Win32 documentation from Microsoft says explicitly, for example, that an INT (defined in "windef.h" as "typedef int INT") is a "32-bit signed integer," so when interfacing, an INT parameter _must_ be 32 bits.
Is this a library interface or an ABI description? I suppose the latter. E.g., the Chief mentioned 64 bit Windows -- if its ABI has `int' to be 64 bit (I don't know if it does, often on 64 bit systems, `int' is still 32 bit, and `long int' (`Med...' in GPC) is 64 bit), do you really expect the interfaces to change to `short' (or whatever is 32 bit then)? I wouldn't. I'd expect the C types to remain the same, even if the sizes vary. (At least that's what I know from other systems, and which makes porting to 64 bits generally rather easy, just recompiling with a compiler for the new target -- as long as you didn't make any assumptions such as a pointer having the same size as `int' (probably the most common one in C, should be less of a problem in Pascal).)
Or the interfaces change completely (or substantially). In this case, the whole point is moot. Then we're talking about one specific platform without any portability concerns, and any type that has a matching size (i.e., plain int and `long' in C, and `WordBool' and `MedBool' in GPC) will do.
Frank
On 17 Dec 2002 at 2:48, Frank Heckenbach wrote:
[...]
Short reality check: GPC already has WordBool etc. (though with 32 bits by default, but you could redefine it as ShortBool, which is in fact better suited than `Boolean (16)' if it's main use it to match `short' in C interfaces).
Is the built in "WordBool" always guaranteed to 32 bits?
(LongBool and LongestBool are both 64 bits on IA32,
Hmmm ... I never knew this. I guess one should never assume anything ;)
[...]
Is there a guarantee that a "plain" integer in GNU C or Pascal will be the same size as a "plain" integer in Microsoft C (e.g.)?
The guarantee is that it's the same in GPC and GCC. I don't know if MS C guarantees anything.
Me neither. I would not be surprised if it didn't.
AFAIK, there are GNU C interfaces? Which types do they use?
All sorts of typedefs and macros mapping various things to various other GNU things. It is easier for gcc, since they are dealing with interfaces designed for C programmers.
The Win32 documentation from Microsoft says explicitly, for example, that an INT (defined in "windef.h" as "typedef int INT") is a "32-bit signed integer," so when interfacing, an INT parameter _must_ be 32 bits.
Is this a library interface or an ABI description? I suppose the latter. E.g., the Chief mentioned 64 bit Windows -- if its ABI has `int' to be 64 bit (I don't know if it does, often on 64 bit systems, `int' is still 32 bit, and `long int' (`Med...' in GPC) is 64 bit), do you really expect the interfaces to change to `short' (or whatever is 32 bit then)? I wouldn't. I'd expect the C types to remain the same, even if the sizes vary. (At least that's what I know from other systems, and which makes porting to 64 bits generally rather easy, just recompiling with a compiler for the new target -- as long as you didn't make any assumptions such as a pointer having the same size as `int' (probably the most common one in C, should be less of a problem in Pascal).)
Or the interfaces change completely (or substantially). In this case, the whole point is moot. Then we're talking about one specific platform without any portability concerns, and any type that has a matching size (i.e., plain int and `long' in C, and `WordBool' and `MedBool' in GPC) will do.
The real problem (??) with the WinAPI is that it is based almost entirely on DLL exports. Therefore the actual parameters supplied must match the ones expected in size, and the sizes of function results must also match - else the DLL will not know what to do with it, and the program will fail in all sorts of ways. I doubt that the interfaces will ever change completely. What might change (and has changed in the past) are the sizes of various types. So today, with 32-bit Windows, INT is 32 bits. With 64-bit Windows, it might well be 64 bits (I don't know, because I am not a beta tester). This should not cause any problem, as long as one can define INT as 64 bits. Then if INT is 64 bits, DWORD or LONG may well become 128 bits, etc., ad nauseum. Of course, GCC will hopefully keep up, and so any manual solutions in GPC should hopefully be minimal.
Best regards, The Chief --------- Prof. Abimbola Olowofoyeku (The African Chief) Web: http://www.bigfoot.com/~african_chief/
On 17 Dec 2002 at 2:48, Frank Heckenbach wrote:
What is a "plain" integer?
`int'
So it is an integer with an implementation-defined length.
The guarantee is that it's the same in GPC and GCC. I don't know if MS C guarantees anything.
MS C's "int" is also an integer with an implementation-defined length. The problem is that there is no guarantee that the two implementations define the length identically (which is clearly required for interoperability).
As long as GPC calls GCC code, all is well, because the types are guaranteed to be the same sizes. But when calling third-party interfaces, that assumption doesn't hold. A method is needed to guarantee that a given parameter is, e.g., 16 bits. "ShortInt" doesn't do that, if the GPC manual is to be believed.
AFAIK, there are GNU C interfaces? Which types do they use?
I don't know; is it relevant? They may have something that "works," but is it correct?
Is this a library interface or an ABI description?
ABI description (from their "Platform SDK" documentation).
...do you really expect the interfaces to change to `short' (or whatever is 32 bit then)? I wouldn't. I'd expect the C types to remain the same, even if the sizes vary.
My expectations are the same, and that's the problem.
MS went from an interface where "int" was 16 bits to an interface where "int" was 32 bits, and I understand that they will be providing an interface where "int" is 64 bits. The 16- and 32-bit interfaces co-existed for a time. I expect the 32- and 64-bit interfaces will as well.
Some years ago, I wrote a program in MS Pascal (!) to call to the 16-bit interface. It worked fine under 16-bit Windows. I moved it to GPC but retained the calls to the 16-bit routines, and then it failed because GPC assumed 32-bit Integers, whereas MS Pascal assumed 16-bit integers. The program worked fine again -- with GPC -- once all of the "Integer"s in the interface definition were changed to "ShortInt"s.
If I write a program today to call the 32-bit interface, and I use "Integer" in GPC, all is well...until GPC changes to use 64-bit "int"s, and then, presumably, Integer becomes 64 bits as well. At that point, if I still call the 32-bit interface, my program fails once again until I fix up all of the parameter types.
GPC's sized integers appear to be intended to address this very problem. An "Integer (16)" stays 16-bits always, regardless of what GPC uses for "Integer" this year. If a particular interface demands certain-sized parameters, e.g., a 32-bit Boolean, then it appears to me that "Boolean (32)" will always produce the correct type, whereas "WordBool" will produce the correct type now but may not in the future. Surely that is what the GPC manual cautions in the section on sized integers.
(At least that's what I know from other systems, and which makes porting to 64 bits generally rather easy, just recompiling with a compiler for the new target -- as long as you didn't make any assumptions....
But presuming that "int" will be the same across platforms is just such an assumption. (And indeed, as I recall, MS had a lot of initial trouble moving from 16-bit to 32-bit interface calls, because under 16-bit Windows, there were a number of 32-bit parameters that were declared as "long"s -- which were 32-bits under the 16-bit compiler but became 64-bits under the 32-bit compiler. And so a lot of programs failed to work when recompiled, because they remained 32-bit parameters under the new interface.)
The problem is that C doesn't have, as far as I know, a method of declaring an integer of a guaranteed size, which makes interfacing across compilers problematic. You can pick some types that happen to work today, but they aren't guaranteed to work tomorrow. ISO Pascal, of course, has the same problem. GPC appears to solve that problem by providing sized integers. (Ada also recognizes this problem and solves it by providing optional "representation attributes" to guarantee a particular size where needed.)
"WordBool" and "Boolean (32)" solve different problems: the former when interfacing to a GNU C routine that uses "unsigned int" and where the parameter size is intended to track changes in the size of GNU C's "int", and the latter when interfacing to third-party routines that require specific parameter sizes.
-- Dave
J. David Bryan a écrit:
The problem is that C doesn't have, as far as I know, a method of declaring an integer of a guaranteed size, which makes interfacing across compilers problematic. You can pick some types that happen to work today, but they aren't guaranteed to work tomorrow. ISO Pascal, of course, has the same problem. GPC appears to solve that problem by providing sized integers. (Ada also recognizes this problem and solves it by providing optional "representation attributes" to guarantee a particular size where needed.)
"WordBool" and "Boolean (32)" solve different problems: the former when interfacing to a GNU C routine that uses "unsigned int" and where the parameter size is intended to track changes in the size of GNU C's "int", and the latter when interfacing to third-party routines that require specific parameter sizes.
I fully agree with this analysis. I has similar problems while rereading with gpc 16 bits integer files which contained experimental data or results of computations written by BP: shortint was one solution, but integer(16) is definitely better because it is clear, explicit and permanent. So keep the actual status: Shortint, integer(16) and also the standard packed(-32768..32767) all defined. integer(16) is much clearer than packed ... The last construct is probably then the way to solve the problem of redefining integer=integer(16) which launched the discussion. Better use integer=packed(-32768..32767) if you want to define 16 bits integer to enable to rerun 16 bits programs completely unchanged. The only issue is _not_ to enforce the standard that packed components can be accessed only by the pack and unpack standard procedures, which is already done now.
Maurice
On 17 Dec 2002 at 19:39, Maurice Lombardi wrote:
The only issue is _not_ to enforce the standard that packed components can be accessed only by the pack and unpack standard procedures....
I cannot find this limitation anywhere in the ISO 10206 standard. The only limitation is on passing components as variable parameters (section 6.7.3.3, "An actual variable parameter shall not denote a component of a variable where that variable possesses a type that is designated packed"). Indeed, several examples (e.g., section 6.12, example 4) show direct access to packed components.
Do you have a section in mind that supports this limitation?
-- Dave
Dave Bryan wrote:
GPC's sized integers appear to be intended to address this very problem. An "Integer (16)" stays 16-bits always, regardless of what GPC uses for "Integer" this year. If a particular interface demands certain-sized parameters, e.g., a 32-bit Boolean, then it appears to me that "Boolean (32)" will always produce the correct type, whereas "WordBool" will produce the correct type now but may not in the future. Surely that is what the GPC manual cautions in the section on sized integers.
(At least that's what I know from other systems, and which makes porting to 64 bits generally rather easy, just recompiling with a compiler for the new target -- as long as you didn't make any assumptions....
But presuming that "int" will be the same across platforms is just such an assumption. (And indeed, as I recall, MS had a lot of initial trouble moving from 16-bit to 32-bit interface calls, because under 16-bit Windows, there were a number of 32-bit parameters that were declared as "long"s -- which were 32-bits under the 16-bit compiler but became 64-bits under the 32-bit compiler. And so a lot of programs failed to work when recompiled, because they remained 32-bit parameters under the new interface.)
The problem is that C doesn't have, as far as I know, a method of declaring an integer of a guaranteed size, which makes interfacing across compilers problematic. You can pick some types that happen to work today, but they aren't guaranteed to work tomorrow. ISO Pascal, of course, has the same problem. GPC appears to solve that problem by providing sized integers. (Ada also recognizes this problem and solves it by providing optional "representation attributes" to guarantee a particular size where needed.)
"WordBool" and "Boolean (32)" solve different problems: the former when interfacing to a GNU C routine that uses "unsigned int" and where the parameter size is intended to track changes in the size of GNU C's "int", and the latter when interfacing to third-party routines that require specific parameter sizes.
I do not think that "explicitely sized" types really solve the problem. Namely, the types are chosen to have needed properties, for example a type must be big enough to allow indexing any array and must be efficiently passed to procedures. Proper sizes depend on target processor and also on the compiler used. They also reflect same design choces of OS writers. On Unix OS interface assumed that long is big enough to hold file offsetes (but this is not true now). Many 64-bit compilers make int still 32 bit and only long and pointers are 64 bits. On Wine list I saw a post stating that 64-bit Microsoft interface uses 32-bit ints and longs and 64-bit pointers (which violates one of basic assumptions in C). So for OS interface one really has to tune mapping for a given flavor -- however such mapping may be hidden in some small unit like: unit mstypes; interface type MSInt = Integer; .... MBBool = Integer; ...
Of course, I assume that there is a way to specify needed type, but mapping of usual Pascal types is likly to require less changes than using explicit sizes. So I would limit explicit sizes to the cases when one really means given size, like graphic program optimized for fixed bit-depth or reading file formats with prescribed size (but for files, due to endiannes problems reading bytes and reconstructing values seems preferable).
J. David Bryan a écrit:
On 17 Dec 2002 at 19:39, Maurice Lombardi wrote:
The only issue is _not_ to enforce the standard that packed components can be accessed only by the pack and unpack standard procedures....
I cannot find this limitation anywhere in the ISO 10206 standard. The only limitation is on passing components as variable parameters (section 6.7.3.3, "An actual variable parameter shall not denote a component of a variable where that variable possesses a type that is designated packed"). Indeed, several examples (e.g., section 6.12, example 4) show direct access to packed components.
Do you have a section in mind that supports this limitation?
No I was only remembering a message in this list, but it has already been answered that this is wrong.
Maurice
Maurice Lombardi wrote:
... snip ...
I fully agree with this analysis. I has similar problems while rereading with gpc 16 bits integer files which contained experimental data or results of computations written by BP: shortint was one solution, but integer(16) is definitely better because it is clear, explicit and permanent.
The problem of reading and writing other systems binary files always exists, in any language. The only safe and universal method is to read and write text files, and even then there are potential problems.
For binaries, even in the C world, it is NOT recommended to read things as integers, etc., but rather as byte sequences to be packed and unpacked by explicit code. That way the operations revolve around the external data format, not the internal format.
"J. David Bryan" wrote:
On 17 Dec 2002 at 19:39, Maurice Lombardi wrote:
The only issue is _not_ to enforce the standard that packed components can be accessed only by the pack and unpack standard procedures....
I cannot find this limitation anywhere in the ISO 10206 standard. The only limitation is on passing components as variable parameters (section 6.7.3.3, "An actual variable parameter shall not denote a component of a variable where that variable possesses a type that is designated packed"). Indeed, several examples (e.g., section 6.12, example 4) show direct access to packed components.
Do you have a section in mind that supports this limitation?
I do believe you are right, and I can finally discard a 25 year old misconception!
Prof. A Olowofoyeku (The African Chief) wrote:
On 17 Dec 2002 at 2:48, Frank Heckenbach wrote:
[...]
Short reality check: GPC already has WordBool etc. (though with 32 bits by default, but you could redefine it as ShortBool, which is in fact better suited than `Boolean (16)' if it's main use it to match `short' in C interfaces).
Is the built in "WordBool" always guaranteed to 32 bits?
Nope, always the same size as `Integer', `Word', `Cardinal' (Pascal) and `[unsigned] int' (C).
AFAIK, there are GNU C interfaces? Which types do they use?
All sorts of typedefs and macros mapping various things to various other GNU things. It is easier for gcc, since they are dealing with interfaces designed for C programmers.
But once it's done in GCC, it can be strgaihtforwardly mapped to GPC (if you figure out the typedefs and macros, that is ;-).
The real problem (??) with the WinAPI is that it is based almost entirely on DLL exports. Therefore the actual parameters supplied must match the ones expected in size, and the sizes of function results must also match - else the DLL will not know what to do with it, and the program will fail in all sorts of ways.
That's true for any external function, nothing specific about DLLs here AFAICS.
I doubt that the interfaces will ever change completely. What might change (and has changed in the past) are the sizes of various types. So today, with 32-bit Windows, INT is 32 bits. With 64-bit Windows, it might well be 64 bits (I don't know, because I am not a beta tester). This should not cause any problem, as long as one can define INT as 64 bits. Then if INT is 64 bits, DWORD or LONG may well become 128 bits, etc., ad nauseum. Of course, GCC will hopefully keep up, and so any manual solutions in GPC should hopefully be minimal.
That would be an ABI decision then (as I supposed), and GCC will usually (always, I guess) follow the ABI of the target platform (where one exists -- not on Linux and the Hurd where GCC is the primary compiler and defines the ABI). This would imply (again, as I supposed) that `WordBool' is more likely to remain correct than `Boolean (32)'.
Frank
On 18 Dec 2002 at 4:25, Frank Heckenbach wrote:
[...]
AFAIK, there are GNU C interfaces? Which types do they use?
All sorts of typedefs and macros mapping various things to various other GNU things. It is easier for gcc, since they are dealing with interfaces designed for C programmers.
But once it's done in GCC, it can be strgaihtforwardly mapped to GPC (if you figure out the typedefs and macros, that is ;-).
Perhaps. The interfaces are done as a separate project (w32api) and not as part of the standard GCC, and it is all in C of course. But, yes, once one can see how the C interface has been implemented, it is just a "simple" case of converting "them" to Pascal (and there is a lot of "them" to be converted ...) if one can figure out what they are doing, AND there is a way to do it in Pascal. Some unions and structures are impossible to convert because there is no way to achieve the conversion in Pascal, and many macros are gobbledegook. Best regards, The Chief --------- Prof. Abimbola Olowofoyeku (The African Chief) Web: http://www.bigfoot.com/~african_chief/
UNIT types;
INTERFACE
{ Note: some comments should be replaced with conditional compilation directives.
This could be extended to support additional types as needed.
Note that a similar unit already exists (sint16, uint16, though), with the same name, in the standard Macintosh Pascal interfaces. }
TYPE { for GPC }
int8 = INTEGER(8); uint8 = WORD(8); int16 = INTEGER(16); uint16 = WORD(16); int32 = INTEGER(32); uint32 = WORD(32); int64 = INTEGER(64); uint64 = WORD(64);
{ for FreePascal }
int8 = SHORTINT; uint8 = BYTE; int16 = INTEGER; uint16 = WORD; int32 = LONGINT; uint32 = CARDINAL; { int64 = INT64; } uint64 = QWORD;
{ etc. }
{ for all }
STRING15 = STRING[15]; STRING31 = STRING[31]; STRING63 = STRING[63]; STRING127 = STRING[127]; STRING255 = STRING[255];
IMPLEMENTATION
{ no implementation for types abstraction unit }
END.
--- "J. David Bryan" dbryan@bcpl.net wrote:
On 15 Dec 2002 at 3:33, Frank Heckenbach wrote:
Yes, plain integers I suppose, not integers with a specified width of 32 bits.
What is a "plain" integer? Is there a guarantee that a "plain" integer in GNU C or Pascal will be the same size as a "plain" integer in Microsoft C (e.g.)?
I take the point that a WordBool is guaranteed to be the same size as a Word in GNU Pascal or an unsigned int in GNU C and therefore should be used in preference to a sized type when interfacing to other GNU modules. But is that guarantee extended to Microsoft compilers? When interfacing to a module supplied by Microsoft (or any third party), the interface requires certain parameter sizes, regardless of how they were originally defined. They may happen to coincide with GNU Pascal's Word or GNU C's unsigned int, but that isn't given.
Indeed, the GPC manual admits as much:
"The following variants of Integer, Cardinal and Word are guaranteed to be compatible to the integer types of GNU C. The sizes given, however, are _not_ guaranteed."
and:
"If you want to be sure that you have a signed integer with 32 bits width, write Integer (32), not just Integer which might be bigger."
The Win32 documentation from Microsoft says explicitly, for example, that an INT (defined in "windef.h" as "typedef int INT") is a "32-bit signed integer," so when interfacing, an INT parameter _must_ be 32 bits. I can declare the Pascal equivalent to be an Integer, but that doesn't guarantee me 32 bits according to the GPC manual, whereas "Integer (32)" does.
I presume all of this extends to "Boolean (32)" as well, or does "Boolean (32)" behave differently from "Integer (32)" in this regard?
You were replying to Chuck's statement: "And there is no need for such an entity." which was a comment about `Boolean (32)'.
I was commenting on the need (such as it is) for integers with Boolean semantics in general, not specifically a need for "Boolean (32)".
-- Dave
===== ======= Frank D. Engel, Jr.
__________________________________________________ Do you Yahoo!? Yahoo! Mail Plus - Powerful. Affordable. Sign up now. http://mailplus.yahoo.com
On 17 Dec 2002 at 20:41, Waldek Hebisch wrote:
I do not think that "explicitely sized" types really solve the problem. Namely, the types are chosen to have needed properties, for example a type must be big enough to allow indexing any array and must be efficiently passed to procedures.
For interfaces to third-party routines, the types have already been chosen by the implementer. In defining the interface and calling such a routine, I must choose types that match the implementation exactly. I have no choice here; if the implementation chose to represent numbers from 0 to 255 in one byte, then I must pass a one-byte variable. If two bytes were chosen, I must pass a two-byte variable, even if 0..255 would fit into a one-byte variable on my system, or even if my system's "natural size" for such ranges is four bytes.
Therefore, to use the implementation, I must have a guarantee from my compiler that the parameters to the external routines are of certain specified sizes. According to the GPC manual, "Integer" (for example) does not give me that guarantee, whereas "Integer (32)" does.
...such mapping may be hidden in some small unit like:
unit mstypes; interface type MSInt = Integer; .... MBBool = Integer;
But that is relying on something that the GPC manual says is unreliable (i.e., that "Integer" is a certain size).
-- Dave
On 18 Dec 2002 at 12:45, J. David Bryan wrote:
According to the GPC manual, "Integer" (for example) does not give me that guarantee, whereas "Integer (32)" does.
I should perhaps emphasize that the important point is the size guarantee, not the "Integer (n)" syntax. If "packed -128..127" guaranteed an eight- bit allocation, then:
type int8 = packed -128..127;
...would be a completely reasonable substitution for "Integer (8)".
(Plain "Integer" offers a guarantee too -- a guarantee of GNU C compatibility -- but that is not the guarantee needed for third-party interfacing, which is a guarantee of a specific size. See:
http://www.gnu-pascal.de/gpc_86.html#SEC86
for reference.)
-- Dave
"J. David Bryan" wrote:
On 17 Dec 2002 at 20:41, Waldek Hebisch wrote:
I do not think that "explicitely sized" types really solve the problem. Namely, the types are chosen to have needed properties, for example a type must be big enough to allow indexing any array and must be efficiently passed to procedures.
For interfaces to third-party routines, the types have already been chosen by the implementer. In defining the interface and calling such a routine, I must choose types that match the implementation exactly. I have no choice here; if the implementation chose to represent numbers from 0 to 255 in one byte, then I must pass a one-byte variable. If two bytes were chosen, I must pass a two-byte variable, even if 0..255 would fit into a one-byte variable on my system, or even if my system's "natural size" for such ranges is four bytes.
Therefore, to use the implementation, I must have a guarantee from my compiler that the parameters to the external routines are of certain specified sizes. According to the GPC manual, "Integer" (for example) does not give me that guarantee, whereas "Integer (32)" does.
Wrong problem, IMHO. You already know how to generate items of various size in a particular installation (and all this is inherently non-portable). Generating such a thing may even be an array[1..count] of char. Your problem is to generate such an entity containing the particular information you want to transmit (or receive).
You have further problems to do with "who removes the parameters". Note that you can generate and call with one single large block, which you treat as one parameter, and the destination treats as a collection of items. Treatment of returned values is another whole area.
J. David Bryan wrote:
`int'
So it is an integer with an implementation-defined length.
Not really implementation defined, but ABI defined.
The guarantee is that it's the same in GPC and GCC. I don't know if MS C guarantees anything.
MS C's "int" is also an integer with an implementation-defined length. The problem is that there is no guarantee that the two implementations define the length identically (which is clearly required for interoperability).
The ABI gives this guarantee (that's its purpose).
AFAIK, there are GNU C interfaces? Which types do they use?
I don't know; is it relevant? They may have something that "works," but is it correct?
If it isn't, the thing to do is to fix it there (i.e., in GCC's ABI). In free software, you try to fix the problems at the root whenever possible (and it would be possible here since the "root" in this context would be GCC) ...
Is this a library interface or an ABI description?
ABI description (from their "Platform SDK" documentation).
And do you have any reason to doubt that GCC follows the ABI? If so, the correct thing to do is to report this to the GCC maintainers for this target and ask them to fix it.
...do you really expect the interfaces to change to `short' (or whatever is 32 bit then)? I wouldn't. I'd expect the C types to remain the same, even if the sizes vary.
My expectations are the same, and that's the problem.
No, that's the solution. :-)
Some years ago, I wrote a program in MS Pascal (!) to call to the 16-bit interface. It worked fine under 16-bit Windows. I moved it to GPC but retained the calls to the 16-bit routines, and then it failed because GPC assumed 32-bit Integers, whereas MS Pascal assumed 16-bit integers. The program worked fine again -- with GPC -- once all of the "Integer"s in the interface definition were changed to "ShortInt"s.
So MS Pascal didn't follow the ABI. How is this relevant to this discussion?
If I write a program today to call the 32-bit interface, and I use "Integer" in GPC, all is well...until GPC changes to use 64-bit "int"s, and then, presumably, Integer becomes 64 bits as well. At that point, if I still call the 32-bit interface, my program fails once again until I fix up all of the parameter types.
GPC's sized integers appear to be intended to address this very problem. An "Integer (16)" stays 16-bits always, regardless of what GPC uses for "Integer" this year.
Maybe that's the source of the confusion. The ABI doesn't change every year -- in fact, once it's established, it should never change. 64 bit Windows will be a new target with a new ABI. So then you'll have a 32 and a 64 bit Windows target. Maybe the system will (for some time) support both platforms, then you can choose which one you use.
(At least that's what I know from other systems, and which makes porting to 64 bits generally rather easy, just recompiling with a compiler for the new target -- as long as you didn't make any assumptions....
But presuming that "int" will be the same across platforms is just such an assumption.
I'm not presuming this. `int' may well be 64 on 64 bit Windows if that's according to its ABI. Or it may remain 32 bits. I don't know.
(And indeed, as I recall, MS had a lot of initial trouble moving from 16-bit to 32-bit interface calls, because under 16-bit Windows, there were a number of 32-bit parameters that were declared as "long"s -- which were 32-bits under the 16-bit compiler but became 64-bits under the 32-bit compiler. And so a lot of programs failed to work when recompiled, because they remained 32-bit parameters under the new interface.)
So the interface was changed (against the ABI). Of course, this may happen, but in general it's more likely to assume that the 64 bit interfaces will follow the 64 bit ABI then the 32 bit one.
"WordBool" and "Boolean (32)" solve different problems: the former when interfacing to a GNU C routine that uses "unsigned int" and where the parameter size is intended to track changes in the size of GNU C's "int", and the latter when interfacing to third-party routines that require specific parameter sizes.
Not really. It's meant more for things like file formats (with the problems of endianness etc. that Chuck mentioned) or memory layout (e.g., of memory mapped hardware), i.e. things which must have the same size on every platform. Interfacing to external code is better done via ABI specifications.
Prof. A Olowofoyeku (The African Chief) wrote:
On 18 Dec 2002 at 4:25, Frank Heckenbach wrote:
[...]
AFAIK, there are GNU C interfaces? Which types do they use?
All sorts of typedefs and macros mapping various things to various other GNU things. It is easier for gcc, since they are dealing with interfaces designed for C programmers.
But once it's done in GCC, it can be strgaihtforwardly mapped to GPC (if you figure out the typedefs and macros, that is ;-).
Perhaps. The interfaces are done as a separate project (w32api) and not as part of the standard GCC,
Of course. The ABI is done within GCC, and mapped 1:1 in GPC. The C interfaces use the ABI, and therefore can also be mapped 1:1 in Pascal.
and it is all in C of course. But, yes, once one can see how the C interface has been implemented, it is just a "simple" case of converting "them" to Pascal (and there is a lot of "them" to be converted ...) if one can figure out what they are doing,
Exactly. (Maybe one day there will be an automatic converter, but don't hold your breath. If/when it will be written, it will use this 1:1 type mapping, of course.)
AND there is a way to do it in Pascal. Some unions and structures are impossible to convert because there is no way to achieve the conversion in Pascal,
I don't remember if we talked about this, but can you give an example for something not convertible?
CBFalconer wrote:
You have further problems to do with "who removes the parameters". Note that you can generate and call with one single large block, which you treat as one parameter, and the destination treats as a collection of items. Treatment of returned values is another whole area.
This is also resolved already in the ABI and partly using attributes.
Maurice Lombardi wrote:
So keep the actual status: Shortint, integer(16) and also the standard packed(-32768..32767) all defined.
Well, I guess I'll leave everything as it is. Actually, I'm getting a little tired of this discussion, and unless really new points are brought up, I probably won't reply anymore.
Keep in mind that there is a parsing conflict. I'm not working on it now. But when I will, and if it turns out that the `Integer (16)' etc. types are a serious problem in this regard, I'll simply drop them then (a bug is always more important than some non-standard feature). This means all who use it will have to change their code quite suddenly then.
I tried to arrange for a smoother change, but the "don't change anything" fraction seems to be in the majority. The alternative suggestions from Waldek and me were criticized or neglected.
I don't have more time to waste on these matters now.
Frank
On 19 Dec 2002 at 4:22, Frank Heckenbach wrote:
[...]
AND there is a way to do it in Pascal. Some unions and structures are impossible to convert because there is no way to achieve the conversion in Pascal,
I don't remember if we talked about this, but can you give an example for something not convertible?
Here are some examples:
typedef enum _CM_ERROR_CONTROL_TYPE { IgnoreError=SERVICE_ERROR_IGNORE, NormalError=SERVICE_ERROR_NORMAL, SevereError=SERVICE_ERROR_SEVERE, CriticalError=SERVICE_ERROR_CRITICAL } SERVICE_ERROR_TYPE;
In this case, one just does something like: Const IgnoreError = SERVICE_ERROR_IGNORE; (in cases where it is sufficient to just refer to "IgnoreError" in the code) - but I have no idea how to translate the enum itself as defined.
Other examples:
typedef struct _LDT_ENTRY { WORD LimitLow; WORD BaseLow; union { struct { BYTE BaseMid; BYTE Flags1; BYTE Flags2; BYTE BaseHi; } Bytes; struct { DWORD BaseMid:8; DWORD Type:5; DWORD Dpl:2; DWORD Pres:1; DWORD LimitHi:4; DWORD Sys:1; DWORD Reserved_0:1; DWORD Default_Big:1; DWORD Granularity:1; DWORD BaseHi:8; } Bits; } HighWord; } LDT_ENTRY,*PLDT_ENTRY,*LPLDT_ENTRY;
typedef struct _DCB { DWORD DCBlength; DWORD BaudRate; DWORD fBinary:1; DWORD fParity:1; DWORD fOutxCtsFlow:1; DWORD fOutxDsrFlow:1; DWORD fDtrControl:2; DWORD fDsrSensitivity:1; DWORD fTXContinueOnXoff:1; DWORD fOutX:1; DWORD fInX:1; DWORD fErrorChar:1; DWORD fNull:1; DWORD fRtsControl:2; DWORD fAbortOnError:1; DWORD fDummy2:17; WORD wReserved; WORD XonLim; WORD XoffLim; BYTE ByteSize; BYTE Parity; BYTE StopBits; char XonChar; char XoffChar; char ErrorChar; char EofChar; char EvtChar; WORD wReserved1; } DCB,*LPDCB;
[...]
Well, I guess I'll leave everything as it is. Actually, I'm getting a little tired of this discussion, and unless really new points are brought up, I probably won't reply anymore.
Fine.
Keep in mind that there is a parsing conflict. I'm not working on it now. But when I will, and if it turns out that the `Integer (16)' etc. types are a serious problem in this regard, I'll simply drop them then (a bug is always more important than some non-standard feature). This means all who use it will have to change their code quite suddenly then.
In which case there needs to be an alternative solution - perhaps the one that you suggested.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
Prof A Olowofoyeku (The African Chief) a écrit:
On 19 Dec 2002 at 4:22, Frank Heckenbach wrote:
[...]
AND there is a way to do it in Pascal. Some unions and structures are impossible to convert because there is no way to achieve the conversion in Pascal,
typedef struct _LDT_ENTRY { WORD LimitLow; WORD BaseLow; union { struct { BYTE BaseMid; BYTE Flags1; BYTE Flags2; BYTE BaseHi; } Bytes; struct { DWORD BaseMid:8; DWORD Type:5; DWORD Dpl:2; DWORD Pres:1; DWORD LimitHi:4; DWORD Sys:1; DWORD Reserved_0:1; DWORD Default_Big:1; DWORD Granularity:1; DWORD BaseHi:8; } Bits; } HighWord; } LDT_ENTRY,*PLDT_ENTRY,*LPLDT_ENTRY;
What about the following
---------------------------------------------------------- program teststruc;
{$define DWORD cardinal}
type tBytes = packed record BaseMid: BYTE; Flags1: BYTE; Flags2: BYTE; BaseHi: BYTE end; type tBits = packed record BaseMid: DWORD(8); Typ: DWORD(5); Dpl: DWORD(2); Pres: DWORD(1); LimitHi: DWORD(4); Sys: DWORD(1); Reserved_0: DWORD(1); Default_Big: DWORD(1); Granularity: DWORD(1); BaseHi: DWORD(8) end; type tHighWord = packed record case integer of 1: (Bytes: tBytes); 2: (Bits: tBits) end;
type tLDT_ENTRY = packed record LimitLow: WORD; BaseLow: WORD; HighWord: tHighWord; end;
var LDT_ENTRY: tLDT_ENTRY; PLDT_ENTRY,LPLDT_ENTRY: ^tLDT_ENTRY;
begin with LDT_ENTRY.HighWord do begin with Bytes do begin BaseMid:=$DE; Flags1 :=$AD; Flags2 :=$BE; BaseHi :=$EF; end; with Bits do writeln(BaseMid,' ', Typ,' ', Dpl,' ', Pres,' ', LimitHi,' ', Sys,' ', Reserved_0,' ', Default_Big,' ', Granularity,' ', BaseHi); end; end.
---------------------------------------------------------- it compiles and gives the expected result (on an ix86 low endian machine)
222 13 1 1 14 1 1 0 1 239
Not so easy to implement automatically, however. It needs extra identifiers for type and var of this type: I do not understand enough C to say if HighWord, Bytes and Bits are type names or variable names which can be used to refer to the struct coponent as a whole (I guess the second). Finally Type cannot be an identifier: it is replaced by Typ.
If you don't mind to have identifiers to refer collectively to components, the following (simpler) also works, and is probably enough for C interfacing
------------------------------------------------------------------------- program teststruc;
{$define DWORD cardinal}
type tLDT_ENTRY = packed record LimitLow: WORD; BaseLow: WORD; case (Bytes,Bits) of Bytes: (BaseMid: BYTE; Flags1: BYTE; Flags2: BYTE; BaseHi: BYTE); Bits: (BaseMid2: DWORD(8); Typ: DWORD(5); Dpl: DWORD(2); Pres: DWORD(1); LimitHi: DWORD(4); Sys: DWORD(1); Reserved_0: DWORD(1); Default_Big: DWORD(1); Granularity: DWORD(1); BaseHi2: DWORD(8)); end; var LDT_ENTRY: tLDT_ENTRY; PLDT_ENTRY,LPLDT_ENTRY: ^tLDT_ENTRY;
begin with LDT_ENTRY do begin BaseMid:=$DE; Flags1 :=$AD; Flags2 :=$BE; BaseHi :=$EF; writeln(BaseMid2,' ', Typ,' ', Dpl,' ', Pres,' ', LimitHi,' ', Sys,' ', Reserved_0,' ', Default_Big,' ', Granularity,' ', BaseHi2) end; readln end.
-----------------------------------------------------------------------
But I had to give a different name to BaseMid and BaseHi in the two case parts
Maurice
On 19 Dec 2002 at 13:10, Maurice Lombardi wrote:
[...]
What about the following
program teststruc;
{$define DWORD cardinal}
Actually, that has to be defined as a type - because it is used throughout (in other units as well).
type tBytes = packed record BaseMid: BYTE; Flags1: BYTE; Flags2: BYTE; BaseHi: BYTE end; type tBits = packed record BaseMid: DWORD(8); Typ: DWORD(5); Dpl: DWORD(2);
[...]
I see - so that is what those colons mean. In this case, the on-going discussions about what to do with this syntax become even more pertinent.
[...]
Not so easy to implement automatically, however. It needs extra identifiers for type and var of this type: I do not understand enough C to say if HighWord, Bytes and Bits are type names or variable names which can be used to refer to the struct coponent as a whole (I guess the second).
I believe that you are right - but others who know more might want to confirm that.
Thanks!
Best regards, The Chief --------- Prof. Abimbola Olowofoyeku (The African Chief) Web: http://www.bigfoot.com/~african_chief/
Prof A Olowofoyeku (The African Chief) wrote:
Here are some examples:
typedef enum _CM_ERROR_CONTROL_TYPE { IgnoreError=SERVICE_ERROR_IGNORE, NormalError=SERVICE_ERROR_NORMAL, SevereError=SERVICE_ERROR_SEVERE, CriticalError=SERVICE_ERROR_CRITICAL } SERVICE_ERROR_TYPE;
In this case, one just does something like: Const IgnoreError = SERVICE_ERROR_IGNORE; (in cases where it is sufficient to just refer to "IgnoreError" in the code) - but I have no idea how to translate the enum itself as defined.
Simply as Integer (that's what enums in C basically are).
Now, we could discuss enums with specified values as a GPC extension. (I know I'm opening another can of worms, but currently there are so many worms around, I hope they'll eat each other ... ;-)
The perhaps obvious syntax
type Foo = (a = 3, b = 5);
is not a good idea since it's too close (too much read-ahead required) to:
type Foo = (a = 3) .. True;
Using `value' or `:=' instead of `=' might work, though.
Then again, it would not actually be a useful translation for this C type in general, since as I said C enums are really integers, i.e., they must be assignment-compatible with plain integers (which Pascal enums aren't). (The same is true for C "Booleans" in some situations, BTW.)
Maurice Lombardi wrote:
type tHighWord = packed record case integer of 1: (Bytes: tBytes); 2: (Bits: tBits) end;
type tLDT_ENTRY = packed record
type LDT_ENTRY = ...
LimitLow: WORD; BaseLow: WORD; HighWord: tHighWord; end;
type PLDT_ENTRY = ^LDT_ENTRY; LPLDT_ENTRY = PLDT_ENTRY;
Not so easy to implement automatically, however. It needs extra identifiers for type and var of this type: I do not understand enough C to say if HighWord, Bytes and Bits are type names or variable names which can be used to refer to the struct coponent as a whole (I guess the second).
Yes (field names, more precisely).
The other names are types, not variables (see my corrections), BTW.
But it's true, in general you might need some additional identifiers when translating. I suppose this can always be done by automatically adding some prefixes.
Finally Type cannot be an identifier: it is replaced by Typ.
That's why I think an automatic translator should add some prefix to every identifier (such as `C_...'). (The Pascal interface can then still map those for which it's useful, to more readable identifiers.)
Prof. A Olowofoyeku (The African Chief) wrote:
On 19 Dec 2002 at 13:10, Maurice Lombardi wrote:
{$define DWORD cardinal}
Actually, that has to be defined as a type - because it is used throughout (in other units as well).
He did so because of the `DWORD(8)'. To satisfy both requirements, just do:
type DWORD = Cardinal;
[...]
BaseMid: Cardinal(8);
type tBits = packed record BaseMid: DWORD(8); Typ: DWORD(5); Dpl: DWORD(2);
[...]
I see - so that is what those colons mean. In this case, the on-going discussions about what to do with this syntax become even more pertinent.
Indeed, that's the only case where specified sizes are really needed in C interfacing. With this in mind, some of my previous comments might become clearer.
As others suggested, packed subranges could replace `Integer/Cardinal/Word(n)' (which includes the present case). This leaves only `Boolean(n)', and as I said, I severely doubt anyone ever uses an explicit bitfield larger than 1 bit with Boolean semantics in C (and if this happens once in a lifetime, the additional `<> 0' in Pascal is not worth the trouble of discussion).
But again, I have no problem with the `Foo(n)' semantics, only the syntax is problematic (for at least 3 reasons so far).
Frank
On 19 Dec 2002 at 21:52, Frank Heckenbach wrote:
[...]
Now, we could discuss enums with specified values as a GPC extension. (I know I'm opening another can of worms, but currently there are so many worms around, I hope they'll eat each other ... ;-)
Pascal breeds cannibalistic worms? ;)
The perhaps obvious syntax
type Foo = (a = 3, b = 5);
is not a good idea since it's too close (too much read-ahead required) to:
type Foo = (a = 3) .. True;
Using `value' or `:=' instead of `=' might work, though.
Interesting. There are perhaps many reasons not to do this. But I would certainly benefit from such an extension. People might think that it is not important enough - but when you have thousands of lines of C header to translate, anything that helps is important. However, I don't feel strongly enough about this to be ready to defend it. So those who are ready to pounce can save their energy ;-)
[...]
Maurice Lombardi wrote:
type tHighWord = packed record
One question - do the records need to be packed, or is that just a "good" thing?
[...]
I see - so that is what those colons mean. In this case, the on-going discussions about what to do with this syntax become even more pertinent.
Indeed, that's the only case where specified sizes are really needed in C interfacing.
Generally speaking, perhaps. With respect to the WinAPI, no. Specified sizes are "really needed" all over the place - function parameters, type declarations, function results, etc.
With this in mind, some of my previous comments might become clearer.
As others suggested, packed subranges could replace `Integer/Cardinal/Word(n)' (which includes the present case).
Packed subranges requires specific knowledge of bits and how to fit something within x number of bits. I certainly do not know that. Having to have such knowledge does not contribute to easy or readable programming. As long as there is a straightforward way to specify the bits (and IMO packed subranges are not a straightforward way), then it does not really matter what the syntax is.
This leaves only `Boolean(n)', and as I said, I severely doubt anyone ever uses an explicit bitfield larger than 1 bit with Boolean semantics in C (and if this happens once in a lifetime, the additional `<> 0' in Pascal is not worth the trouble of discussion).
I am not sure that I understand the distinction being made here about booleans. I think it is accepted that the WinAPI expects a 32-bit size for booleans. Whether or not one uses integer or boolean semantics to achieve that has already been well debated. Both are feasible solutions, but one is easier and therefore preferable for those who do have to use the feature. I guess i'ts up to you (Frank) to decide which solution you prefer to implement.
But again, I have no problem with the `Foo(n)' semantics, only the syntax is problematic (for at least 3 reasons so far).
If the choice is between packed subranges and a new, easy syntax, then I vote for the latter. Better still if it could be used in the way that Maurice has shown, in declaring fields of records (instead of having first to declare the type separately).
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
Prof A Olowofoyeku (The African Chief) wrote:
The perhaps obvious syntax
type Foo = (a = 3, b = 5);
is not a good idea since it's too close (too much read-ahead required) to:
type Foo = (a = 3) .. True;
Using `value' or `:=' instead of `=' might work, though.
Interesting. There are perhaps many reasons not to do this. But I would certainly benefit from such an extension. People might think that it is not important enough - but when you have thousands of lines of C header to translate, anything that helps is important. However, I don't feel strongly enough about this to be ready to defend it. So those who are ready to pounce can save their energy ;-)
Anyway, I think the semantical implementation would be rather easy since we can take it from the C frontend. It's also no question that it will be marked as a GPC extension. Only the syntax would be the question. (Same as the recently discussed record/enum extensions where we don't have a final conclusion yet, either, AFAIR.)
[...]
Maurice Lombardi wrote:
type tHighWord = packed record
One question - do the records need to be packed, or is that just a "good" thing?
With bitfields, they need do be packed (otherwise each field gets some whole number of bytes). Otherwise, I think it's better to not pack them.
Generally speaking, perhaps. With respect to the WinAPI, no. Specified sizes are "really needed" all over the place - function parameters, type declarations, function results, etc.
As I tried to explain, no (ABI).
This leaves only `Boolean(n)', and as I said, I severely doubt anyone ever uses an explicit bitfield larger than 1 bit with Boolean semantics in C (and if this happens once in a lifetime, the additional `<> 0' in Pascal is not worth the trouble of discussion).
I am not sure that I understand the distinction being made here about booleans. I think it is accepted that the WinAPI expects a 32-bit size for booleans.
As far as I could gather, it's the ABI which means that types such as WordBool (where C uses int) are probably at least as well suited if not better. ("Probably", i.e. if 64 bit Windows will stick to the interfaced WRT ABI.)
But again, I have no problem with the `Foo(n)' semantics, only the syntax is problematic (for at least 3 reasons so far).
If the choice is between packed subranges and a new, easy syntax, then I vote for the latter. Better still if it could be used in the way that Maurice has shown, in declaring fields of records (instead of having first to declare the type separately).
With a new syntax, this might well be possible. I.e., with the current syntax, I explicitly disallowed:
type Foo = Integer; Bar = Foo (16);
because I consider `Integer (16)' a special syntax that should not spread to each type.
An alternate syntax could be applied to any type -- though I wonder, what, e.g., `Byte (32)' should mean. ;-) The only possibly reasonable explanation would be the same as `Cardinal (32)'. Though C doesn't allow `char foo : 32' if the size of `char' is smaller than 32 bits.
As for the syntax, my suggestion was:
TypeOfSize (Integer, n)
Waldek suggested:
type foo = Integer attribute(Size(n),...);
I tend to prefer Waldek's (maybe even `attribute (packed (n))' since there is already a `packed' attribute in GCC, but without argument). The advantage is to avoid introducing a special identifier.
However, I think this should only apply to `type' definitions then (I think the same holds for GCC's `packed' attribute), not to `var' declarations etc. where it would implicitly create a new type.
Frank
Frank Heckenbach a écrit:
Prof A Olowofoyeku (The African Chief) wrote: Maurice Lombardi wrote:
type tHighWord = packed record case integer of 1: (Bytes: tBytes); 2: (Bits: tBits) end;
type tLDT_ENTRY = packed record
type LDT_ENTRY = ...
LimitLow: WORD; BaseLow: WORD; HighWord: tHighWord; end;
type PLDT_ENTRY = ^LDT_ENTRY; LPLDT_ENTRY = PLDT_ENTRY;
Not so easy to implement automatically, however. It needs extra identifiers for type and var of this type: I do not understand enough C to say if HighWord, Bytes and Bits are type names or variable names which can be used to refer to the struct coponent as a whole (I guess the second).
Yes (field names, more precisely).
The other names are types, not variables (see my corrections), BTW.
But it's true, in general you might need some additional identifiers when translating. I suppose this can always be done by automatically adding some prefixes.
Finally Type cannot be an identifier: it is replaced by Typ.
That's why I think an automatic translator should add some prefix to every identifier (such as `C_...'). (The Pascal interface can then still map those for which it's useful, to more readable identifiers.)
To summarize, the correct translation, with a test program would be ------------------------------------------------------------------------
program teststruc;
{$define DWORD cardinal}
type LDT_ENTRY = packed record LimitLow: WORD; BaseLow: WORD; HighWord: packed record case integer of 1: (Bytes: packed record BaseMid: BYTE; Flags1: BYTE; Flags2: BYTE; BaseHi: BYTE end); 2: (Bits: packed record BaseMid: DWORD(8); C_Type: DWORD(5); Dpl: DWORD(2); Pres: DWORD(1); LimitHi: DWORD(4); Sys: DWORD(1); Reserved_0: DWORD(1); Default_Big: DWORD(1); Granularity: DWORD(1); BaseHi: DWORD(8) end) end; end;
type PLDT_ENTRY = ^LDT_ENTRY; LPLDT_ENTRY = PLDT_ENTRY;
var ldt:LDT_ENTRY;
begin with ldt.HighWord do begin with Bytes do begin BaseMid:=$DE; Flags1 :=$AD; Flags2 :=$BE; BaseHi :=$EF; end; with Bits do writeln(BaseMid,' ', C_Type,' ', Dpl,' ', Pres,' ', LimitHi,' ', Sys,' ', Reserved_0,' ', Default_Big,' ', Granularity,' ', BaseHi); end; readln end.
-------------------------------------------------------------------------
You may check that it is strictly equivalent to
--------------------------------------------------------------------------- #include <stdio.h>
#define WORD unsigned short #define BYTE char #define DWORD unsigned
typedef struct _LDT_ENTRY { WORD LimitLow; WORD BaseLow; union { struct { BYTE BaseMid; BYTE Flags1; BYTE Flags2; BYTE BaseHi; } Bytes; struct { DWORD BaseMid:8; DWORD Type:5; DWORD Dpl:2; DWORD Pres:1; DWORD LimitHi:4; DWORD Sys:1; DWORD Reserved_0:1; DWORD Default_Big:1; DWORD Granularity:1; DWORD BaseHi:8; } Bits; } HighWord; } LDT_ENTRY,*PLDT_ENTRY,*LPLDT_ENTRY;
int main(void) { // struct _LDT_ENTRY ldt; LDT_ENTRY ldt; // equivalent declarations
ldt.HighWord.Bytes.BaseMid = 0xDE; ldt.HighWord.Bytes.Flags1 = 0xAD; ldt.HighWord.Bytes.Flags2 = 0xBE; ldt.HighWord.Bytes.BaseHi = 0xEF;
printf("%d %d %d %d %d %d %d %d %d %d\n", ldt.HighWord.Bits.BaseMid, ldt.HighWord.Bits.Type, ldt.HighWord.Bits.Dpl, ldt.HighWord.Bits.Pres, ldt.HighWord.Bits.LimitHi, ldt.HighWord.Bits.Sys, ldt.HighWord.Bits.Reserved_0, ldt.HighWord.Bits.Default_Big, ldt.HighWord.Bits.Granularity, ldt.HighWord.Bits.BaseHi);
return 0; }
---------------------------------------------------------------------------
I know no C equivalent to with in Pascal ... With respect to my first idea, besides the confusions between types and variables corrected by Franck, it adds no extra type identifier (which would be very problematic with generic identifiers like Bytes, Bits etc). It can be fully automated, because it is systematic: union -> case integer of ... struct -> packed record ... Type -> C_Type: it is the only case here where some kind of prefixing is mandatory. There is inly a finite (small) list of these. The only problem I see is the restriction by pascal to only one case variant in a record. I suppose C has no restriction on the number of union inside a struct. This can be solved only by some extra types.
Maurice
Maurice Lombardi wrote:
... snip ...
The only problem I see is the restriction by pascal to only one case variant in a record. I suppose C has no restriction on the number of union inside a struct. This can be solved only by some extra types.
Is this really so? There is the requirement that fixed components precede variant components, but AFAIK there is no limitation on nesting.
Isn't the following legal?
TYPE x = RECORD a : integer; CASE b : char OF 'B': (b1 : fubar); 'C': CASE c1 : char OF 'c': (c2 : foo); END; (* CASE c1 *) 'D': CASE d1 : char OF 'd': (d2 : bar); END; (* CASE d1 *) END; (* CASE b *) (* e : integer; WOULD BE ILLEGAL here *) END; (* RECORD x *)
The names have to be distinct, and the compiler must be able to infer a fixed offset for any component name.
Maurice Lombardi wrote:
To summarize, the correct translation, with a test program would be
[...]
You may check that it is strictly equivalent to
Since the C header is #included, the defines apply to the including program as well. A 100% translator would have to do the same (i.e., translate it to a Pascal include file, not a unit/module), though in this case, some Pascal type definitions will do for most cases (but not for `DWORD (8)' in an importer -- but this might be changed with a new syntax) ...
#define WORD unsigned short
That's not the same as `Word' in GPC. You'd need
type WORD = ShortCard;
#define BYTE char
`char' can be signed or unsigned in C. Not specifying this is either a bug in the C header, or it means that it doesn't matter, so both `Byte' or `ByteInt' would be OK in GPC.
Only the record with the bitfields should be packed.
Records that contain both bitfields and other fields might be a problem in the translation (doesn't occur here). One might need an articifial sub-record ...
I know no C equivalent to with in Pascal ...
There is none. You can only set a pointer to the record at the point of `with' and dereference it explicitly where necessary. This would be semantically equivalent (i.e., the record access is only evaluated once at the point of `with'), but not syntactically.
With respect to my first idea, besides the confusions between types and variables corrected by Franck, it adds no extra type identifier (which would be very problematic with generic identifiers like Bytes, Bits etc).
I don't see why. And in general, you do need additional type identifiers. C can use structured types etc. in parameter lists where Pascal requires a type identifier.
There can in fact be anonymous types in C which cannot be anonymous in Pascal, so the translator will have to make up a name ...
It can be fully automated, because it is systematic: union -> case integer of ... struct -> packed record ... Type -> C_Type: it is the only case here where some kind of prefixing is mandatory. There is inly a finite (small) list of these.
But it's possible that a future GPC version will add new keywords. Even if only for some dialects, the translator should avoid them which means that its output may change at any time. Not a good idea IMHO.
Another thing is that in C structs, unions, enums and "plain" identifiers can have the same name (because it's always used iwth `struct' etc. prefixed). And then there's the problem of case-sensitivity ...
So the translator has to do some identifier renaming, and if so, I'd prefer to make the rules as simple as possible (e.g., not dependent on the list of Pascal keywords).
BTW, the renaming might also be a good thing; e.g. if `FooBar' is a C function working on CStrings etc., in Pascal you might want to have the name `FooBar' for the corresponding Pascal function (which will call the C function internally, so the latter should have a different name).
The only problem I see is the restriction by pascal to only one case variant in a record. I suppose C has no restriction on the number of union inside a struct. This can be solved only by some extra types.
Must be in fact, since unions are syntactically more like sub-records, i.e. they have a field name of their own. You translated this correctly above. If you put the variants into the main record instead, this would have been possible in this case (because the union was last), but the access would have looked differently (omitting the `HighWord').
So I think one can say, a C union corresponds to a Pascal variant record with no fields before the variant, so their translation should pose no special problems.
Frank
On 20 Dec 2002 at 7:22, Frank Heckenbach wrote:
[...]
An alternate syntax could be applied to any type -- though I wonder, what, e.g., `Byte (32)' should mean. ;-) The only possibly reasonable explanation would be the same as `Cardinal (32)'. Though C doesn't allow `char foo : 32' if the size of `char' is smaller than 32 bits.
As for the syntax, my suggestion was:
TypeOfSize (Integer, n)
Waldek suggested:
type foo = Integer attribute(Size(n),...);
I tend to prefer Waldek's (maybe even `attribute (packed (n))' since there is already a `packed' attribute in GCC, but without argument). The advantage is to avoid introducing a special identifier.
If a function returns "foo" and "foo is declared as "Integer attribute(Size(n),...)" doesn't this trigger the age-old problem with functions and attributes (that means you have to declare the function twice)? And, assuming that the function itself needs another attribute (e.g., stdcall)? Then will there be a problem? - e.g. "function bar (i :foo): foo; attribute(stdcall);"
Also, since this will require new extensions to the compiler anyway, I would have thought that introducing an appropriately titled identifier might be preferable to extending an existing identifier.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/
Prof A Olowofoyeku (The African Chief) wrote:
On 20 Dec 2002 at 7:22, Frank Heckenbach wrote:
[...]
An alternate syntax could be applied to any type -- though I wonder, what, e.g., `Byte (32)' should mean. ;-) The only possibly reasonable explanation would be the same as `Cardinal (32)'. Though C doesn't allow `char foo : 32' if the size of `char' is smaller than 32 bits.
As for the syntax, my suggestion was:
TypeOfSize (Integer, n)
Waldek suggested:
type foo = Integer attribute(Size(n),...);
I tend to prefer Waldek's (maybe even `attribute (packed (n))' since there is already a `packed' attribute in GCC, but without argument). The advantage is to avoid introducing a special identifier.
If a function returns "foo" and "foo is declared as "Integer attribute(Size(n),...)" doesn't this trigger the age-old problem with functions and attributes (that means you have to declare the function twice)? And, assuming that the function itself needs another attribute (e.g., stdcall)? Then will there be a problem?
- e.g. "function bar (i :foo): foo; attribute(stdcall);"
I wrote:
: However, I think this should only apply to `type' definitions then : (I think the same holds for GCC's `packed' attribute), not to `var' : declarations etc. where it would implicitly create a new type.
Also, since this will require new extensions to the compiler anyway, I would have thought that introducing an appropriately titled identifier might be preferable to extending an existing identifier.
But `attribute' is already a "container" ...
Frank