Hi
This program fails to compile under '--borland-pascal' and '--delphi':
program delphibug; {$delphi} { fails } {$borland-pascal} { so does this } CONST foo = 'PK'#5#6; { this is the offending line } begin Writeln ('OK'); end.
This is the error I get (with gpc-20030830): "delphibug.pas:4: error: string concatenation without `Concat' or `+' is an extension delphibug.pas:4: error: of GNU Pascal"
This error should not happen. If you remove the embedded condititionals, the program compiles fine both under BP and all versions of Delphi.
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:
Hi
This program fails to compile under '--borland-pascal' and '--delphi':
program delphibug; {$delphi} { fails } {$borland-pascal} { so does this } CONST foo = 'PK'#5#6; { this is the offending line } begin Writeln ('OK'); end.
This is the error I get (with gpc-20030830): "delphibug.pas:4: error: string concatenation without `Concat' or `+' is an extension delphibug.pas:4: error: of GNU Pascal"
This error should not happen. If you remove the embedded condititionals, the program compiles fine both under BP and all versions of Delphi.
Yes. Will fix it later.
Frank
On 14 Dec 2003 at 21:04, Frank Heckenbach wrote:
[...]
This is the error I get (with gpc-20030830): "delphibug.pas:4: error: string concatenation without `Concat' or `+' is an extension delphibug.pas:4: error: of GNU Pascal"
This error should not happen. If you remove the embedded condititionals, the program compiles fine both under BP and all versions of Delphi.
Yes. Will fix it later.
Ok. While you are at it, there is another minor one. This program: program athen; {$delphi} begin If ParamCount = 0 then; Writeln ('OK'); end.
generates a warning: athen.pas: In main program: athen.pas:4: warning: `;' after `then'
Should this warning be generated in BP mode?
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 ...
Ok. While you are at it, there is another minor one. This program: program athen; {$delphi} begin If ParamCount = 0 then; Writeln ('OK'); end.
generates a warning: athen.pas: In main program: athen.pas:4: warning: `;' after `then'
Should this warning be generated in BP mode?
What possible reason could there be for suppressing it? The only use I can see for such a statement is to discard the return value from a function named ParamCount that has side effects, and that is much more clearly done with: "junk := ParamCount;"
What possible reason could there be for suppressing it? The only use I can see for such a statement is to discard the return value from a function named ParamCount that has side effects, and that is much more clearly done with: "junk := ParamCount;"
I always wanted the extended syntax
nil := ParamCount;
to get the benefits of being able to throw away the return value with the clarity that you are doing so and without the necessity to create junk variables.
Enjoy, Peter.
On 15 Dec 2003 at 9:16, Peter N Lewis wrote:
What possible reason could there be for suppressing it? The only use I can see for such a statement is to discard the return value from a function named ParamCount that has side effects, and that is much more clearly done with: "junk := ParamCount;"
I always wanted the extended syntax
nil := ParamCount;
to get the benefits of being able to throw away the return value with the clarity that you are doing so and without the necessity to create junk variables.
Precisely. However, such an extension would then mean loss of compatibility with other Pascal compilers. I think I will just suppress the warning.
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 2003 at 9:16, Peter N Lewis wrote:
What possible reason could there be for suppressing it? The only use I can see for such a statement is to discard the return value from a function named ParamCount that has side effects, and that is much more clearly done with: "junk := ParamCount;"
I always wanted the extended syntax
nil := ParamCount;
to get the benefits of being able to throw away the return value with the clarity that you are doing so and without the necessity to create junk variables.
Precisely. However, such an extension would then mean loss of compatibility with other Pascal compilers. I think I will just suppress the warning.
IIRC the original complaint, since snipped, applied to BP and attempted to use a null statement after a conditional. It seems to me that there is absolutely no need for such a statement in BP, since ParamCount begins life there as a global variable, and it would probably not be good form to redefine it.
As far as an extended throw-away syntax is concerned, I have seen far too many C failures due to ignoring a return value (especially malloc/realloc, but including fclose, printf, etc) than is comfortable, and I see no need to encourage such bad C habits in Pascal.
On 15 Dec 2003 at 8:39, CBFalconer wrote: [...]
IIRC the original complaint, since snipped, applied to BP and attempted to use a null statement after a conditional. It seems to me that there is absolutely no need for such a statement in BP, since ParamCount begins life there as a global variable, and it would probably not be good form to redefine it.
This focus on ParamCount is a red herring. That was just a trivial test program (as Frank always emphasises) that shows the problem. ParamCount is not the problem here. Rather, it is the warning about a ";" following a "then" that was being highlighted.
Best regards, The Chief --------- Prof. Abimbola Olowofoyeku (The African Chief) Web: http://www.bigfoot.com/~african_chief/
"Prof. A Olowofoyeku (The African Chief)" wrote:
On 15 Dec 2003 at 8:39, CBFalconer wrote: [...]
IIRC the original complaint, since snipped, applied to BP and attempted to use a null statement after a conditional. It seems to me that there is absolutely no need for such a statement in BP, since ParamCount begins life there as a global variable, and it would probably not be good form to redefine it.
This focus on ParamCount is a red herring. That was just a trivial test program (as Frank always emphasises) that shows the problem. ParamCount is not the problem here. Rather, it is the warning about a ";" following a "then" that was being highlighted.
My point, which I probably did not make clear, is that the only use for a null statement after a then is to discard something in the conditional part. Having discarded the need for this by using clearer methods, such a null THEN clause is clearly a programmatic error and a warning can only be useful.
On 15 Dec 2003 at 23:35, CBFalconer wrote:
[...]
This focus on ParamCount is a red herring. That was just a trivial test program (as Frank always emphasises) that shows the problem. ParamCount is not the problem here. Rather, it is the warning about a ";" following a "then" that was being highlighted.
My point, which I probably did not make clear, is that the only use for a null statement after a then is to discard something in the conditional part. Having discarded the need for this by using clearer methods, such a null THEN clause is clearly a programmatic error and a warning can only be useful.
I am not sure how something is an error, if it is something that I intend to do, does not cause my program to behave in a manner that I do not expect or want, and does not violate the language.
IMHO having to create any number of junk variables just for the purpose of discarding things is undesirable. I don't see how it is "clearer" either. It ought to be pretty clear to anyone that the value is being deliberately discarded when a "then" is followed by a semi-colon. Finally, your solution still generates a warning (or "hint") in other Pascal implementations. For example, this program:
program foo; var i : integer; homedir : string [255]; begin {....} chdir (homedir); i := ioresult; end.
generates this under Delphi: "Value assigned to 'i' never used" and this under FPC: "Local variable "i" is assigned but never used"
Seems that you are damned if you do and you are damned if you don't ...
In this example, all I want is to try to go somewhere before doing something else, and I don't need to know (or care) whether it happens successfully or not, because it is of no real consequence either way. I of course want to clear IOResult, and I don't want any complaints. This scenario is of course contrived.
I guess "If ioresult = 0 then begin end;" is the way to go in order to satisfy all compilers ...
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 2003 at 23:35, CBFalconer wrote:
[...]
This focus on ParamCount is a red herring. That was just a trivial test program (as Frank always emphasises) that shows the problem. ParamCount is not the problem here. Rather, it is the warning about a ";" following a "then" that was being highlighted.
My point, which I probably did not make clear, is that the only use for a null statement after a then is to discard something in the conditional part. Having discarded the need for this by using clearer methods, such a null THEN clause is clearly a programmatic error and a warning can only be useful.
I am not sure how something is an error, if it is something that I intend to do, does not cause my program to behave in a manner that I do not expect or want, and does not violate the language.
(I suppose "programmatic error" was meant as "bad style".)
IMHO having to create any number of junk variables just for the purpose of discarding things is undesirable. I don't see how it is "clearer" either. It ought to be pretty clear to anyone that the value is being deliberately discarded when a "then" is followed by a semi-colon.
In this case yes. But people (including myself ;-) sometime make mistakes and put an semicolon after `then' or `else' where it doesn't belong. The compiler can't distinguish the cases, and the resulting bugs are often hard to find (because one tends to overlook the semicolon even when checking again). That's why I (and probably others) appreciate such a warning. But if you don't, you can always turn it off (`-Wno-semicolon').
In this example, all I want is to try to go somewhere before doing something else, and I don't need to know (or care) whether it happens successfully or not, because it is of no real consequence either way. I of course want to clear IOResult, and I don't want any complaints. This scenario is of course contrived.
I guess "If ioresult = 0 then begin end;" is the way to go in order to satisfy all compilers ...
In this case I'd recommend `InOutRes := 0' which says what you actually want to do -- clear the state, not query it. This will avoid the issue here, but not in general.
What I could imagine is a built-in procedure `Ignore', `IgnoreValue', `Discard' or so which takes one parameter of arbitrary type and does nothing.
Or perhaps (but less preferable IMHO) a type-cast to `Void' (as in C) ...
Do any other compilers have something like that?
FWIW, Delphi has something called a Variant, which is type-compatible with all sorts.
I don't think that's suitable. We don't actually want to declare such a dummy variable (which would have to be global, so assignments could not even be optimized away). And since it doesn't accept all types (as stated in the Delphi description), it wouldn't be general enough.
I still prefer the built-in procedure.
Adriaan van Os wrote:
CBFalconer wrote:
As far as an extended throw-away syntax is concerned, I have seen far too many C failures due to ignoring a return value (especially malloc/realloc, but including fclose, printf, etc) than is comfortable, and I see no need to encourage such bad C habits in Pascal.
I agree with that. Worse -- the whole Win32 API (and some of the later parts of Mac OS) are based on this bad habit. Many Win32 functions return values that are useless in most situations, simply because in C they can be ignored. Some functions return an error result code, but never consistently. The result is of course instable software, because very few programmers pay attention to all the details if tricky and variable from situation to situation.
Bad habits in programming tend to get worse all the time and then the final result is invariably a total mess.
I beg to differ. Error status results (as in `malloc', I/O functions etc. in C) are serious indeed. But in GPC many of them cause runtime errors instead anyway (which can be caught, but only by explicit action, not by ignoring a function result).
There are other functions which really return unimportant results -- e.g., some of the CString routines return a pointer passed as an argument back. This is to facilitate chaining them, but ignoring the result is perfectly safe as well. GPC now allows declaring such functions with the `ignorable' attribute, and many such functions in the RTS and included units are declared so now. So there's no problem either -- GPC will simply accept both procedure and function style use.
(Typical C functions fall in one of these categories, and when writing a Pascal interface it's useful to distinguish the cases by giving or not giving this attribute. Of course, this can never be automated by any header converter, since it depends on the semantics of the C functions ...)
But it occasionally happens that you want to ignore another function's result (or some other value, for that matter) -- of course, after due consideration whether it's safe to do. That's where a built-in ignore procedure would come handy.
Frank
Frank Heckenbach wrote:
... massive snippage ...
There are other functions which really return unimportant results -- e.g., some of the CString routines return a pointer passed as an argument back. This is to facilitate chaining them, but ignoring the result is perfectly safe as well. GPC now allows declaring such functions with the `ignorable' attribute, and many such functions in the RTS and included units are declared so now. So there's no problem either -- GPC will simply accept both procedure and function style use.
This can lead to unexpected and baffling errors, especially in C. My classic example is:
char * revstring(char *s) { /* whatever, to reverse string in place, and return s */ }
....
char thestring[] = "whatever";
printf(""%s" "%s"\n", thestring, revstring(thestring));
which should print out:
"revetahw" "revetahw"
contrary to expectations. The cure is to make revstring a void function, or a procedure in Pascal. Moral: discarding function results should be awkward.
contrary to expectations. The cure is to make revstring a void function, or a procedure in Pascal. Moral: discarding function results should be awkward.
I don' mind it being a bit awkward, but I dont see the need to further complicate the issue by adding dummy variables.
Adding a dummy variable in the variables section does not make the code:
dummy := revstring(thestring)) any clearer than nil := revstring(thestring)) or ThrowAwayResult( revstring(thestring)) )
Personally, I think the middle one is the clearest - it is clear that revstring is a function returning a value and clear that it is being discarded.
The first one is unclear in that the value might possibly be used later (and indeed some crazy graduate programmer might come along later and modify the code to use it without changing the name of the variable).
The last one is also unclear as to what, if anything, ThrowAwayResult actually does, whether a procedure really gets called or whatever - only reading documentation and looking at the assembly code would explain this.
Regardless, we live in a world with C programmers who return pointless errors because they can throw them away easily (and indeed clearly when using the (void) syntax), and it is a world we need to deal with. For example, what exactly are you to do if disposing an object returns an error? Or closing a readonly file returns an error. The most you could do would be put up an alert or an assertion, but even as mad keen on assertions as I am I can't image putting an assertion from every single case whether an almost useless function (eg one where the user would hardly or never detect whether it was called at all) might return an error. Peter.
Peter N Lewis wrote:
Adding a dummy variable in the variables section does not make the code:
dummy := revstring(thestring)) any clearer than nil := revstring(thestring)) or ThrowAwayResult( revstring(thestring)) )
Personally, I think the middle one is the clearest - it is clear that revstring is a function returning a value and clear that it is being discarded.
I already stated the problems I see with this syntax. Unlesss you can address these concerns, just repeating the suggestion is quite pointless.
The first one is unclear in that the value might possibly be used later (and indeed some crazy graduate programmer might come along later and modify the code to use it without changing the name of the variable).
Agreed.
The last one is also unclear as to what, if anything, ThrowAwayResult actually does, whether a procedure really gets called or whatever - only reading documentation and looking at the assembly code would explain this.
Well, if you're so paranoid about optimization, you'll always have to read the assembly code, anyway. ;-)
If you don't trust the programmer of the RTS (or any module used) to not name a procedure `ThrowAway...' or `Ignore...' and not really ignore things, you could just as well be paranoid about any `+' or `=' operator having been overloaded or any number of other things ...
I don't know, but if your concern is that anything that looks like `identifier (...)' might be a routine call, my advice is to "get over it". It's already not true in C (think of macros and inline functions), even less so in Pascal (built-in routines, also inline routines (which any Pascal compiler is free to use), type-casts (BP), macros (GPC), etc.).
Also the converse is not true -- neither in C (again, macros), and even less so in Pascal (routine calls without arguments, implicit calls e.g. for string assignments, some built-in operators e.g. string `+' and many set operators (EP), user-defined operators (PXSC), macros (GPC), etc.).
What I want to say it that associating a syntactic pattern with some runtime behaviour is in general misleading (already), so I don't see this as an important argument against using such a pattern.
Indeed, I prefer such a pattern because it entails no new syntax. A user of another compiler could implement it by defining a regular procedure (sure, with an untyped argument (BP)). This might be worse at runtime (if not inlined), but in contrast a new syntax could not be emulated in Pascal code at all, so would be more incompatible.
Regardless, we live in a world with C programmers who return pointless errors because they can throw them away easily (and indeed clearly when using the (void) syntax), and it is a world we need to deal with. For example, what exactly are you to do if disposing an object returns an error? Or closing a readonly file returns an error.
Can this actually happen? It can't be excluded since the `close' function is the same for read-only and other files, and for other files it can indeed cause an error.
As I said, error status codes are not the main concern in Pascal, because they're (usually) not returned as function results but cause runtime errors. These can be handled more globally -- e.g., in batch style programs the default behaviour (aborting with an error message) is usually just fine; for interactive programs you might prefer to catch all I/O or all runtime errors, print messages in a suitable form and continue or shut down cleanly. In both cases, you don't have to worry about every single possible source of errors -- if closing a read-only file doesn't ever cause an error, fine, and if it does for some reason, the general error handling strategy should apply just the same.
Frank
CBFalconer wrote:
This can lead to unexpected and baffling errors, especially in C. My classic example is:
char * revstring(char *s) { /* whatever, to reverse string in place, and return s */ }
....
char thestring[] = "whatever";
printf(""%s" "%s"\n", thestring, revstring(thestring));
which should print out:
"revetahw" "revetahw"
contrary to expectations. The cure is to make revstring a void function, or a procedure in Pascal. Moral: discarding function results should be awkward.
That's not primarily a problem of ignoring function results, but of (a) the existence of functions with side-effects and (b) mistaking semantics (in particular, thinking of C strings as string values rather than pointers).
(a) is inherent in Pascal as well. We could discuss whether functions should have been defined as having no side-effects, but this would be an academic discussion since we won't change the basics of Pascal.
(b) is true whenever using C strings (and in some other situations). That's why I generally recommend to avoid them. But if you use them, you'll just have to remember to look at semantics more carefully (which not every C programmer does which leads to strange errors, sure ...).
Frank
CBFalconer wrote:
As far as an extended throw-away syntax is concerned, I have seen far too many C failures due to ignoring a return value (especially malloc/realloc, but including fclose, printf, etc) than is comfortable, and I see no need to encourage such bad C habits in Pascal.
I agree with that. Worse -- the whole Win32 API (and some of the later parts of Mac OS) are based on this bad habit. Many Win32 functions return values that are useless in most situations, simply because in C they can be ignored. Some functions return an error result code, but never consistently. The result is of course instable software, because very few programmers pay attention to all the details if tricky and variable from situation to situation.
Bad habits in programming tend to get worse all the time and then the final result is invariably a total mess.
Regards,
Adriaan van Os
Peter N Lewis wrote:
What possible reason could there be for suppressing it? The only use I can see for such a statement is to discard the return value from a function named ParamCount that has side effects, and that is much more clearly done with: "junk := ParamCount;"
I always wanted the extended syntax
nil := ParamCount;
to get the benefits of being able to throw away the return value with the clarity that you are doing so and without the necessity to create junk variables.
Yes for semantics, no for the syntax.
`nil' is a constant, and it's of pointer type. This assignment would violate both rules (and basically create a completely different thing by the same name). I don't think we should follow the example of some other languages to squeeze out the last bits of unused syntax (usually accompanied by worse error recognition).
What I could imagine is a built-in procedure `Ignore', `IgnoreValue', `Discard' or so which takes one parameter of arbitrary type and does nothing.
Or perhaps (but less preferable IMHO) a type-cast to `Void' (as in C) ...
Do any other compilers have something like that?
Frank
On 15 Dec 2003 at 11:19, Frank Heckenbach wrote:
[...]
I always wanted the extended syntax
nil := ParamCount;
to get the benefits of being able to throw away the return value with the clarity that you are doing so and without the necessity to create junk variables.
Yes for semantics, no for the syntax.
`nil' is a constant, and it's of pointer type. This assignment would violate both rules (and basically create a completely different thing by the same name). I don't think we should follow the example of some other languages to squeeze out the last bits of unused syntax (usually accompanied by worse error recognition).
What I could imagine is a built-in procedure `Ignore', `IgnoreValue', `Discard' or so which takes one parameter of arbitrary type and does nothing.
Or perhaps (but less preferable IMHO) a type-cast to `Void' (as in C) ...
Do any other compilers have something like that?
FWIW, Delphi has something called a Variant, which is type-compatible with all sorts. We could have a more limited kind of Variant. This is what the Delphi 7 help file says about "Variant":
"Sometimes it is necessary to manipulate data whose type varies or cannot be determined at compile time. In these cases, one option is to use variables and parameters of type Variant, which represent values that can change type at runtime. Variants offer greater flexibility but consume more memory than regular variables, and operations on them are slower than on statically bound types. Moreover, illicit operations on variants often result in runtime errors, where similar mistakes with regular variables would have been caught at compile time. You can also create custom variant types.
By default, Variants can hold values of any type except records, sets, static arrays, files, classes, class references, and pointers. In other words, variants can hold anything but structured types and pointers. They can hold interfaces, whose methods and properties can be accessed through them. (See Object interfaces.) They can hold dynamic arrays, and they can hold a special kind of static array called a variant array. (See Variant arrays.) Variants can mix with other variants and with integer, real, string, and Boolean values in expressions and assignments; the compiler automatically performs type conversions.
Variants that contain strings cannot be indexed. That is, if V is a variant that holds a string value, the construction V[1] causes a runtime error.
You can define custom Variants that extend the Variant type to hold arbitrary values. For example, you can define a Variant string type that allows indexing or that holds a particular class reference, record type, or static array. Custom Variant types are defined by creating descendants to the TCustomVariantType class."
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:
Ok. While you are at it, there is another minor one. This program: program athen; {$delphi} begin If ParamCount = 0 then; Writeln ('OK'); end.
generates a warning: athen.pas: In main program: athen.pas:4: warning: `;' after `then'
Should this warning be generated in BP mode?
I think so. It's just a diagnostic. The construct is also valid in standard Pascal. You can use `-Wno-semicolon'.
For full BP compatibility turn off all warnings as BP has none (not really recommended ;-).
Frank