Hi Markus,
first of all thank for you answer.
Jose Pascual wrote:
I'm working in port some of my little application to linux.
All of my
application has been writting in pascal. My porting to
linux is going
ok but some of them use threads.
I have read in GPC lists there are people working in a
thread unit for
GPC, aren't you?
Yep.
great!
Could someone share this unit with me? I could help to debugging it.
I'm almost done with the threads themselves and mutexes. If that is sufficient for your purposes, I'll put it online as soon as I've finished testing.
It'll be afable! I'm in a hurry so I have made some very alpha version with importing funtion from libpthread so I'd like to test your beta version. I'll need threading an semaphore in my application. Do you know (more or less) you are going to put it online?
thank you so much
You're welcome,
Markus
thank again
best regards
Jose Pascual
Hi Jose,
I'm almost done with the threads themselves and mutexes. If that is sufficient for your purposes, I'll put it online as soon as I've finished testing.
It'll be afable! I'm in a hurry so I have made some very alpha version with importing funtion from libpthread so I'd like to test your beta version. I'll need threading an semaphore in my application. Do you know (more or less) you are going to put it online?
If you need semaphores, I fear you'll have to wait until next week. Hope this isn't too late?
Best,
Markus
Hi Markus,
I'm almost done with the threads themselves and mutexes.
If that is
sufficient for your purposes, I'll put it online as soon as I've finished testing.
It'll be afable! I'm in a hurry so I have made some very
alpha version
with importing funtion from libpthread so I'd like to test
your beta
version. I'll need threading an semaphore in my application. Do you know (more or less) you are going to put it online?
If you need semaphores, I fear you'll have to wait until next week. Hope this isn't too late?
okey, meanwhile, Could you send me your beta implementation in order to begin to adapt, check and test threading?
Best,
Markus
best regards
Jose Pascual
Hi Markus,
I'm almost done with the threads themselves and mutexes.
If that is
sufficient for your purposes, I'll put it online as soon as I've finished testing.
It'll be afable! I'm in a hurry so I have made some very
alpha version
with importing funtion from libpthread so I'd like to test
your beta
version. I'll need threading an semaphore in my
application. Do you
know (more or less) you are going to put it online?
If you need semaphores, I fear you'll have to wait until next week. Hope this isn't too late?
okey, meanwhile, Could you send me your beta implementation in order to begin to adapt, check and test threading?
I just compile with threading and semaphores one simple application using my very initial 'beta' implementation of pthreads. It seem to work okey I'll need to try with a bigger application.
Anyway, I'd like to check your beta implementation of pthread in order to test & try it
best regards
Jose Pascual
Hello,
I just wanted to ask: Has the multithreading unit I uploaded been something of a help for anyone here?
Regards,
Markus
Hello Markus,
MG> I just wanted to ask: Has the multithreading unit I uploaded been something of MG> a help for anyone here?
I was out of list reading a bit, so I missed an announcement. I'll download this unit and try it immediately. It is of great importance for me. Thank you.
Igor Marnat
marny@rambler.ru
Hello Markus,
I got it and tried to build the library. I'll use it for ARM processor, so I use arm-elf-gcc (2.95.3) and arm-elf-gpc (20021111). My Linux box lives on 2.4.27-rc3 kernel. I met the following problems:
1. Firstly, I have configured it using
export CC=arm-elf-gcc export CFLAGS='-Wl,-elf2flt -mcpu=arm7tdmi' ./configure --enable-shared=no --host=i686-gnu --target=arm-elf --build=arm-elf \ --with-build-cc=gcc --without-cxx --without-cxx-binding --with-tags=
Then I tried to do "make" but it told me:
Making all in units make[1]: Entering directory `/home/igor/src/gnualp-0.1.4/units' libtool --mode=compile --tag=CC gpc -DPACKAGE_NAME="" -DPACKAGE_TARNAME="" -DPACKAGE_VERSION="" -DPACKAGE_STRING="" -DPACKAGE_BUGREPORT="" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DGNU_COMPATIBLE_OS=1 --automake -c -o alpexceptions.o alpexceptions.pas libtool: unrecognized option `--tag=CC' Try `libtool --help' for more information. make[1]: *** [alpexceptions.lo] Error 1 make[1]: Leaving directory `/home/igor/src/gnualp-0.1.4/units' make: *** [all-recursive] Error 1
Then I changed Makefile in units directory like this:
was: .pas.o: libtool --mode=compile --tag=CC gpc $(DEFS) --automake -c -o $@ $< .pas.lo: libtool --mode=compile --tag=CC gpc $(DEFS) --automake -c -o $*.o $<
now: .pas.o: libtool --mode=compile gpc $(DEFS) --automake -c -o $@ $< .pas.lo: libtool --mode=compile gpc $(DEFS) --automake -c -o $*.o $<
2. Now build process goes further but it stops on file units/cnatives.c, in function run_alp_thread. My arm-elf-gcc compiler doesn't want to accept variables declarations after the function calls, so I moved declarations of "gpc_object thread" and "pthread_mutex_t *trigger" to the very beginning of the function (declarations only, not initialization).
3. After that build process goes further, now it tells me
/bin/sh ../libtool --mode=link arm-elf-gcc -Wl,-elf2flt -mcpu=arm7tdmi -o libgnualp.la -rpath /usr/local/lib alpexceptions.lo alpcollections.lo alptime.lo alpthreads.lo cport.lo cnatives.lo -lrt -lpthread libtool: link: `alpexceptions.lo' is not a valid libtool object make: *** [libgnualp.la] Error 1
and I don't know what to do just now, perhaps I have to think about it a little. Perhaps, I missed some options or something like that?
Igor Marnat
mailto:marny@rambler.ru
I've got a problem with GPC giving the error:
error: function result must not be a procedural type
Is there a reason for this error? The manual states:
"In Extended Pascal, function result type can be every assignable type. Of course,there are no type restrictions in GNU Pascal as well."
Since GPC supports as an extension procedural and functional types and assignments involving those types, it would seem to be covered under "every assignable type" and "no type restrictions in GNU Pascal".
Since Posix has such things as signal:
typedef void (*sig_t) (int);
sig_t signal(int sig, sig_t func);
to make a Pascal interface to this I need to return a procedural type from a function.
Is this likely to work in the future or is there some serious problem with this?
Thanks, Peter.
Peter N Lewis wrote:
I've got a problem with GPC giving the error:
error: function result must not be a procedural type
Is there a reason for this error? The manual states:
"In Extended Pascal, function result type can be every assignable type. Of course,there are no type restrictions in GNU Pascal as well."
Since GPC supports as an extension procedural and functional types and assignments involving those types, it would seem to be covered under "every assignable type" and "no type restrictions in GNU Pascal".
Note that in Pascal there is no syntactic dictinction between function used as a value and parameterless function call. I guess that the restriction is intended to reduce resulting confusion -- if context want a function than we use function "as is", if context wants something else we call the function. In fact, any "function producing" expression has the same problem: it is not clear if the resulting function should be called or not (AFAICS the rule above is used).
Since Posix has such things as signal:
typedef void (*sig_t) (int); sig_t signal(int sig, sig_t func);
to make a Pascal interface to this I need to return a procedural type from a function.
GNU Pascal has function pointers (such pointer can be a return value from a function). So literal translation of the above is possible.
Is this likely to work in the future or is there some serious problem with this?
In principle w could agree on some rules deciding when we call function and when we use functional value and implement them. But function pointers seem to work today.
Waldek Hebisch wrote:
Peter N Lewis wrote:
I've got a problem with GPC giving the error:
error: function result must not be a procedural type
Is there a reason for this error? The manual states:
"In Extended Pascal, function result type can be every assignable type. Of course,there are no type restrictions in GNU Pascal as well."
Since GPC supports as an extension procedural and functional types and assignments involving those types, it would seem to be covered under "every assignable type" and "no type restrictions in GNU Pascal".
Note that in Pascal there is no syntactic dictinction between function used as a value and parameterless function call. I guess that the restriction is intended to reduce resulting confusion -- if context want a function than we use function "as is", if context wants something else we call the function. In fact, any "function producing" expression has the same problem: it is not clear if the resulting function should be called or not (AFAICS the rule above is used).
In fact, the rules are a bit hairy internally, and may not be quite correct in some strange cases. I plan to work on this issue sometime and perhaps reimplement much of it. Maybe we can remove the restriction in this course (perhaps calling the function so often until the type matches), but I don't want to promise too much now.
Since Posix has such things as signal:
typedef void (*sig_t) (int); sig_t signal(int sig, sig_t func);
to make a Pascal interface to this I need to return a procedural type from a function.
GNU Pascal has function pointers (such pointer can be a return value from a function). So literal translation of the above is possible.
Yes, for now, I'd recommend using function pointers (or `var' parameters as, e.g., the signal routines in gpc.pas such as `InstallSignalHandler' do).
Frank
Frank Heckenbach wrote:
Waldek Hebisch wrote:
Note that in Pascal there is no syntactic dictinction between function used as a value and parameterless function call. I guess that the restriction is intended to reduce resulting confusion -- if context want a function than we use function "as is", if context wants something else we call the function. In fact, any "function producing" expression has the same problem: it is not clear if the resulting function should be called or not (AFAICS the rule above is used).
In fact, the rules are a bit hairy internally, and may not be quite correct in some strange cases. I plan to work on this issue sometime and perhaps reimplement much of it. Maybe we can remove the restriction in this course (perhaps calling the function so often until the type matches), but I don't want to promise too much now.
This may be too eager to choose a call. Look at:
type fp = ^ ft; fp2 = ^ ft; ft = function : fp;
function foo: fp; var x : fp2;
x := fp2 (@foo);
Casts may be quite reasonable to mask "inessential" type incompatibility, but if allowed for procedures will cause spurious calls.
Also, if we choose call the procedural version would not work. We can use empty parentheses to force the call, but I am affraid that we have no way to prevent the call.
I personaly think that procedure variables are more elegant than procedure pointers, but IMHO without a 100% reliable way to prevent call procedure variables just are broken.
Waldek Hebisch wrote:
Frank Heckenbach wrote:
Waldek Hebisch wrote:
Note that in Pascal there is no syntactic dictinction between function used as a value and parameterless function call. I guess that the restriction is intended to reduce resulting confusion -- if context want a function than we use function "as is", if context wants something else we call the function. In fact, any "function producing" expression has the same problem: it is not clear if the resulting function should be called or not (AFAICS the rule above is used).
In fact, the rules are a bit hairy internally, and may not be quite correct in some strange cases. I plan to work on this issue sometime and perhaps reimplement much of it. Maybe we can remove the restriction in this course (perhaps calling the function so often until the type matches), but I don't want to promise too much now.
This may be too eager to choose a call. Look at:
type fp = ^ ft; fp2 = ^ ft; ft = function : fp;
function foo: fp; var x : fp2;
x := fp2 (@foo);
Casts may be quite reasonable to mask "inessential" type incompatibility, but if allowed for procedures will cause spurious calls.
Yes. Perhaps we could say, inside a cast any pointer type matches, so there's no need to call anything in this example, and therefore we should not call anything. But I'm not sure if that's easy to implement ...
Also, if we choose call the procedural version would not work. We can use empty parentheses to force the call, but I am affraid that we have no way to prevent the call.
So we should only call when necessary (i.e., types don't match without calling).
I personaly think that procedure variables are more elegant than procedure pointers, but IMHO without a 100% reliable way to prevent call procedure variables just are broken.
My be difficult. If foo is a procedural (or functional) variable, then
bar := foo;
can be a call if bar is of the result type. Of course, you can always do `@foo' (according to BP, this does not give the address of the variable, but casts it to a pointer type). This should always prevent a call AFAICS.
Frank
Frank Heckenbach wrote:
Waldek Hebisch wrote:
I personaly think that procedure variables are more elegant than procedure pointers, but IMHO without a 100% reliable way to prevent call procedure variables just are broken.
My be difficult. If foo is a procedural (or functional) variable, then
bar := foo;
can be a call if bar is of the result type. Of course, you can always do `@foo' (according to BP, this does not give the address of the variable, but casts it to a pointer type). This should always prevent a call AFAICS.
But `@foo' is a pointer! So we have a way to prevent call using pointers. But logically, to assign to a procedure variable we need a cast, and the problems cames back -- note that the problem not only involves procedures, but _all_ procedure valued expressions (including casts). That is why I think that procedure pointers are better -- they work always with uniform syntax.
Hello Igor,
thank you very much for your feedback!
libtool --mode=compile --tag=CC gpc -DPACKAGE_NAME="" -DPACKAGE_TARNAME="" -DPACKAGE_VERSION="" -DPACKAGE_STRING="" -DPACKAGE_BUGREPORT="" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DGNU_COMPATIBLE_OS=1 --automake -c -o alpexceptions.o alpexceptions.pas libtool: unrecognized option `--tag=CC'
Which version of libtool are you using?
- Now build process goes further but it stops on file units/cnatives.c, in
function run_alp_thread. My arm-elf-gcc compiler doesn't want to accept variables declarations after the function calls, so I moved declarations of "gpc_object thread" and "pthread_mutex_t *trigger" to the very beginning of the function (declarations only, not initialization).
Okay, I'll change the sources accordingly.
- After that build process goes further, now it tells me
libtool: link: `alpexceptions.lo' is not a valid libtool object
I mean to remember I had the same error as long as I left out the --tag=CC option, so this one's probably related to the first error.
Best,
Markus
Hello Markus,
MG> Which version of libtool are you using?
"libtool --version" tells me:
ltmain.sh (GNU libtool) 1.4.3 (1.922.2.111 2002/10/23 02:54:36)
Should I update it?
Best regards, Igor Marnat mailto:marny@rambler.ru
The following compiler directives seem to work in GPC
{$W unused} {$W unused-function} {$W unused-value} {$W unused-parameter} {$W unused-label} {$W unused-variable} {$W unused-function}
but there negatives don't
{$W no-unused} {$W no-unused-function} {$W no-unused-value} {$W no-unused-parameter} {$W no-unused-label} {$W no-unused-variable} {$W no-unused-function}
Unless I am doing something wrong (section 6.9 of the gpc manual), this seems to be an omission in gpc.
Regards,
Adriaan van Os
On Wed, 4 Aug 2004, Adriaan van Os wrote:
The following compiler directives seem to work in GPC
{$W unused} {$W unused-function} {$W unused-value} {$W unused-parameter} {$W unused-label} {$W unused-variable} {$W unused-function}
but there negatives don't
{$W no-unused} {$W no-unused-function} {$W no-unused-value} {$W no-unused-parameter} {$W no-unused-label} {$W no-unused-variable} {$W no-unused-function}
Unless I am doing something wrong (section 6.9 of the gpc manual), this seems to be an omission in gpc.
Haven't read the section. However, would you really want a warning message that says "you don't have an error"?
Russ
Russell Whitaker wrote:
Adriaan van Os wrote:
The following compiler directives seem to work in GPC
{$W unused} {$W unused-function} {$W unused-value} {$W unused-parameter} {$W unused-label} {$W unused-variable} {$W unused-function}
but there negatives don't
{$W no-unused} {$W no-unused-function} {$W no-unused-value} {$W no-unused-parameter} {$W no-unused-label} {$W no-unused-variable} {$W no-unused-function}
Unless I am doing something wrong (section 6.9 of the gpc manual), this seems to be an omission in gpc.
Haven't read the section. However, would you really want a warning message that says "you don't have an error"?
No, see the equivalent command-line flags, e.g. -Wno-unused-parameter means "don't issue a warning for unused parameters". I didn't invent the naming convention, but is generally used with gpc and gcc..
The idea is to use this locally:
{$W no-unused-parameter} procedure .... {$W unused-parameter}
Ideally, this would also work:
{$local -W no-unused-parameter} procedure .... {$endlocal}
This is better, as {$endlocal} resets the state of the warning to its previous value (whatever the value was).
Regards,
Adriaan van Os
In MW Pascal, if a parameter is not used, then it can generate a warning, which you can silence with
{$unused( param_name )}
However GPC barfs when it sees this.
I believe the GPC way to silence the warning is to use attribute(unused), but then I also believe GPC does not currently catch this particular case.
I'm trying to ensure by source code both
a) compiles cleanly without any warnings and b) compiles under both GPC and MW Pascal
Unfortunately, while I could probably define a macro like:
{$ifdef __GPC__} {$definec NOTUSED attribute(unused)} {$elsec} {$definec NOTUSED } {$endc}
and add the NOTUSED entries to my parameters, I cannot think of any way to get GPC to ignore or udnerstand the {$unused( param_name )}
Could $unused either be supported to disable the warning for a variable/parameter, or could we get some sort of flag to allow {$unused(x,y,z)} to be silently ignored so that it is possible to write code that is source compatible?
Thanks, Peter.
Peter N Lewis wrote:
In MW Pascal, if a parameter is not used, then it can generate a warning, which you can silence with
{$unused( param_name )}
However GPC barfs when it sees this.
I believe the GPC way to silence the warning is to use attribute(unused), but then I also believe GPC does not currently catch this particular case.
I'm trying to ensure by source code both
a) compiles cleanly without any warnings and b) compiles under both GPC and MW Pascal
One portable way, BTW, is to use a local dummy variable and assign to it (in case of strings, e.g., you might want to assign its `Length' to a dummy integer, to avoid a possible string copy). This makes the parameter to be used, and a good optimizer should eliminate the dummy variable and the assignment.
Unfortunately, while I could probably define a macro like:
{$ifdef __GPC__} {$definec NOTUSED attribute(unused)} {$elsec} {$definec NOTUSED } {$endc}
and add the NOTUSED entries to my parameters, I cannot think of any way to get GPC to ignore or udnerstand the {$unused( param_name )}
Could $unused either be supported to disable the warning for a variable/parameter, or could we get some sort of flag to allow {$unused(x,y,z)} to be silently ignored so that it is possible to write code that is source compatible?
I don't really like this syntax, because (our) compiler directives usually don't refer directly to language elements (identifiers).
So I'd rather tend to ignore it -- perhaps ignore `{$unused...}' in Mac mode with a warning otherwise (or only if `-pedantic'?), just like we ignore several BP directives?
Frank
One portable way, BTW, is to use a local dummy variable and assign to it (in case of strings, e.g., you might want to assign its `Length' to a dummy integer, to avoid a possible string copy). This makes the parameter to be used, and a good optimizer should eliminate the dummy variable and the assignment.
Agreed, although that is fairly ugly and requires defining a temporary variable (or for different types a temporary for each type).
Another (non-portable) option, would be if we had the way of explicitly specifying "throw away the result" akin to C's (void) (which sadly is needed more and more for compatibility with the idiotic C calls that pointlessly return their parameter), then that could be used to accomplish this without a dummy variable, but would not solve the problem of source code compatibility, although it would change the location of the GPC macro and make it somewhat clearer and more consistent in location.
For example, if GPC supported a syntax like:
nil := whatever
Then that could be used to both throw away function results (but clearly mark them in the code which is exactly as safe as writing dummy_result := whatever) as well as provide a mechanism for "using" unused variables.
Unfortunately, while I could probably define a macro like:
{$ifdef __GPC__} {$definec NOTUSED attribute(unused)} {$elsec} {$definec NOTUSED } {$endc}
and add the NOTUSED entries to my parameters, I cannot think of any way to get GPC to ignore or udnerstand the {$unused( param_name )}
Could $unused either be supported to disable the warning for a variable/parameter, or could we get some sort of flag to allow {$unused(x,y,z)} to be silently ignored so that it is possible to write code that is source compatible?
I don't really like this syntax, because (our) compiler directives usually don't refer directly to language elements (identifiers).
So I'd rather tend to ignore it -- perhaps ignore `{$unused...}' in Mac mode with a warning otherwise (or only if `-pedantic'?), just like we ignore several BP directives?
Ignoring it would be fine, preferably not only in Mac mode, it would need its own switch or pedantic would be fine by me (I don't generally use Mac mode as such even though it is Mac specific because I want to access the general GPC facilities in as GPC a manner as possible). Ignoring {$unused} should be safe for anything other than pedantic mode since other than leading to a possible source compatibility issue, it can't do any real damage since it only hides a warning and if it is ignored by GPC it will just mean the warning is displayed again...
All that said, if it was possible to support it in GPC, even though it referred to a language element from a Macro, it would be preferable since the syntax is relatively clean and fairly clear as to what it is doing and would mean less hacks in my MW/GPC source compatibility.
But as usual, any solution you're willing to go with is a better solution that not being able to write source compatible code.
Thanks, Peter.
Peter N Lewis wrote: (other attribution lines missing)
... snip ...
and add the NOTUSED entries to my parameters, I cannot think of any way to get GPC to ignore or udnerstand the {$unused( param_name )}
Could $unused either be supported to disable the warning for a variable/parameter, or could we get some sort of flag to allow {$unused(x,y,z)} to be silently ignored so that it is possible to write code that is source compatible?
I don't really like this syntax, because (our) compiler directives usually don't refer directly to language elements (identifiers).
So I'd rather tend to ignore it -- perhaps ignore `{$unused...}' in Mac mode with a warning otherwise (or only if `-pedantic'?), just like we ignore several BP directives?
Ignoring it would be fine, preferably not only in Mac mode, it would need its own switch or pedantic would be fine by me (I don't
In general it should not be too hard to search source files for "{$" or "(*$" and edit directives. My attitude in PascalP was to ignore all unrecognized directives, and to spit out a warning for any such. After all, they are comments.
In general it should not be too hard to search source files for "{$" or "(*$" and edit directives.
That does not help.
The original problem was to support specifying parameters as unused in a way that is source code compatible between MW and GPC. As I sated, I can specify a parameter as being unused in GPC using "attribute ( unused);" and use a define that expands to "attribute ( unused );" in GPC and nothing in MW. But I can only do this in MW by using {$unused(paramname)} which I cannot "hide" from GPC since I can't use a macro to expand to a pragma.
I don't mind (indeed am clearly perfectly willing) changing the source code to whatever is required to make it source code compatible, but currently there is no mechanism to suppress the warning that is source code compatible between the two.
At 7:53 -0400 20/9/04, CBFalconer wrote:
My attitude in PascalP was to ignore all unrecognized directives, and to spit out a warning for any such. After all, they are comments.
Since the initial comment is to suppress a warning, adding a warning to complain about the attempt to suppress a warning would sort of defeat the purpose! Peter. -- http://www.stairways.com/ http://download.stairways.com/
Peter N Lewis wrote:
Another (non-portable) option, would be if we had the way of explicitly specifying "throw away the result" akin to C's (void) (which sadly is needed more and more for compatibility with the idiotic C calls that pointlessly return their parameter),
GPC supports `attribute (ignorable)' now on function declarations for exactly this purpose. But if you don't like (for aesthetic or MW compatibility reasons) to call such functions like procedures, you will need something else indeed. (And it doesn't help for unused parameters, either.)
then that could be used to accomplish this without a dummy variable, but would not solve the problem of source code compatibility, although it would change the location of the GPC macro and make it somewhat clearer and more consistent in location.
For example, if GPC supported a syntax like:
nil := whatever
Then that could be used to both throw away function results (but clearly mark them in the code which is exactly as safe as writing dummy_result := whatever) as well as provide a mechanism for "using" unused variables.
I agree with the semantics, but as you might remember, we had such a discussion, and I expressed my concerns about that 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.
On 31 Dec 2003 I wrote:
: I already stated the problems I see with this syntax. Unlesss you : can address these concerns, just repeating the suggestion is quite : pointless.
After that mail the other thread seems to have ended, so I haven't done anything about it since then. Still I prefer such a built-in procedure.
BTW, is `nil := ...' MW syntax? Does MW support macros with arguments? If so, you could on the MW side define a macro `Discard (foo)' that expands to `nil := (foo)'.
Unfortunately, while I could probably define a macro like:
{$ifdef __GPC__} {$definec NOTUSED attribute(unused)} {$elsec} {$definec NOTUSED } {$endc}
and add the NOTUSED entries to my parameters, I cannot think of any way to get GPC to ignore or udnerstand the {$unused( param_name )}
Could $unused either be supported to disable the warning for a variable/parameter, or could we get some sort of flag to allow {$unused(x,y,z)} to be silently ignored so that it is possible to write code that is source compatible?
I don't really like this syntax, because (our) compiler directives usually don't refer directly to language elements (identifiers).
So I'd rather tend to ignore it -- perhaps ignore `{$unused...}' in Mac mode with a warning otherwise (or only if `-pedantic'?), just like we ignore several BP directives?
Ignoring it would be fine, preferably not only in Mac mode, it would need its own switch or pedantic would be fine by me (I don't generally use Mac mode as such even though it is Mac specific because I want to access the general GPC facilities in as GPC a manner as possible). Ignoring {$unused} should be safe for anything other than pedantic mode since other than leading to a possible source compatibility issue, it can't do any real damage since it only hides a warning and if it is ignored by GPC it will just mean the warning is displayed again...
OK. Do we still need this if we add `Discard'?
The original problem was to support specifying parameters as unused in a way that is source code compatible between MW and GPC. As I sated, I can specify a parameter as being unused in GPC using "attribute ( unused);" and use a define that expands to "attribute ( unused );" in GPC and nothing in MW. But I can only do this in MW by using {$unused(paramname)} which I cannot "hide" from GPC since I can't use a macro to expand to a pragma.
BTW, a future GPC version might allow macros that expand to compiler-directives, but AFAICS this wouldn't help here since you'd need this on the MW side where it apparently isn't possible.
Frank
At 0:17 +0200 21/9/04, Frank Heckenbach wrote:
I agree with the semantics, but as you might remember, we had such a discussion, and I expressed my concerns about that syntax:
Yes, I wasn't trying to reopen the debate on that issue.
BTW, is `nil := ...' MW syntax?
No no, that is just something I made up, its always seemed to me to be the most applicable syntax since nil is such a recognizable thing.
Does MW support macros with arguments? If so, you could on the MW side define a macro `Discard (foo)' that expands to `nil := (foo)'.
No, MW does not have any such facility either.
BTW, I do use "attribute( ignorable )" on function definitions where appropriate.
Ignoring it would be fine, preferably not only in Mac mode, it would need its own switch or pedantic would be fine by me (I don't generally use Mac mode as such even though it is Mac specific because I want to access the general GPC facilities in as GPC a manner as possible). Ignoring {$unused} should be safe for anything other than pedantic mode since other than leading to a possible source compatibility issue, it can't do any real damage since it only hides a warning and if it is ignored by GPC it will just mean the warning is displayed again...
OK. Do we still need this if we add `Discard'?
Yes, because Discard could not be implemented in MW (at least I don't see any way to do it with a Macro that would make the equivalent of {$unused}.
The original problem was to support specifying parameters as unused in a way that is source code compatible between MW and GPC. As I sated, I can specify a parameter as being unused in GPC using "attribute ( unused);" and use a define that expands to "attribute ( unused );" in GPC and nothing in MW. But I can only do this in MW by using {$unused(paramname)} which I cannot "hide" from GPC since I can't use a macro to expand to a pragma.
BTW, a future GPC version might allow macros that expand to compiler-directives, but AFAICS this wouldn't help here since you'd need this on the MW side where it apparently isn't possible.
Correct.
The nice thing about GPC is it is still in development, so essentially for any code compatibility between GPC and MW, GPC is the only place to turn. I don't mind adjusting my source code (as long as it is not too hideous), I just need some way to write code that is source compatible.
Thanks, Peter.
Peter N Lewis wrote:
Ignoring it would be fine, preferably not only in Mac mode, it would need its own switch or pedantic would be fine by me (I don't generally use Mac mode as such even though it is Mac specific because I want to access the general GPC facilities in as GPC a manner as possible). Ignoring {$unused} should be safe for anything other than pedantic mode since other than leading to a possible source compatibility issue, it can't do any real damage since it only hides a warning and if it is ignored by GPC it will just mean the warning is displayed again...
OK. Do we still need this if we add `Discard'?
Yes, because Discard could not be implemented in MW (at least I don't see any way to do it with a Macro that would make the equivalent of {$unused}.
BTW, what do you do with unwanted function results in MW? Does `{$unused}' also apply there?
Frank
Yes, because Discard could not be implemented in MW (at least I don't see any way to do it with a Macro that would make the equivalent of {$unused}.
BTW, what do you do with unwanted function results in MW? Does `{$unused}' also apply there?
No. {$unused(x,y,z)} accepts variable names only.
MW Pascal has no solution for throwing away unwanted results. Peter.
Peter N Lewis wrote:
Yes, because Discard could not be implemented in MW (at least I
don't
see any way to do it with a Macro that would make the equivalent of {$unused}.
BTW, what do you do with unwanted function results in MW? Does `{$unused}' also apply there?
No. {$unused(x,y,z)} accepts variable names only.
MW Pascal has no solution for throwing away unwanted results.
MW Pascal has:
{$pragmac noreturn on} {$pragmac noreturn off}
By the way, what about the following (see my email of August 4)
{$W no-unused} {$W no-unused-function} {$W no-unused-value} {$W no-unused-parameter} {$W no-unused-label} {$W no-unused-variable} {$W no-unused-function}
Regards,
Adriaan van Os
Adriaan van Os wrote:
By the way, what about the following (see my email of August 4)
{$W no-unused} {$W no-unused-function} {$W no-unused-value} {$W no-unused-parameter} {$W no-unused-label} {$W no-unused-variable} {$W no-unused-function}
Still on my list ...
Frank
Peter N Lewis wrote:
... snip ...
BTW, what do you do with unwanted function results in MW? Does `{$unused}' also apply there?
No. {$unused(x,y,z)} accepts variable names only.
MW Pascal has no solution for throwing away unwanted results.
The standard Pascal solution is to define a variable named 'junk' (or whatever else floats your boat) and put all such items there.
CBFalconer wrote:
Peter N Lewis wrote:
... snip ...
BTW, what do you do with unwanted function results in MW? Does `{$unused}' also apply there?
No. {$unused(x,y,z)} accepts variable names only.
MW Pascal has no solution for throwing away unwanted results.
The standard Pascal solution is to define a variable named 'junk' (or whatever else floats your boat) and put all such items there.
This was already mentioned. It's what I'm doing now. The disadvantage is that you need one such variable for each type and in each routine (making them global would defeat optimization quite a bit).
Frank
The problem is, that using variables may only delay the problem:
procedure dummy(x, y: integer);
var a: integer;
begin
a := x; a := y
end;
(or similar), would work today, then tomorrow when the compiler gets better dead code elimination, it figgures out that a isn't used for anything, and you are back to getting the warning. No matter how complex the code you use to attempt to "fool" the compiler into thinking you are using the var, there is always a higher level opto that can figgure out that you aren't doing real work.
IP Pascal uses:
procedure dummy(x, y: integer);
var a: integer;
begin
reference(x); reference(y)
end;
Which is straightforward. Reference is a built-in that sets the variable as referenced.
CBFalconer wrote:
Peter N Lewis wrote:
... snip ...
BTW, what do you do with unwanted function results in MW? Does `{$unused}' also apply there?
No. {$unused(x,y,z)} accepts variable names only.
MW Pascal has no solution for throwing away unwanted results.
The standard Pascal solution is to define a variable named 'junk' (or whatever else floats your boat) and put all such items there.
Scott Moore wrote:
The problem is, that using variables may only delay the problem:
procedure dummy(x, y: integer);
var a: integer;
begin
a := x; a := y
end;
(or similar), would work today, then tomorrow when the compiler gets better dead code elimination, it figgures out that a isn't used for anything, and you are back to getting the warning. No matter how complex the code you use to attempt to "fool" the compiler into thinking you are using the var, there is always a higher level opto that can figgure out that you aren't doing real work.
IP Pascal uses:
procedure dummy(x, y: integer);
var a: integer;
begin
reference(x); reference(y)
end;
Which is straightforward. Reference is a built-in that sets the variable as referenced.
I basically agree. Can your `reference' also be used to throw away unwanted function results, or is it only for variables?
Frank
No, I still use the stupid way:
function stuff: integer;
begin
stuff := 0
end;
To me the idea is, parameters can be safely ignored (there is also a "reference check off" switch /nrf or /norefer, but that affects the entire program). Functions always return *something*, so you might as well specify what it is, even for a dummy function. Otherwise, you are asking the compiler to guess for you.
Probally the bottom line is that its a lot less trouble than pinning down all those parameters.
To come clean, I use the /norefer flag a lot on new code. Hey, I'm lazy. On the other hand, my previous compiler (SVS 386 Pascal) either didn't do reference checking, or I didn't have it on, and I found my code littered with excess variables when I moved to IP Pascal.
Frank Heckenbach wrote:
I basically agree. Can your `reference' also be used to throw away unwanted function results, or is it only for variables?
Frank
Scott Moore wrote:
No, I still use the stupid way:
function stuff: integer;
begin
stuff := 0
end;
To me the idea is, parameters can be safely ignored (there is also a "reference check off" switch /nrf or /norefer, but that affects the entire program). Functions always return *something*, so you might as well specify what it is, even for a dummy function. Otherwise, you are asking the compiler to guess for you.
Indeed. Actually according to the standards it's an *error* if you don't (and GPC treats it so).
What I meant is for the caller to ignore the result of a function (i.e., basically, to use a function like a procedure). Besides the mentioned useless results in C functions, there can be useful cases even in Pascal code where a result is sometimes, but not always needed.
To come clean, I use the /norefer flag a lot on new code. Hey, I'm lazy. On the other hand, my previous compiler (SVS 386 Pascal) either didn't do reference checking, or I didn't have it on, and I found my code littered with excess variables when I moved to IP Pascal.
Same here for code I (or someone else) previously compiled with Borland Pascal or with GPC without warnings.
Frank
On 22 Sep 2004 at 9:30, Scott Moore wrote:
The problem is, that using variables may only delay the problem:
procedure dummy(x, y: integer);
var a: integer;
begin
a := x; a := y
end;
(or similar), would work today, then tomorrow when the compiler gets better dead code elimination, it figgures out that a isn't used for anything, and you are back to getting the warning.
Indeed. Delphi already issues warnings in such cases.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/
At 9:30 -0700 22/9/04, Scott Moore wrote:
The problem is, that using variables may only delay the problem:
procedure dummy(x, y: integer);
var a: integer;
begin
a := x; a := y
end;
(or similar), would work today, then tomorrow when the compiler gets better dead code elimination, it figgures out that a isn't used for anything, and you are back to getting the warning.
Actually, this already happens with MW Pascal, if you turn up the optimization level the warnings would come back for that case.
There is also the negative case where the parameter being ignored is a var large record/array, and thus unless the optimization works that results in lots of wasted stack space (potentially stack overflowing in fact) and CPU time (although you can then convert to junk := r.field or junk := a[1], further obscuring the purpose of the code).
IP Pascal uses: reference(x);
Which is straightforward. Reference is a built-in that sets the variable as referenced.
Nice. I'm happy with that as a GPC solution (it looks similar to what Frank was after, and we might as well be compatible with something as make up something new). I'll still need the {$unused(x,y,z)} either supported or ignored for compatibility.
Enjoy, Peter.
Peter N Lewis wrote:
IP Pascal uses: reference(x);
Which is straightforward. Reference is a built-in that sets the variable as referenced.
Nice. I'm happy with that as a GPC solution (it looks similar to what Frank was after, and we might as well be compatible with something as make up something new).
We might. But I'm still unsure, if it looks reasonable when used for ignoring function results (that's why I asked Scott whether he uses it for that purpose as well). Would `Reference (MyFunc (a, b, c))' seem clear as to what it'd mean?
(And if we do, should we add an `--ip-pascal' option and otherwise say `Reference is a feature of IP Pascal' ...? ;-)
Frank
Frank Heckenbach wrote:
Peter N Lewis wrote:
IP Pascal uses: reference(x);
Which is straightforward. Reference is a built-in that sets the variable as referenced.
Nice. I'm happy with that as a GPC solution (it looks similar to what Frank was after, and we might as well be compatible with something as make up something new).
We might. But I'm still unsure, if it looks reasonable when used for ignoring function results (that's why I asked Scott whether he uses it for that purpose as well). Would `Reference (MyFunc (a, b, c))' seem clear as to what it'd mean?
(And if we do, should we add an `--ip-pascal' option and otherwise say `Reference is a feature of IP Pascal' ...? ;-)
Frank
Too scary to be a joke !
Scott Moore wrote:
IP Pascal uses:
procedure dummy(x, y: integer);
var a: integer;
begin
reference(x); reference(y)
end;
Which is straightforward. Reference is a built-in that sets the variable as referenced.
Sorry, but I fiind it absurd to write actual code to get rid of an unwanted warning (even if the actual code translates into dummy code). Why do we want warnings anyway ? Well, if there are many warnings on every build or compile, that only irritates the programmer and the warnings will miss their purpose. So, the idea is to have software that eventually compiles without warnings. There are two valid ways to get rid of warnings. The programmer carefully inspects the program source that produces the warning and then decides:
(1) the compiler is right, the source is dangerous and should be changed, òr (2) the compiler warning is irrelevant (or wrong) in the specific context of a portion of the source code, the compiler should stop complaining there.
In the second case, we need fine control over warnings, that is, a compiler directive to put specific warnings off locally with {$local W no-xxx} ... {$endlocal} or whatever.
Now, to the case of unused parameters - they don't hurt, unused parameters won't crash software. But - apparently we missed an opportunity to eliminate the unused parameter to make the software faster (at least in theory). However, this leads to problems when the parameter list of a procedure or function can not be changed, as is the case with e.g. callback routines. For those routines, we can should be able to put the check off with {$local W no-unused-parameter} ... {$endlocal}.
That's all - sorry, I don't see why need need control over individual parameters.
By the way, If the compiler were to eliminate unused parameters automatically, callback routines (and other fixed parameter list routines) will need local compiler directives anyway.
Peter N. Lewis wrote:
I'll still need the {$unused(x,y,z)} either supported or ignored for compatibility.
{$ifc defined __MWERKS__} ... {$endc} will ignore the warning in GPC.
Regards,
Adriaan van Os
Adriaan van Os wrote:
Scott Moore wrote:
IP Pascal uses:
procedure dummy(x, y: integer);
var a: integer;
begin
reference(x); reference(y)
end;
Which is straightforward. Reference is a built-in that sets the variable as referenced.
Sorry, but I fiind it absurd to write actual code to get rid of an unwanted warning (even if the actual code translates into dummy code). Why do we want warnings anyway ? Well, if there are many warnings on every build or compile, that only irritates the programmer and the warnings will miss their purpose. So, the idea is to have software that eventually compiles without warnings.
Exactly.
There are two valid ways to get rid of warnings. The programmer carefully inspects the program source that produces the warning and then decides:
(1) the compiler is right, the source is dangerous and should be changed, òr (2) the compiler warning is irrelevant (or wrong) in the specific context of a portion of the source code, the compiler should stop complaining there.
In the second case, we need fine control over warnings, that is, a compiler directive to put specific warnings off locally with {$local W no-xxx} ... {$endlocal} or whatever.
That's one way, but it's debatable whether it's the best way.
Some year ago, people (including myself) used to use `{$W-} ... {$W+}' around such code portions, in the absence of many finer-grained warning options (as well as `{$local}', but that's a side-issue here). Obviously, this lead to some justified warnings ignored occasionally.
Now, a local "no-unused-warnings" options would be finer-grained than `W-', but still not as much as possible. For one thing, it concerns all parameters. One can imagine a fixed parameter form where some parameters are always needed, and some are "optional", so you do want warnings if you don't used the required parameters.
Another thing, you'd have to enclose the whole routine (not just the header) with this option since the fact that parameters are unused turns out at the end of the routine (unless you put the directive around the final `end;' or such which also obscures the matter). But then it affects also subroutines which generally don't have the same fixed parameter form, so you want warnings there.
Now, to the case of unused parameters - they don't hurt, unused parameters won't crash software.
Crashing is not the only kind of bug.
But - apparently we missed an opportunity to eliminate the unused parameter to make the software faster (at least in theory). However, this leads to problems when the parameter list of a procedure or function can not be changed, as is the case with e.g. callback routines. For those routines, we can should be able to put the check off with {$local W no-unused-parameter} ... {$endlocal}.
That's all - sorry, I don't see why need need control over individual parameters.
I'd prefer to. In addition, since I sometimes want to discard other values (function results), it might be preferable to do both things with a common syntax.
By the way, If the compiler were to eliminate unused parameters automatically, callback routines (and other fixed parameter list routines) will need local compiler directives anyway.
I don't think this will ever happen, except for inlined routines where the problem doesn't arise.
Frank
Frank Heckenbach wrote:
Now, a local "no-unused-warnings" options would be finer-grained than `W-', but still not as much as possible. For one thing, it concerns all parameters. One can imagine a fixed parameter form where some parameters are always needed, and some are "optional", so you do want warnings if you don't used the required parameters.
It depends on the implementation, it could be as fine-grained as we want it to be. So, if we need control over individual parameters, local warning directives could be put in the header around individual parameters.
Another thing, you'd have to enclose the whole routine (not just the header) with this option since the fact that parameters are unused turns out at the end of the routine (unless you put the directive around the final `end;' or such which also obscures the matter).
That would indeed obscure the matter. What I like about Pascal is writing software that achieves the highest possible degree of transparency and translucency. A Pascal algorithm shouldn't be a bunch of tricks but an elegant expression of clear logical ideas. So, in this case, if we want the advantages of unused-parameter checking, we need a way to say "hey, this is a routine with unused parameters" or "hey, this parameter is unused". That information belongs in the header, not in the body. Next, it is a matter of compiler implementation to use that information to do the actual unused-parameter check in the body (or not). The compiler could/should remember all information specified in the header, including compiler directives.
However, using a trick in the body to make an unused-parameter look like a used parameter obscures the matter. It has nothing to do with the logic of the actual algorithm which dictates that the parameter is *not* used. So any statement in the body that specifies otherwise (to make the warning go away) obscures the matter. I call that upside-down thinking.
But then it affects also subroutines which generally don't have the same fixed parameter form, so you want warnings there.
This is no longer a problem if local warning directives can be specified in the header.
Now, to the case of unused parameters - they don't hurt, unused parameters won't crash software.
Crashing is not the only kind of bug.
OK.
But - apparently we missed an opportunity to eliminate the unused parameter to make the software faster (at least in theory). However, this leads to problems when the parameter list of a procedure or function can not be changed, as is the case with e.g. callback routines. For those routines, we can should be able to put the check off with {$local W no-unused-parameter} ... {$endlocal}.
That's all - sorry, I don't see why need need control over individual parameters.
I'd prefer to.
OK.
In addition, since I sometimes want to discard other values (function results), it might be preferable to do both things with a common syntax.
Discarding a mechanical result value, actually returned by a function, is something completely different from the logical specification of an unused parameter. Nothing is discarded in the latter case. It only looks like we are discarding something once we take the (strange) decision to reference an "unused" parameter without actually using it. In other words, we then need a way to "use" a parameter it without "using" it, which brings us to the idea of "discarding" it. Sorry if I sound a bit sharp.
Regards,
Adriaan van Os
Adriaan van Os wrote:
Frank Heckenbach wrote:
Now, a local "no-unused-warnings" options would be finer-grained than `W-', but still not as much as possible. For one thing, it concerns all parameters. One can imagine a fixed parameter form where some parameters are always needed, and some are "optional", so you do want warnings if you don't used the required parameters.
It depends on the implementation, it could be as fine-grained as we want it to be. So, if we need control over individual parameters, local warning directives could be put in the header around individual parameters.
Another thing, you'd have to enclose the whole routine (not just the header) with this option since the fact that parameters are unused turns out at the end of the routine (unless you put the directive around the final `end;' or such which also obscures the matter).
That would indeed obscure the matter. What I like about Pascal is writing software that achieves the highest possible degree of transparency and translucency. A Pascal algorithm shouldn't be a bunch of tricks but an elegant expression of clear logical ideas. So, in this case, if we want the advantages of unused-parameter checking, we need a way to say "hey, this is a routine with unused parameters" or "hey, this parameter is unused". That information belongs in the header, not in the body. Next, it is a matter of compiler implementation to use that information to do the actual unused-parameter check in the body (or not). The compiler could/should remember all information specified in the header, including compiler directives.
It seems you misunderstand what compiler directives are or how they work. Compiler directives (as in GPC, and AFAIK also BP, Delphi and other compilers) switch certain compiler settings *while* the source is being processed.
The `-Wunused...' options mean (by definition) "warn about all undefined ...'s". Making it a compiler directive would then mean "warn about all undefined ...'s while the directive is turned on".
You may wish that it would mean "warn about all undefined ...'s that were declared while the directive was turned on", but that's not the way it works.
What's more like what you have in mind might be attributes on the parameters, as e.g. the GNU C compiler allows for. I've also thought about them in this context, and probably we could implement them. The disadvantages I see are (a) it adds another bit of extra nonstandard syntax (even if the attribute syntax is already there in GPC, adding another place where it's allowed means new syntax), (b) it doesn't care take of discarding function results, so we'd still want to add another thing. (I'd rather add one general thing than several more specific things, and again, adding a built-in "procedure", even with nonstandard semantics, is a less severe change than adding new syntax.)
In addition, since I sometimes want to discard other values (function results), it might be preferable to do both things with a common syntax.
Discarding a mechanical result value, actually returned by a function, is something completely different from the logical specification of an unused parameter. Nothing is discarded in the latter case.
Sure, something is discarded! The caller passes some value (or reference) in the parameter, and the called routine discards this value.
Frank
Adriaan van Os wrote:
Scott Moore wrote:
IP Pascal uses:
procedure dummy(x, y: integer); var a: integer; begin reference(x); reference(y) end;
Which is straightforward. Reference is a built-in that sets the variable as referenced.
Sorry, but I fiind it absurd to write actual code to get rid of an unwanted warning (even if the actual code translates into dummy code). Why do we want warnings anyway ? Well, if there are many warnings on every build or compile, that only irritates the programmer and the warnings will miss their purpose. So, the idea is to have software that eventually compiles without warnings. There are two valid ways to get rid of warnings. The programmer carefully inspects the program source that produces the warning and then decides:
(1) the compiler is right, the source is dangerous and should be changed, òr (2) the compiler warning is irrelevant (or wrong) in the specific context of a portion of the source code, the compiler should stop complaining there.
In the second case, we need fine control over warnings, that is, a compiler directive to put specific warnings off locally with {$local W no-xxx} ... {$endlocal} or whatever.
Now, to the case of unused parameters - they don't hurt, unused parameters won't crash software. But - apparently we missed an opportunity to eliminate the unused parameter to make the software faster (at least in theory). However, this leads to problems when the parameter list of a procedure or function can not be changed, as is the case with e.g. callback routines. For those routines, we can should be able to put the check off with {$local W no-unused-parameter} ... {$endlocal}.
This brings up the more general subject of the attitude to warnings. Pascal is not C. In C many, if not most, warnings indicate a serious situation where the probability of bad code is high, if not certain. Pascal has so many more internal checks that warnings tend to be just that, and the probability that the code does what is intended is much higher.
Thus the Pascal programmer should be prepared to evaluate and accept warnings on compilation. This attitude is probably not fatal, as it would be in C. In particular an unused parameter falls into this classification.
On 24 Sep 2004 at 6:27, CBFalconer wrote:
[....]
This brings up the more general subject of the attitude to warnings. Pascal is not C. In C many, if not most, warnings indicate a serious situation where the probability of bad code is high, if not certain. Pascal has so many more internal checks that warnings tend to be just that, and the probability that the code does what is intended is much higher.
Thus the Pascal programmer should be prepared to evaluate and accept warnings on compilation. This attitude is probably not fatal, as it would be in C. In particular an unused parameter falls into this classification.
May I suggest another approach? Both Delphi and FreePascal have "warnings" and "hints". Warnings are for serious things that can hide bugs, while hints are for less serious things. Can we assign some of these things to "hints", and then have a switch to turn hinting on and off?
Example;
This program;
program warn;
function bar : integer; begin writeln ('bar'); end;
procedure foo (x, y : integer); begin y := bar; writeln (y); y := 0; end;
var x : integer; y : byte;
begin x := 1234; writeln (y); end.
Generates this, when compiled with Delphi: E:\temp\warn.pas(6) Warning: Return value of function 'bar' might be undefined E:\temp\warn.pas(12) Hint: Value assigned to 'y' never used E:\temp\warn.pas(20) Hint: Value assigned to 'x' never used E:\temp\warn.pas(21) Warning: Variable 'y' might not have been initialized
And generates this, when compiled with FPC: warn.pas(6,1) Warning: Function result does not seem to be set warn.pas(8,16) Hint: Parameter X not used warn.pas(21,15) Warning: Variable Y does not seem to be initialized warn.pas(8,11) Hint: Local proc FOO is not used warn.pas(16,1) Note: Local variable X is assigned but never used
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/
Delphi 7 Professional and probably other versions:
With a project open, choose
Project Options Compiler Messages
Check boxes X Show Hints X Show Warnings
Then a list of about 50 warnings, with check boxes, that the user can turn on/off. (There could be more.)
Surely much better than an endless philosophical disputation on what warnings should/should not be given:
Let the user choose -- caveat emptor.
Prof. Harley Flanders
----- Original Message ----- From: Prof A Olowofoyeku (The African Chief) To: gpc@gnu.de Sent: Friday, September 24, 2004 9:53 AM Subject: Re: Unused parameter warnings
On 24 Sep 2004 at 6:27, CBFalconer wrote:
[....]
This brings up the more general subject of the attitude to warnings. Pascal is not C. In C many, if not most, warnings indicate a serious situation where the probability of bad code is high, if not certain. Pascal has so many more internal checks that warnings tend to be just that, and the probability that the code does what is intended is much higher.
Thus the Pascal programmer should be prepared to evaluate and accept warnings on compilation. This attitude is probably not fatal, as it would be in C. In particular an unused parameter falls into this classification.
May I suggest another approach? Both Delphi and FreePascal have "warnings" and "hints". Warnings are for serious things that can hide bugs, while hints are for less serious things. Can we assign some of these things to "hints", and then have a switch to turn hinting on and off?
Example;
This program;
program warn;
function bar : integer; begin writeln ('bar'); end;
procedure foo (x, y : integer); begin y := bar; writeln (y); y := 0; end;
var x : integer; y : byte;
begin x := 1234; writeln (y); end.
Generates this, when compiled with Delphi: E:\temp\warn.pas(6) Warning: Return value of function 'bar' might be undefined E:\temp\warn.pas(12) Hint: Value assigned to 'y' never used E:\temp\warn.pas(20) Hint: Value assigned to 'x' never used E:\temp\warn.pas(21) Warning: Variable 'y' might not have been initialized
And generates this, when compiled with FPC: warn.pas(6,1) Warning: Function result does not seem to be set warn.pas(8,16) Hint: Parameter X not used warn.pas(21,15) Warning: Variable Y does not seem to be initialized warn.pas(8,11) Hint: Local proc FOO is not used warn.pas(16,1) Note: Local variable X is assigned but never used
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/
Prof. Harley Flanders wrote:
Then a list of about 50 warnings, with check boxes, that the user can turn on/off. (There could be more.)  Surely much better than an endless philosophical disputation on what warnings should/should not be given:  Let the user choose -- caveat emptor.
That is not what the debate is about. GPC already has a long list of command-line switches that deal with warnings (in casu -Wno-unused-parameter). So, the ablilty to put them on or off is already there. The debate is about what to do if an otherwise useful warning (that you don't want to switch off entirely) produces an irrelevant warning in a specific context.
Regards,
Adriaan van Os
Prof A Olowofoyeku (The African Chief) wrote:
On 24 Sep 2004 at 6:27, CBFalconer wrote:
[....]
This brings up the more general subject of the attitude to warnings. Pascal is not C. In C many, if not most, warnings indicate a serious situation where the probability of bad code is high, if not certain. Pascal has so many more internal checks that warnings tend to be just that, and the probability that the code does what is intended is much higher.
Thus the Pascal programmer should be prepared to evaluate and accept warnings on compilation. This attitude is probably not fatal, as it would be in C. In particular an unused parameter falls into this classification.
May I suggest another approach? Both Delphi and FreePascal have "warnings" and "hints". Warnings are for serious things that can hide bugs, while hints are for less serious things. Can we assign some of these things to "hints", and then have a switch to turn hinting on and off?
I'm not sure this would really help. In the end, what would it mean? Is it ok to compile with one hint per 100 lines of code? When you say, warnings are for things that can hide bugs, the same goes for these hints. Not using a parameter usually indicates a bug -- it only makes sense in special situations (fixed parameter forms).
Example;
function bar : integer; begin writeln ('bar'); end;
Generates this, when compiled with Delphi: E:\temp\warn.pas(6) Warning: Return value of function 'bar' might be undefined
Well, according to the standards this is an error even. I don't see any reason in weakening this to a warning.
Frank
On 24 Sep 2004 at 16:50, Frank Heckenbach wrote:
Prof A Olowofoyeku (The African Chief) wrote:
On 24 Sep 2004 at 6:27, CBFalconer wrote:
[....]
This brings up the more general subject of the attitude to warnings. Pascal is not C. In C many, if not most, warnings indicate a serious situation where the probability of bad code is high, if not certain. Pascal has so many more internal checks that warnings tend to be just that, and the probability that the code does what is intended is much higher.
Thus the Pascal programmer should be prepared to evaluate and accept warnings on compilation. This attitude is probably not fatal, as it would be in C. In particular an unused parameter falls into this classification.
May I suggest another approach? Both Delphi and FreePascal have "warnings" and "hints". Warnings are for serious things that can hide bugs, while hints are for less serious things. Can we assign some of these things to "hints", and then have a switch to turn hinting on and off?
I'm not sure this would really help. In the end, what would it mean?
It means that not every problem generates a warning, since some will only generate hints. It also means that, in the light of this long thread, one can turn off hints, while leaving warnings, and hopefully provide a solution to those who sometimes want warnings and sometimes don't (assuming they will be satisfied with hints instead of warnings).
Is it ok to compile with one hint per 100 lines of code?
That is a matter for the programmer. Programmer emptor. In my experience, Delphi generates hints when the code is not dangerous, but might be inefficient or superfluous (as in my examples). So, a million hints are perfectly fine - your program will not do anything unexpected - but it might be wasting memory, or otherwise be doing unnecessary things, hence running (marginally?) slower, or getting unnecessary (marginal?) bloat in the size of your executables. I tend to ignore hints - but sometimes it is easier to just remove the superfluous code so that the hint goes away.
When you say, warnings are for things that can hide bugs, the same goes for these hints.
Not necessarily. I have seen so many redundant assignments that generate hints that do not hide any bugs (such as those in my example). I am yet to see only a generated hint in a situation where there is a possible bug (in the sense of the program possibly behaving incorrectly, crashing or otherwise behaving unexpectedly).
Not using a parameter usually indicates a bug
Agreed.
-- it only makes sense in special situations (fixed parameter forms).
If callback routines are an example of this, then yes.
Example;
function bar : integer; begin writeln ('bar'); end;
Generates this, when compiled with Delphi: E:\temp\warn.pas(6) Warning: Return value of function 'bar' might be undefined
Well, according to the standards this is an error even. I don't see any reason in weakening this to a warning.
Presumably it will not generate an error in BP/Delphi mode? (else you lose compatibility). In Delphi mode it should only generate a warning.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/
Prof A Olowofoyeku (The African Chief) wrote:
Not necessarily. I have seen so many redundant assignments that generate hints that do not hide any bugs (such as those in my example). I am yet to see only a generated hint in a situation where there is a possible bug (in the sense of the program possibly behaving incorrectly, crashing or otherwise behaving unexpectedly).
Not using a parameter usually indicates a bug
Agreed.
So these should in general not be hints, I conclude.
-- it only makes sense in special situations (fixed parameter forms).
If callback routines are an example of this, then yes.
Yes, they are the typical example (together with other kinds of procedural parameters). Then there are (some) virtual methods, and probably some other cases. Too many to ignore this as an exotic case, but too few to accept unused parameters in general, IMHO.
Frank
On 25 Sep 2004 at 16:32, Frank Heckenbach wrote:
Prof A Olowofoyeku (The African Chief) wrote:
Not necessarily. I have seen so many redundant assignments that generate hints that do not hide any bugs (such as those in my example). I am yet to see only a generated hint in a situation where there is a possible bug (in the sense of the program possibly behaving incorrectly, crashing or otherwise behaving unexpectedly).
Not using a parameter usually indicates a bug
Agreed.
So these should in general not be hints, I conclude.
Perhaps. I would personally prefer hints here, since the only times that I have come across this in my own code have been when using callbacks or when experimenting. Hints are sufficient to let you see the problem, and are less problematic when you regularly use -Werror.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/
Prof A Olowofoyeku (The African Chief) wrote:
On 25 Sep 2004 at 16:32, Frank Heckenbach wrote:
Prof A Olowofoyeku (The African Chief) wrote:
Not necessarily. I have seen so many redundant assignments that generate hints that do not hide any bugs (such as those in my example). I am yet to see only a generated hint in a situation where there is a possible bug (in the sense of the program possibly behaving incorrectly, crashing or otherwise behaving unexpectedly).
Not using a parameter usually indicates a bug
Agreed.
So these should in general not be hints, I conclude.
Perhaps. I would personally prefer hints here, since the only times that I have come across this in my own code have been when using callbacks or when experimenting. Hints are sufficient to let you see the problem, and are less problematic when you regularly use -Werror.
Sure -- when experimenting I sometimes turn off `-Werror' myself ...
(For callbacks etc., once we have an accepted mechanism, such as `Discard', one can just as well add it immediately.)
Adding hints would probably be some work (a new "infrastructure" and various checks and stuff we now have for errors and warnings). I'm not conviced this is justified ...
Frank
On 25 Sep 2004 at 19:13, Frank Heckenbach wrote:
[...]
So these should in general not be hints, I conclude.
Perhaps. I would personally prefer hints here, since the only times that I have come across this in my own code have been when using callbacks or when experimenting. Hints are sufficient to let you see the problem, and are less problematic when you regularly use -Werror.
Sure -- when experimenting I sometimes turn off `-Werror' myself ...
(For callbacks etc., once we have an accepted mechanism, such as `Discard', one can just as well add it immediately.)
Adding hints would probably be some work (a new "infrastructure" and various checks and stuff we now have for errors and warnings). I'm not conviced this is justified ...
No sweat. I just thought this might help those who are not happy with things as they are. I am perfectly happy with the status quo ...
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/
gpc is down, so my copy of the GPC manual might be old, but I cannot find an entry in the GPC manual for it.
Does GPC implememt overloads ?
Scott Moore wrote:
gpc is down, so my copy of the GPC manual might be old, but I cannot find an entry in the GPC manual for it.
gpc -v
tells the version (YYYYMMDD). The last (alpha) ist 20040516. The next one is due soon, perhaps in a week. (If the server isn't back by then, I might put it on an alternative site.)
Does GPC implememt overloads ?
Operator overloads (both predefined and new operators). Function overloading is planned, but not yet supported.
Frank
On 26 Sep 2004 at 0:15, Frank Heckenbach wrote:
[...]
gpc -v
tells the version (YYYYMMDD). The last (alpha) ist 20040516. The next one is due soon, perhaps in a week. (If the server isn't back by then, I might put it on an alternative site.)
I can't remember whether we have discussed this one before, but would it be possible for GPC to ignore some of the Delphi commands for exception handling - i.e., the "Try", "Except", "Finally" ... "End" blocks (perhaps with a warning that they are ignored/unsupported)?
Thanks.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/
Prof A Olowofoyeku (The African Chief) wrote:
I can't remember whether we have discussed this one before, but would it be possible for GPC to ignore some of the Delphi commands for exception handling - i.e., the "Try", "Except", "Finally" ... "End" blocks (perhaps with a warning that they are ignored/unsupported)?
You mean to treat: try Statements except on ex1 do EH1 on ex2 do EH2 else EHE finally FS end
as begin Statements; FS end
At first glance looks easy. However, we do not want to make `try', `except', `on', `finally' into reserved words. Since for most Pascal instructions prepending identifier to the instruction turns the instruction into illegal code we should be able to parse `try' blocks reserving any words. Still, there are some nasty cases (at least user defined operators cause a problem).
On the other hand we would like do things properly. I would feel guilty putting into the compiler code which just ignores some important aspect of source programs.
On 30 Sep 2004 at 13:32, Waldek Hebisch wrote:
Prof A Olowofoyeku (The African Chief) wrote:
I can't remember whether we have discussed this one before, but would it be possible for GPC to ignore some of the Delphi commands for exception handling - i.e., the "Try", "Except", "Finally" ... "End" blocks (perhaps with a warning that they are ignored/unsupported)?
You mean to treat: try Statements except on ex1 do EH1 on ex2 do EH2 else EHE finally FS end
as begin Statements; FS end
Yes
At first glance looks easy. However, we do not want to make `try', `except', `on', `finally' into reserved words. Since for most Pascal instructions prepending identifier to the instruction turns the instruction into illegal code we should be able to parse `try' blocks reserving any words. Still, there are some nasty cases (at least user defined operators cause a problem).
On the other hand we would like do things properly. I would feel guilty putting into the compiler code which just ignores some important aspect of source programs.
With warnings. Presumably, those who are sharing code between compilers that support exception handling of that kind and those that do not, are aware of the potential problem. With warnings, the ball is then left squarely in their courts.
On the other hand, the points that you have raised are significant. So I should perhaps withdraw my request, and replace it with a request that exception handling be added to GPC if at all possible.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/
Prof A Olowofoyeku (The African Chief) wrote:
On 30 Sep 2004 at 13:32, Waldek Hebisch wrote:
Prof A Olowofoyeku (The African Chief) wrote:
I can't remember whether we have discussed this one before, but would it be possible for GPC to ignore some of the Delphi commands for exception handling - i.e., the "Try", "Except", "Finally" ... "End" blocks (perhaps with a warning that they are ignored/unsupported)?
At first glance looks easy. However, we do not want to make `try', `except', `on', `finally' into reserved words. Since for most Pascal instructions prepending identifier to the instruction turns the instruction into illegal code we should be able to parse `try' blocks reserving any words. Still, there are some nasty cases (at least user defined operators cause a problem).
On the other hand we would like do things properly. I would feel guilty putting into the compiler code which just ignores some important aspect of source programs.
I feel the same. (Actually I was going to write something like this, but I waited if you had anything better to say. ;-)
On the other hand, the points that you have raised are significant. So I should perhaps withdraw my request, and replace it with a request that exception handling be added to GPC if at all possible.
I agree that it should be added. It would allow for cleaner handling of runtime errors (when wanted) and nonlocal gotos (where there are problems now) as well.
As I've said (at least in discussions with Waldek and Markus), the backend has some kind of exception support, and first we should learn about it and decide whether we can use it. If so, I'd rather do this than to reinvent the wheel. Again if so, it might mean that we'll have to require a certain backend version (3.x.y), which is planned after the release of gpc-2.2. But then I really hope we can add it soon ...
Frank
Back on the original subject, the spec for Borlands version of overloads are just awful. Virtually any difference in type between overload parameter lists is accepted as a valid overload. For example, two subranges of integer are accepted, which is clearly an ambiguous overload. Borland "resolves" this by calling the procedure or function with the smallest integer range. Thats a recipe for fairly incomprehensible behavior for the user.
Scott Moore wrote:
Back on the original subject, the spec for Borlands version of overloads are just awful. Virtually any difference in type between overload parameter lists is accepted as a valid overload. For example, two subranges of integer are accepted, which is clearly an ambiguous overload. Borland "resolves" this by calling the procedure or function with the smallest integer range. Thats a recipe for fairly incomprehensible behavior for the user.
I think I agree. For me, that's still the major open question WRT overloading.
My idea would be to check (at call time) which routine is acceptable, and give an error if it's more than one. This would be unabmiguous. OTOH, it may be too strict for some purposes. E.g., if you want to have a version that accepts a normal `Integer' parameter and one with `LongInt' for extended ranges, you couldn't do this since a value that fits in `Integer' also fits into `LongInt', so such a call would be ambiguous.
Maybe that's the motivation of Borland's decision, but I'm still skeptical of it, since the results are quite fragile.
And it's debatable whether it's even desirable to implement two such versions. The compiler can't check that their implementations are equivalent, so the results could still be confusing, even if meant well. So perhaps we should not allow that indeed (since, after all, it's only a syntactic restriction -- one can always use different names for different routines, as we do now).
Frank
Frank Heckenbach wrote:
Scott Moore wrote:
Back on the original subject, the spec for Borlands version of overloads are just awful. Virtually any difference in type between overload parameter lists is accepted as a valid overload. For example, two subranges of integer are accepted, which is clearly an ambiguous overload. Borland "resolves" this by calling the procedure or function with the smallest integer range. Thats a recipe for fairly incomprehensible behavior for the user.
I think I agree. For me, that's still the major open question WRT overloading.
My idea would be to check (at call time) which routine is acceptable, and give an error if it's more than one. This would be unabmiguous. OTOH, it may be too strict for some purposes. E.g., if you want to have a version that accepts a normal `Integer' parameter and one with `LongInt' for extended ranges, you couldn't do this since a value that fits in `Integer' also fits into `LongInt', so such a call would be ambiguous.
Maybe that's the motivation of Borland's decision, but I'm still skeptical of it, since the results are quite fragile.
And it's debatable whether it's even desirable to implement two such versions. The compiler can't check that their implementations are equivalent, so the results could still be confusing, even if meant well. So perhaps we should not allow that indeed (since, after all, it's only a syntactic restriction -- one can always use different names for different routines, as we do now).
Frank
Here are IP Pascal's rules for overloads. I just finished implementing it. Yes, it is quite strict. To me, thats less problems going forward.
==============================================================================
OVERLOAD RULES AND IMPLEMENTATION
Overloading means to allow the same identifier to represent several different types, which are differentiated by context. In IP Pascal, only functions and procedures can be overloaded:
procedure myproc;
begin
end;
overload procedure myproc(i: integer);
begin
end;
overload function myproc: integer;
begin
end;
A procedure or function can be overloaded, but only by a procedure or function that is in the same scope. A procedure or function in an outter block or in another module cannot be overloaded.
A function can overload a procedure, and a procedure can overload a function.
When a procedure or function is overloaded, the keyword "overload" is used for all procedures or functions besides the original or overloaded function or procedure. The original procedure or function retains a special status as the "prime" function or procedure.
A function or procedure can be overloaded before its actual definition appears. The following is valid:
procedure myproc; forward;
overload procedure myproc(i: integer);
begin
end;
overload function myproc: integer;
begin
end;
procedure myproc;
begin
end;
The prime procedure or function must be completed by a matching prime definition.
However, both the forwarded definition and the actual defintion must have headers, which must be "congruous" with the original header. This is necessary to establish which version of the function or procedure is being forwarded. "congruous" procedures or functions is according to the definition of the ISO 7185 standard.
Overload functions or procedures can themselves be forwarded. An overload forward must be completed by a an overload definition. Unlike ISO 7185 procedure and function declarations, forwarded overloads must allways have a complete parameter list and result. The final definition and the forward of an overload must be "congruous" in the ISO 7185 sense of procedure and functions. This is necessary because overload functions and procedures are distingished by their parameter lists and returns.
Note that if a forwarded overload definition is NOT congruous with its original forwarded declaration, then it will be assumed that it is a new overload definition, and the original forward will generate an error when it is not resolved in the containing block. In addition, since the rules of ISO 7185 congruousness are stricter than the rules for overload uniqueness, its also possible to receive an error on the overload for not being unique.
When multiple overload functions appear for the same name, their return types must be identical. Here "identical" refers to either the same type identifier, or an alias of it:
function mystuff: boolean;
begin
end;
overload funcion mystuff(i: integer): boolean;
begin
end;
This applies even if the functions are otherwise distinct, i.e., their parameter numbers and types differ. This rule allows the context for which a function result appears to be unambiguous.
Calls to an overloaded function or procedure are differentiated by the following criteria, in order:
1. Whether called as procedures or functions.
2. Number of parameters.
3. Type compatibility of parameters.
Two parameter types are compatible according to the ISO 7185 definition of type compatibility. To qualify as different variants of the same overloaded function or procedure, two parameters must not only be of different types, but those types must be incompatible with each other. An invalid example would be:
type mysub = 1..10;
procedure myproc(i: integer);
begin
end;
overload procedure myproc(v: mysub);
begin
end;
These overload forms are invalid because the parameters are ISO 7185 type compatible, even though they are different types. There is not enough difference between these parameter types to allow the overload to be differentiated.
Note that the VAR, VIEW or value status of a parameter DOES NOT serve to differentiate two overload functions or procedures from each other. The following is an invalid sample:
procedure myproc(i: integer);
begin
end;
overload myproc(var i: integer);
begin
end;
This sample is invalid because both versions of myproc are not considered different enough to be a valid overload.
Even function parameters must be different in type. What type is a function parameter ? This is determined by its return type. If a function parameter appears in an overload, then the type of other overload parameters may not be compatible with the return type of that function. This is an invalid example:
procedure myproc(function x: integer);
begin
end;
overload myproc(i: integer);
begin
end;
This sample is invalid because its possible to have a function:
function q: integer;
such that:
myproc(q);
is ambiguous as to which form of overload is indicated.
Overloaded functions and procedures cannot be passed as procedure or function parameters. The following is an illegal example:
program test;
procedure alpha;
begin
end;
procedure alpha(i: integer);
begin
end;
procedure zeta(procedure tau);
begin
end;
begin
zeta(alpha)
end.
It is ambiguous which copy of alpha gets passed to zeta, since the parameters to alpha do not appear in the call to zeta.
COINING
Overload labels in the output code are subject to the same coining rules as standard module prefix coining. In addition, overload routines are output with a special coining posfix:
procedure myproc(i: integer; c: char);
Results in:
myproc_procedure_integer_char
function myfunc(i: integer; c: char): boolean;
Results in:
myfunc_function_integer_char_boolean
The posfix consists of the sequence "_procedure" (for a procedure) or "_function" (for a function), followed by each of the names for each parameter type, followed by the name of the function result, if a function. Under the rules of IP Pascal, parameters and function results must always be named, so coining is always possible.
==================================================================================
Scott Moore wrote:
Overloaded functions and procedures cannot be passed as procedure or function parameters. The following is an illegal example:
program test;
procedure alpha;
begin
end;
procedure alpha(i: integer);
Should be `overload' I suppose.
begin
end;
procedure zeta(procedure tau);
begin
end;
begin
zeta(alpha)
end.
It is ambiguous which copy of alpha gets passed to zeta, since the parameters to alpha do not appear in the call to zeta.
You've addressed some valid concerns in your other examples, but in this case, I'm not sure what the problem is. A parameter `procedure tau' means a procedure parameter without arguments. Otherwise you'd have to write `procedure zeta(procedure tau (i: Integer));'. So I see no ambiguity here.
Or do you follow Wirth's original Pascal for procedural parmeters (which doesn't specify arguments AFAIK), rather than ISO Pascal?
Frank
Frank Heckenbach wrote:
Scott Moore wrote:
Overloaded functions and procedures cannot be passed as procedure or function parameters. The following is an illegal example:
program test;
procedure alpha;
begin
end;
procedure alpha(i: integer);
Should be `overload' I suppose.
begin
end;
procedure zeta(procedure tau);
begin
end;
begin
zeta(alpha)
end.
It is ambiguous which copy of alpha gets passed to zeta, since the parameters to alpha do not appear in the call to zeta.
You've addressed some valid concerns in your other examples, but in this case, I'm not sure what the problem is. A parameter `procedure tau' means a procedure parameter without arguments. Otherwise you'd have to write `procedure zeta(procedure tau (i: Integer));'. So I see no ambiguity here.
Or do you follow Wirth's original Pascal for procedural parmeters (which doesn't specify arguments AFAIK), rather than ISO Pascal?
Frank
I see your point, matching indirectly via the type of passed parameter. Let me study if that works for all combinations of overloads and get back to you. Say, it pays to have you guys look stuff over !
On 5 Oct 2004 at 0:08, Scott Moore wrote:
Here are IP Pascal's rules for overloads. I just finished implementing it. Yes, it is quite strict. To me, thats less problems going forward.
[....]
overload procedure myproc(i: integer);
Any particular reason for creating YAOS (yet another overload syntax)? I would have thought it reasonable to emulate an already existing and well established syntax (Delphi's).
Just curious ...
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/
Prof A Olowofoyeku (The African Chief) wrote:
On 5 Oct 2004 at 0:08, Scott Moore wrote:
Here are IP Pascal's rules for overloads. I just finished implementing it. Yes, it is quite strict. To me, thats less problems going forward.
[....]
overload procedure myproc(i: integer);
Any particular reason for creating YAOS (yet another overload syntax)? I would have thought it reasonable to emulate an already existing and well established syntax (Delphi's).
Just curious ...
Best regards, The Chief
Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/
The reasons were as follows:
1. The overload status of a procedure or function is very important while parsing the header. Therefore it saves work to specify it there.
2. The directive slot after a procedure or function:
procedure x; <directive>;
Was clearly designed such that the directive replaces the body of the procedure or function logically. I.e., both "forward" and "external" both replace the body. Having a new directive that does not replace the body is out of whack with the original intent of the syntax of a directive.
3. Taking the directive spot on a procedure or function is specific to a procedure or function. On a keyword such as "overload", it is certainly possible to extent that to other program items, such as vars or even consts. The spot in front of the item introduction (procedure, function, var, etc). I call a "modifier" and is syntatically universal.
4. IP Pascal began with modifiers in 1980, so there is long a precident for it within the IP family. This is also before Borland Pascal. Originally there were also modifiers "global", and "absolute", although these are long gone now.
Good question, thank you.
On 5 Oct 2004 at 12:41, Scott Moore wrote:
[...]
The reasons were as follows:
- The overload status of a procedure or function is very important
while parsing the header. Therefore it saves work to specify it there.
- The directive slot after a procedure or function:
procedure x; <directive>;
Was clearly designed such that the directive replaces the body of the procedure or function logically. I.e., both "forward" and "external" both replace the body. Having a new directive that does not replace the body is out of whack with the original intent of the syntax of a directive.
Well, I think that GPC is already down this route, with attributes and other stuff. I also think that GPC should aim for full compatibility with Delphi in this case.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/
"Prof A Olowofoyeku (The African Chief)" wrote:
On 5 Oct 2004 at 0:08, Scott Moore wrote:
Here are IP Pascal's rules for overloads. I just finished implementing it. Yes, it is quite strict. To me, thats less problems going forward.
[....]
overload procedure myproc(i: integer);
Any particular reason for creating YAOS (yet another overload syntax)? I would have thought it reasonable to emulate an already existing and well established syntax (Delphi's).
Any reason for creating overloaded functions in the first place? It gobbles up another reserved word, and thus violates standards, and cuts off a vital (to me) error detection mechanism. You can always simply write "myproci" and "myproc" if you wish.
CBFalconer wrote:
"Prof A Olowofoyeku (The African Chief)" wrote:
On 5 Oct 2004 at 0:08, Scott Moore wrote:
Here are IP Pascal's rules for overloads. I just finished implementing it. Yes, it is quite strict. To me, thats less problems going forward.
[....]
overload procedure myproc(i: integer);
Any particular reason for creating YAOS (yet another overload syntax)? I would have thought it reasonable to emulate an already existing and well established syntax (Delphi's).
Any reason for creating overloaded functions in the first place? It gobbles up another reserved word, and thus violates standards, and cuts off a vital (to me) error detection mechanism. You can always simply write "myproci" and "myproc" if you wish.
Another good question. I felt exactly that way about overloads a year ago. What happened is I listened to several fans of overloads, and read a book from an author who was advocating overloads for Pascal. I became a fan of overloads for procedures and functions, and also of templates, which I plan to implement as well.
The reason is that Pascal is very type strict. At least the standard version, as well as IP Pascal. Certainly lots of implementations "increase functionality" by loosening the type checking of Pascal. Overloads APPEAR to do that, without REALLY doing that. For example, you can implement C++ style "default parameters" by using overloads ability to match parameter counts. You can make a procedure that "apparently" takes several different types in the same parameter position.
None of the strict typing of Pascal is actually being violated. It just appears so. And under the rules of IP Pascal, the rules for overloads are quite strict as well.
So now back to the why, and what changed my mind about overloads and templates. Because these features give Pascal many of the attributes of "more advanced" languages like C++, with out breaking down the type safety of Pascal, I believe they will do a lot to help the perception of Pascal as an overly strict language without degrading or throwing out the type safety aspect of Pascal. The procedure or function chosen from the overload group is verified to the same type standard as normal pascal, and the criteria for the selection is also clear. Under IP rules, each parameter must be compatible under ISO 7185 rules to be selected as an overload candidate.
In fact, I think overloads and templates will help Pascal more than other languages. A non-type safe language such as C++ has many ways to subvert type checking and accomplish parameter mismatches. Pascal does not, so this "trick" allows Pascal to do what other languages can do, with out breaking what I consider Pascals main attribute, type safety.
In fact, the reason I implemented overload for IP Pascal at this time is a good example in of itself. The Windows API has many calls of the type:
WINAPI int someapifunc(stuff *x, stuff *y);
In C, that is of course how you pass a VAR parameter, you point to it, essentially do it yourself VAR parameters. But in the Windows API, the user may pass NULL for one of the pointers, which means "the parameter does not exist". This trick does not exist for Pascal, unless you pass everything to Windows via a pointer, which brings other kinds of problems to Pascal, like the need to be able to convert everything to and from a pointer (effectively breaking typing rules).
The way I have handled this in the past is to implement multiple functions:
function someapifunc(var x, y: stuff): integer;
function someapifunc_n(var x: stuff): integer;
function someapifunc_nn: integer;
With overloads this becomes:
function someapifunc(var x, y: stuff): integer;
overload function someapifunc(var x: stuff): integer;
overload function someapifunc: integer;
No longer any need to coin various names for WINAPI functions and document them. And the result, IMHO is cleaner. Instead of the C call:
someapifunc(&q, NULL);
I have:
someapifunc(q);
And a simple rule: if the parameter does not exist, leave it out !
Typically I have seen this kind of interfacing in other Pascals by allowing for an operator such as &x, that takes the address of any variable, then allowing the user to stuff any address into a pointer parameter. This "solves" the problem, but imports a huge type safety problem from C into Pascal, namely the ability to arbitrarily manipulate addresses.
Another example, again from Windows (also appears in Linux !):
someapifunc(int code, void *x);
Here the "void *" actually does have a type, it just has several actual types. The "code" selects which type is actually going to be indexed by x. This is certainly not one of the better practices of C (it should have been broken into multiple functions). However, with overloads, Pascal can call it easily, and in a type safe manner, by listing each of the forms of the call in an overload group.
Similar to overloads, I believe templates will help Pascal quite a bit:
procedure wrtstr(var f: file; s: template);
var i: integer;
begin
for i := 1 to max(s) do write(f, s[i])
end;
With a template, one or more parameters can be left "abstract" until the actual call is parsed. What goes on is that the compiler parses the procedure without fully evaluating the template parameter, essentially "stockpiling" the body of the procedure in an encoded form. When the actual call occurs, the compiler can reevaluate the entire procedure in terms of what it now knows about the type of the argument.
This, like overloads, does not affect the type safety of Pascal. When the actual call occurs, the procedure that is generated to match the template is completely evaluated to standard Pascal rules. It is only "type soft" while the template is still abstract. On invocation, all the type rules come into play.
The number of traditional Pascal typing difficulties templates solve is stunning. Remember the common complaint about having to have several different procedures or functions to get around fixed length strings ? That problem no longer applies. A collection of string functions can be written for fixed length strings that adapt to any string type.
How about the ability to write a set of general purpose list manipulators ? In standard Pascal you have to rewrite a set of insert, delete, sort, etc routines to fit each type of dynamic list. With templates, you can write a series of routines that only rely on the common features of a list, such as each entry having a ".next" field, and a ".data" field.
In fact, templates subsume a lot of the functionality that people get from using source macros with Pascal, but without any of the drawbacks. Unlike macros, templates CAN be evaluated before they are invoked. In fact, a smart compiler can perform type checking even on template parameters. In the string example, s is clearly an array, and its usage can be checked, if (for example) it is later misused as a record.
Sorry for the long winded discussion. However, to wrap up, I believe overloads and templates are more important to Pascal than other languages, because these techniques increase both the apparent and real power of Pascal WITHOUT short circuiting the type safety of Pascal. They allow you to "have your cake and eat it too".
Scott Moore wrote:
For example, you can implement C++ style "default parameters" by using overloads ability to match parameter counts.
FWIW, I'll also consider default parameters when dealing with overlaods. They're no less type-strict, and may be more comfortable to use in some situations.
No longer any need to coin various names for WINAPI functions and document them. And the result, IMHO is cleaner. Instead of the C call:
someapifunc(&q, NULL);
I have:
someapifunc(q);
And a simple rule: if the parameter does not exist, leave it out !
Good example indeed. But it is a case where default parameters may be even better suited -- if there are n such parameters, with overloads you'll need 2^n routines.
Typically I have seen this kind of interfacing in other Pascals by allowing for an operator such as &x, that takes the address of any variable, then allowing the user to stuff any address into a pointer parameter. This "solves" the problem, but imports a huge type safety problem from C into Pascal, namely the ability to arbitrarily manipulate addresses.
Taking the address doesn't imply doing address arithmetic. As a thought experiment, just imagine that every global and local variable is internally allocated via `New', every normal use of the variable uses the-internal-pointer^, and `&x' (or `@x' as in BP and GPC) yields this internal pointer. This is no less type-safe (as I just proved, as I described it in standard Pascal terms). Of course, most of the dialects that habe `&'/`@' also allow for address arithmetic which is not so harmless.
The number of traditional Pascal typing difficulties templates solve is stunning. Remember the common complaint about having to have several different procedures or functions to get around fixed length strings ? That problem no longer applies. A collection of string functions can be written for fixed length strings that adapt to any string type.
But in your scheme, each invocation would create a new copy of the routine, which is not really nice WRT compile-time and binary-size. I think I prefer schema parameters for this case which are also type-safe.
How about the ability to write a set of general purpose list manipulators ? In standard Pascal you have to rewrite a set of insert, delete, sort, etc routines to fit each type of dynamic list. With templates, you can write a series of routines that only rely on the common features of a list, such as each entry having a ".next" field, and a ".data" field.
Yes, here templates would come handy.
Frank
Frank Heckenbach wrote:
Scott Moore wrote:
For example, you can implement C++ style "default parameters" by using overloads ability to match parameter counts.
FWIW, I'll also consider default parameters when dealing with overlaods. They're no less type-strict, and may be more comfortable to use in some situations.
No longer any need to coin various names for WINAPI functions and document them. And the result, IMHO is cleaner. Instead of the C call:
someapifunc(&q, NULL);
I have:
someapifunc(q);
And a simple rule: if the parameter does not exist, leave it out !
Good example indeed. But it is a case where default parameters may be even better suited -- if there are n such parameters, with overloads you'll need 2^n routines.
In theory, yes. For practical matters, the number never rises above 8 (three optional parameters). However, I don't have any fundamental objection to default parameters beyond degradation in source transparency, which I agree overloading also affects. By this I define source transparency is making it obvious to the reader of a program exactly what routine will be executed for any particular call, and how that call will appear.
Typically I have seen this kind of interfacing in other Pascals by allowing for an operator such as &x, that takes the address of any variable, then allowing the user to stuff any address into a pointer parameter. This "solves" the problem, but imports a huge type safety problem from C into Pascal, namely the ability to arbitrarily manipulate addresses.
Taking the address doesn't imply doing address arithmetic. As a thought experiment, just imagine that every global and local variable is internally allocated via `New', every normal use of the variable uses the-internal-pointer^, and `&x' (or `@x' as in BP and GPC) yields this internal pointer. This is no less type-safe (as I just proved, as I described it in standard Pascal terms). Of course, most of the dialects that habe `&'/`@' also allow for address arithmetic which is not so harmless.
I don't disagree. I just think that Pascal has its methods for handling program objects by their address (VAR parameters) and C has its, and I am not wild about mixing them.
The number of traditional Pascal typing difficulties templates solve is stunning. Remember the common complaint about having to have several different procedures or functions to get around fixed length strings ? That problem no longer applies. A collection of string functions can be written for fixed length strings that adapt to any string type.
But in your scheme, each invocation would create a new copy of the routine, which is not really nice WRT compile-time and binary-size. I think I prefer schema parameters for this case which are also type-safe.
Schemas require run time templates, which mean that you trade code space (template style) for runtime efficiency. Schemas are largely the reason I decided not to implement the ISO extended Pascal standard. They largely import type checking from compile time to runtime. I had a conversation with John Reagan (one of the authors and chief proponents of the standard), where he related to me that the makers of the standard believed that compile time for runtime trade offs were acceptable in a day and age where "computers were more powerfully than what is required".
Without (hopefully) getting into a tirade on the subject, I fundamentally oppose that. Making Pascal increasingly rely on runtime work is a recipe for having Pascal fall behind other languages in runtime capability, whereas at present Pascal is at par, or even excels because of the better information Pascal delivers to the compiler. Schemas fundamentally (and permanently) degrade Pascals runtime performance. Further, type safety is an attribute independent of implementation. C has degraded the type status of type safety and type safe languages. Java has somewhat restored it, but has also created in programmers minds the idea that type safety must be paid for with degraded runtime performance. The trap of having C/C++ be perceived as "industrial strength" languages with Pascal, Java and other languages as lower performing "trade off" languages is all to apparent, and does not need the help of fundamental runtime trade-offs like schemas.
Finally, I debate that schemas are necessary for Pascal. The prime problem schemas are used for is to create dynamic length arrays. Indeed, that was the entire reason schemas were considered for creation in the first place. Instead, IP Pascal uses a completely type safe method advocated by N. Wirth himself in Oberon, which I further developed so that it is completely upward and downward compatible with the rules of fixed length arrays in standard Pascal. Thus, IP Pascal has dynamic length arrays, and fixed length arrays can be passed to a dynamic length parameter, etc. The method used in IP Pascal requires a fraction of the work of schemas, both from the point of view of the compiler writer, and also runtime checking, but accomplishes all of the aims of schemas with respect to dynamic arrays. So I submit that schemas were not a required price to pay to enhance standard based Pascal.
Templates (as in source time) certainly make it easier to generate multiple runtime routines, but this is very much in control of the programmer. Certainly, one would not want to use templates as a replacement for dynamic arrays, which is why IP Pascal implements same. For the situations templates are most useful, the alternative to a template would require multiple library variants in any case, each hand written by the programmer, perhaps with cut and paste. In fact, in virtually any case where a routine is created by cut and paste methods (i.e., a copy with trivial changes due to typing limitations), templates are likely to be a better implementation.
Ok, that might have been a tirade :-)
How about the ability to write a set of general purpose list manipulators ? In standard Pascal you have to rewrite a set of insert, delete, sort, etc routines to fit each type of dynamic list. With templates, you can write a series of routines that only rely on the common features of a list, such as each entry having a ".next" field, and a ".data" field.
Yes, here templates would come handy.
Frank
Scott Moore wrote:
And a simple rule: if the parameter does not exist, leave it out !
Good example indeed. But it is a case where default parameters may be even better suited -- if there are n such parameters, with overloads you'll need 2^n routines.
In theory, yes. For practical matters, the number never rises above 8 (three optional parameters).
I don't think so.
They largely import type checking from compile time to runtime.
Not really. An additional runtime type-check would be necessary when e.g. a formal parameter is of a discriminated schema type and the actual parameter is of an undiscriminated type (i.e., a parameter itself or a pointer). However, this case is extremely rare -- the exact opposite is the common case, where all type-checking can be done at compile time.
If used for array bounds (as is indeed common), some range-checking becomes a little more expensive (comparing two variables rather than a variable and a constant), and some range checks (though rarer) have to move from compile time to run time. True, this is a runtime price, but it's far smaller than you make it appear. Furthermore, with any other concept for dynamic arrays, you get the same price, AFAICS.
Schemas fundamentally (and permanently) degrade Pascals runtime performance.
What do you mean permanently? It only affects code that uses schemata, other code is not affected.
And again, what are your alternatives? When I use schemata for dynamic arrays, you have another implementation of dynamic arrays which surely also requires more runtime range checks.
When I use schemata for other purposes, you need explicit code which in the end probably does almost the same at runtime which schema code does implicitly.
Further, type safety is an attribute independent of implementation.
Finally, I debate that schemas are necessary for Pascal. The prime problem schemas are used for is to create dynamic length arrays. Indeed, that was the entire reason schemas were considered for creation in the first place. Instead, IP Pascal uses a completely type safe method
I don't know why you keep insisting on type-safety when the alternatives (default parameters, address operators, schemata) are just as type safe. I wonder if you have understood the schema concept at all if you actually think they're type-unsafe.
Anyway, I have some uses of schemata which are more then dynamic length arrays, but since you obviously don't care, I won't bother explaining.
Frank
Frank Heckenbach wrote:
Scott Moore wrote:
And a simple rule: if the parameter does not exist, leave it out !
Good example indeed. But it is a case where default parameters may be even better suited -- if there are n such parameters, with overloads you'll need 2^n routines.
In theory, yes. For practical matters, the number never rises above 8 (three optional parameters).
I don't think so.
They largely import type checking from compile time to runtime.
Not really. An additional runtime type-check would be necessary when e.g. a formal parameter is of a discriminated schema type and the actual parameter is of an undiscriminated type (i.e., a parameter itself or a pointer). However, this case is extremely rare -- the exact opposite is the common case, where all type-checking can be done at compile time.
If used for array bounds (as is indeed common), some range-checking becomes a little more expensive (comparing two variables rather than a variable and a constant), and some range checks (though rarer) have to move from compile time to run time. True, this is a runtime price, but it's far smaller than you make it appear. Furthermore, with any other concept for dynamic arrays, you get the same price, AFAICS.
Dynamic arrays are pretty much what the whole issue is about. First, Oberon dispenses with the lower bound check, which I think is proper. Second, whenever you introduce a mix of dynamic and fixed arrays there are problems. If you specify a parameter as dynamic, convertions happen when called with a fixed, etc. In fact, there is considerable incentive to add bounds variables to ALL arrays, fixed or not, just to keep compatibility. So I stay with what I said, the overhead is greater with schemas, for no added benifit.
Schemas fundamentally (and permanently) degrade Pascals runtime performance.
What do you mean permanently? It only affects code that uses schemata, other code is not affected.
As programmers get used to using schemas, it is permanent. Using the method in IP Pascal, there is no incentive to use dynamic when a fixed array would do, so there is no incentive to use more expensive schema types.
And again, what are your alternatives? When I use schemata for dynamic arrays, you have another implementation of dynamic arrays which surely also requires more runtime range checks.
Typically in a schema you must carry a pointer to a template (a runtime data structure describing the schema type to be accessed). With simple dynamics, as IP and Oberon implemented, there is only the array length, and it can be picked up or not depending on if the array type is being accessed dynamically or not.
When I use schemata for other purposes, you need explicit code which in the end probably does almost the same at runtime which schema code does implicitly.
Further, type safety is an attribute independent of implementation.
Finally, I debate that schemas are necessary for Pascal. The prime problem schemas are used for is to create dynamic length arrays. Indeed, that was the entire reason schemas were considered for creation in the first place. Instead, IP Pascal uses a completely type safe method
I don't know why you keep insisting on type-safety when the alternatives (default parameters, address operators, schemata) are just as type safe. I wonder if you have understood the schema concept at all if you actually think they're type-unsafe.
I didn't say that, and now we are insulting. So we are going to agree to disagree.
Anyway, I have some uses of schemata which are more then dynamic length arrays, but since you obviously don't care, I won't bother explaining.
Frank
I'm sorry you felt you needed to put this on a personal level. I am actually confused why you felt that was required, but I have had examples of it before. I think we are done. Kinda sad, really, we cannot have a reasonable conversation.
Scott Moore wrote:
Dynamic arrays are pretty much what the whole issue is about. First, Oberon dispenses with the lower bound check, which I think is proper. Second, whenever you introduce a mix of dynamic and fixed arrays there are problems. If you specify a parameter as dynamic, convertions happen when called with a fixed, etc.
Schema formal parameters accept only schemata as actual parameters. There are no implicit conversions. (The only exceptions is for value parameters of type `String', to allow for actual parameters of a fixed string type (for backward compatibility) and string literals.)
Of course, when you plan to pass some data to a schematic argument, you must make it a schema, but I can't remember that I ever had such a problem where I didn't want to make it a schema, anyway (because the schema type is just the type I use for this particular structure). And I certainly never had to do a manual runtime conversion from a fixed array to a schema just to pass it as a parameter.
So these problems you keep referring to (I remember you said the same in a newsgroup discussion before) simply do not exist in practice.
Schemas fundamentally (and permanently) degrade Pascals runtime performance.
What do you mean permanently? It only affects code that uses schemata, other code is not affected.
As programmers get used to using schemas, it is permanent.
I'm trying to not take this personal, but believe me, I *can* decide when a fixed size will do and when not.
And again, what are your alternatives? When I use schemata for dynamic arrays, you have another implementation of dynamic arrays which surely also requires more runtime range checks.
Typically in a schema you must carry a pointer to a template (a runtime data structure describing the schema type to be accessed).
What makes you think so? We don't need a runtime type description. The compiler has such a description, but it's never output in any runtime form, so it cannot be used at runtime, not even accidentally.
If that's your main concern about schemata, you might want to point out why you think it's necessary so we can try to clarify things, instead of repeating assertions without any evidence or example which are hard to comment in a useful way.
I wonder if you have understood the schema concept at all if you actually think they're type-unsafe.
Anyway, I have some uses of schemata which are more then dynamic length arrays, but since you obviously don't care, I won't bother explaining.
I'm sorry you felt you needed to put this on a personal level. I am actually confused why you felt that was required, but I have had examples of it before. I think we are done. Kinda sad, really, we cannot have a reasonable conversation.
Yes, I remember. You're quick to take things personal. Just for the record, what exactly do you feel I put on a personal level? That you don't care about schemata? I think that's pretty clear from your comments. That you haven't completely understood the schema concept? That's not exactly a personal offense -- if you don't care for something, you don't need to understand it, of course. But it might be wiser to not publicly criticise something you don't really know. As this mail shows, you apparently have some misconceptions about schemata (automatic conversions from fixed types, need for runtime type descriptions). If you want to continue critizing things based on false information, indeed we cannot have a reasonable conversation.
If you're really interested, I could explain some things about schemata to you and how some situations can be handled efficiently. But if you begin with statements such as "This is necessary ..." and "That is impossible ...", while Waldek and I who actually worked on the implementation of schemata know better, it's kind of pointless ...
BTW, about the other points, I fully agree with Waldek's last mail.
Frank
Scott Moore wrote:
Frank Heckenbach wrote:
Good example indeed. But it is a case where default parameters may be even better suited -- if there are n such parameters, with overloads you'll need 2^n routines.
In theory, yes. For practical matters, the number never rises above 8 (three optional parameters). However, I don't have any fundamental objection to default parameters beyond degradation in source transparency, which I agree overloading also affects. By this I define source transparency is making it obvious to the reader of a program exactly what routine will be executed for any particular call, and how that call will appear.
You may easily have 8 default parameters. Of course, it is quite likely that some (most) of the parameters have the same type, so you need some way to signal which parameters you want to pass explicitely like:
procedure foo(i1: integer value 0; i2 integer value 1, i3 .... i8: integer value -1); ....
foo(5 => i2, 9 => i7);
Note that with equal types you can not use overloads.
But in your scheme, each invocation would create a new copy of the routine, which is not really nice WRT compile-time and binary-size. I think I prefer schema parameters for this case which are also type-safe.
Schemas require run time templates, which mean that you trade code space (template style) for runtime efficiency. Schemas are largely the reason I decided not to implement the ISO extended Pascal standard. They largely import type checking from compile time to runtime. I had a conversation with John Reagan (one of the authors and chief proponents of the standard), where he related to me that the makers of the standard believed that compile time for runtime trade offs were acceptable in a day and age where "computers were more powerfully than what is required".
Without (hopefully) getting into a tirade on the subject, I fundamentally oppose that.
I very much oppose the view that "computers are more powerfull than what is required". Looking how processor price increases with speed clearily shows that this is nonsense.
However, I think that such opinion about schema is just mistaken. Pascal tradition was to use statically sized data -- if you can live that then you will get best speed (and you may forget about schema). But having faster computers we want to solve more complicated problems. For such problems dynamically sized data is a must. So the question is how to implement such data -- efficiently and in type safe way. IHMO Pascal schema are one of best solutions: -- they allow ommiting extra info if array is statically allocated and _not_ used as an argument to function/procedure -- they allow to do many checks at compile time -- runtime and size overhead is quite small -- they are quite flexible
Note that your "general arrays" are just as efficient/expensive as simple array schema with one discriminant. If I read your description correctly, the only thing that "general arrays" can but schema can not is cooperating with fixed length arrays. So using schema you loose a single word per fixed array. But if you need n by n matrix your workaround looses 2n words and a lot of time for pointer manipulation -- in that case schema is much more efficient.
etc. The method used in IP Pascal requires a fraction of the work of schemas, both from the point of view of the compiler writer, and also runtime checking, but accomplishes all of the aims of schemas with respect to dynamic arrays. So I submit that schemas were not a required price to pay to enhance standard based Pascal.
The only advantage your method has is simpler implementation. You are penny-wise for one dimensional arrays (how many fixed length one dimensional arrays do you want to have?), and you loose big on multi dimensional arrays.
On Wed, 6 Oct 2004, Scott Moore wrote:
[..]
With overloads this becomes:
function someapifunc(var x, y: stuff): integer;
overload function someapifunc(var x: stuff): integer;
overload function someapifunc: integer;
Isn't "overload function" somewhat redundant? Perhaps just: overload someapifunc ...
Just asking Russ
Scott Moore wrote:
Back on the original subject, the spec for Borlands version of overloads are just awful. Virtually any difference in type between overload parameter lists is accepted as a valid overload. For example, two subranges of integer are accepted, which is clearly an ambiguous overload. Borland "resolves" this by calling the procedure or function with the smallest integer range.
I am not sure that this is entirely correct. What Delphi does is this: "In these cases, when it is possible to do so without ambiguity, the compiler invokes the routine whose parameters are of the type with the smallest range that accommodates the actual parameters in the call".
I don't think that this is the same thing as what you said.
That being said, I am not sure why one would want to overload routines using different subranges of integer. Just because the compiler allows something doesn't mean that one should do it, especially seeing that, in such cases, one single routine (taking a parameter of the largest size of integer) would do just fine.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/
Prof A Olowofoyeku (The African Chief) wrote:
That being said, I am not sure why one would want to overload routines using different subranges of integer. Just because the compiler allows something doesn't mean that one should do it, especially seeing that, in such cases, one single routine (taking a parameter of the largest size of integer) would do just fine.
As I wrote, this may be done for efficiency (since passing an Integer is slightly faster than passing a LongInt, e.g.), but I'm also doubtful if it's a good thing to do.
A similar problem would appear with `Integer' and `Real', BTW, since integer values are allowable for `Real' (value) parameters. I'm not sure how important this is.
Though it might be, especially for operators. If we want to define a new numeric type, say GMP's real type, and provide regular operators for it, so we could do `GMPRealValue + IntegerValue' and `GMPRealValue + RealValue', we have just this situation.
Of course, defining an `GMPRealtype + Real' operator would accept an integer RHS operand as well, but it's less efficient than calling GMP's "GMP-Real + Integer" routine directly.
So perhaps one should allow integer vs. real ambiguities, since they're less fragile than those between different integer subranges?
Frank
On 6 Oct 2004 at 0:09, Frank Heckenbach wrote:
[...]
So perhaps one should allow integer vs. real ambiguities, since they're less fragile than those between different integer subranges?
Yes. I also think that one should allow integer subranges, even if it may not always be advisable for programmers (if only for compatibility with Delphi - but also, one should not presume to be able to predict the kinds of things that programmers might need to do that may make such usage advantageous). Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/
On Sat, 25 Sep 2004, Scott Moore wrote:
gpc is down, so my copy of the GPC manual might be old, but I cannot find an entry in the GPC manual for it.
Does GPC implememt overloads ?
You can get a copy of the GPC manual (gpc.pdf for gpc-20040516) from 'http://www.desy.de/~bohnen/gpc'. Hope that helps
Ernst-Ludwig
(For callbacks etc., once we have an accepted mechanism, such as `Discard', one can just as well add it immediately.)
One thing that would be good, and generally is not done, is to generate a hint/warning/error in the case where you specify that a parameter is unused, but then in fact use it (since this likely indicates either an error or at the least obscure code indicating one thing and doing another).
Metrowerks Pascal has the concept of notes which I guess are akin to the hints suggested here.
In my thinking, I would say anything that the compiler cannot compile should be an error, anything that is quite likely an error, but the compile can compile it (generally something that could be legal in at least some case), and anything that is just the compiler trying to help you clean up your code would be a hint.
I generally do not compile with -Werror, as I often use warnings to remind me of things I have not yet done and so they might stay in the code for a week while I'm working through putting structure in the code before filling out details. But I loathe warnings and strongly believe code should compile properly without any warnings as the normal case, which is why we need strong, precise control over turning off warnings where appropriate.
To my mind, the cleanest way in GPC is attribute (unused) on the formal parameter, but one down side of this is I don't believe GPC allows you to specify that in only the implementation (for example, if I have a unit:
interface function doit( a: Integer; b: Integer ): Integer; implementation function doit( a: Integer; b: Integer attribute (unused) ): Integer; begin return a; end;
That would not be possible in GPC would it? This case might occur in a unit (or set of units) that provides a set of functions all with the same parameters (perhaps a set of callback functions that do different things).
Obviously, the easiest thing for me would be just to implement the {$unused(b)} directive, but whatever solution, I don't really care as long as I can make it work.
Enjoy, Peter.
Peter N Lewis wrote:
(For callbacks etc., once we have an accepted mechanism, such as `Discard', one can just as well add it immediately.)
One thing that would be good, and generally is not done, is to generate a hint/warning/error in the case where you specify that a parameter is unused, but then in fact use it (since this likely indicates either an error or at the least obscure code indicating one thing and doing another).
I agree that it can be useful. (Though, unfortunately, this would complicate the implementation again. Currently `unused' attributes are handled by just marking the thing as used. For this warning we'd need another flag and extra code to handle the two flags. It's all more work than I'd like to spend on the matter, at least for now ...)
To my mind, the cleanest way in GPC is attribute (unused) on the formal parameter, but one down side of this is I don't believe GPC allows you to specify that in only the implementation (for example, if I have a unit:
interface function doit( a: Integer; b: Integer ): Integer; implementation function doit( a: Integer; b: Integer attribute (unused) ): Integer; begin return a; end;
That would not be possible in GPC would it?
That's up to the (yet to be done) implementation. I think it would be possible to allow it in the implementation. We don't allow routine attributes there, but we do that on purposes, because (at least some of the) attributes there would lead to nonsense, such as specifying a different linker name or calling convention after the routine has been exported and perhaps called from within the current module.
Provided it's clear that parameter attributes can never influence the interface, it should be possible to allow them in the implementation.
But now that you wrote the example, I see a syntactic problem. We already have the syntax `<type> <attribute>' for type attributes. Though we don't allow type attributes in parameters (more or less in the spirit of Pascal's forbidding new structured types there), I wouldn't like to have the same syntax mean something different here.
For variable's attributes, we have `var <name> = <type>; <attribute>'. But wouldn't this look strange in a parameter list?
function doit( a: Integer; b: Integer; attribute (unused) ): Integer;
This would at first glance look like another parameter (though syntactically invalid, even with procedural parameters and all the extensions we have, AFAICS, so maybe not a conflict, but still strange) ...
A related question is if we should simply allow `unused' (and perhaps more) as type attributes. I.e., we'd create a variant of a type which is generally unused. This sounds strange, of course. I'm reminded of this, because I've once wondered if we should have `static' as a type attribute (though I'm not sure yet if I'd really need it, probably not) ...
Obviously, the easiest thing for me would be just to implement the {$unused(b)} directive,
I think this would be quite a bit more difficult, and raises some new questions, since directives are outside of the syntax rules. E.g.:
procedure foo (a: Integer);
{$unused(a)}
procedure bar (a: Integer); begin end;
begin end;
Which `a' is meant here? The outer one? What if you move the directive after the word `procedure', is it the inner one now? If not, it would seem confusing. If so, it would need to reference an identifier before it's declared, also bad ...
Frank
I agree that it can be useful. (Though, unfortunately, this would complicate the implementation again. Currently `unused' attributes are handled by just marking the thing as used. For this warning we'd need another flag and extra code to handle the two flags. It's all more work than I'd like to spend on the matter, at least for now ...)
Fair enough - I just wanted to make sure the idea was known and considered since it might be the case that it fell out easily and if so would certainly be worth implementing.
But now that you wrote the example, I see a syntactic problem. We already have the syntax `<type> <attribute>' for type attributes. Though we don't allow type attributes in parameters (more or less in the spirit of Pascal's forbidding new structured types there), I wouldn't like to have the same syntax mean something different here.
For variable's attributes, we have `var <name> = <type>; <attribute>'. But wouldn't this look strange in a parameter list?
function doit( a: Integer; b: Integer; attribute (unused) ): Integer;
This would at first glance look like another parameter (though syntactically invalid, even with procedural parameters and all the extensions we have, AFAICS, so maybe not a conflict, but still strange) ...
Yes, strange indeed.
A related question is if we should simply allow `unused' (and perhaps more) as type attributes. I.e., we'd create a variant of a type which is generally unused. This sounds strange, of course. I'm reminded of this, because I've once wondered if we should have `static' as a type attribute (though I'm not sure yet if I'd really need it, probably not) ...
Also strange, and quite cumbersome I would think for any particular case.
Obviously, the easiest thing for me would be just to implement the {$unused(b)} directive,
I think this would be quite a bit more difficult, and raises some new questions, since directives are outside of the syntax rules. E.g.:
procedure foo (a: Integer);
{$unused(a)}
procedure bar (a: Integer); begin end;
begin end;
Which `a' is meant here? The outer one? What if you move the directive after the word `procedure', is it the inner one now? If not, it would seem confusing. If so, it would need to reference an identifier before it's declared, also bad ...
Basically I guess since it is accessing the symbol table it would apply to the same thing the compiler currently considered as the "current in scope variable", which would be ambiguous at best everywhere from "procedure" up to the ";" (and possibly one more token. For myself (and we could certainly recommend it as the way to go), I generally write the {$unused(a,b,c)} line on the first line after the begin. That ensures the compiler and the parser are pretty much guaranteed to be in sync.
Enjoy, Peter.
Peter N Lewis wrote:
Obviously, the easiest thing for me would be just to implement the {$unused(b)} directive,
I think this would be quite a bit more difficult, and raises some new questions, since directives are outside of the syntax rules. E.g.:
procedure foo (a: Integer);
{$unused(a)}
procedure bar (a: Integer); begin end;
begin end;
Which `a' is meant here? The outer one? What if you move the directive after the word `procedure', is it the inner one now? If not, it would seem confusing. If so, it would need to reference an identifier before it's declared, also bad ...
Basically I guess since it is accessing the symbol table it would apply to the same thing the compiler currently considered as the "current in scope variable", which would be ambiguous at best everywhere from "procedure" up to the ";" (and possibly one more token.
Exactly, that's the problem. Since the compiler processes things not on a token basis, but in semantic groups, produced by the parser, this uncertainty doesn't arise normally, because there's no place, say before and after the `:' where the compiler would do anything.
For myself (and we could certainly recommend it as the way to go), I generally write the {$unused(a,b,c)} line on the first line after the begin. That ensures the compiler and the parser are pretty much guaranteed to be in sync.
While this is a useful principle from the programmer's point of view, it still doesn't answer the question from the compiler's point of view. IMHO, a feature whose meaning can't even be clearly defined (in any situation) is highly suspicious. (My favourite example are BP's `^X' char constants. Borland's implementation of them only works in some situations, where there are probably most often used, and they simply forgot about other cases, so the resulting syntax of their language is hard to even describe properly ...)
BTW, many of us (including myself) have complained about the convoluted language of the Pascal standards. At least it's to achieve the goal of defining things unambiguously (though IMHO this goal is not necessarily incompatible with better readability -- perhaps by using a little more formalism than writing everything out in long English sentences) ...
Frank
Peter N Lewis wrote:
... snip ...
Which `a' is meant here? The outer one? What if you move the directive after the word `procedure', is it the inner one now? If not, it would seem confusing. If so, it would need to reference an identifier before it's declared, also bad ...
Basically I guess since it is accessing the symbol table it would apply to the same thing the compiler currently considered as the "current in scope variable", which would be ambiguous at best everywhere from "procedure" up to the ";" (and possibly one more token. For myself (and we could certainly recommend it as the way to go), I generally write the {$unused(a,b,c)} line on the first line after the begin. That ensures the compiler and the parser are pretty much guaranteed to be in sync.
Consider:
PROCEDURE foo(bar : integer);
VAR junk : integer;
FUNCTION fee(faw : integer) : integer; BEGIN fee := bar * faw; END;
BEGIN IF something THEN junk := fee(10); END;
Unknown attributions:
Not using a parameter usually indicates a bug
Not necessarily. You often want to design a procedure or function with a spare parameter to cover future extension, and probably document that it shall be called with that parameter zero. The actual procedure code has no reason (today) to use the parameter.
CBFalconer wrote:
Unknown attributions:
Not using a parameter usually indicates a bug
Not necessarily. You often want to design a procedure or function with a spare parameter to cover future extension, and probably document that it shall be called with that parameter zero. The actual procedure code has no reason (today) to use the parameter.
FWIW, I'm not really a fan of this practice (which I've seen in some places, and occasionally tried myself). For one, unless you actually know what the future extensions will be, it's hard to foresee which type the future parameter should have (and if one is enough actually). In C, you might get away with an integer parameter, since almost everything is an integer in C. ;-) In Pascal, you'd often want a better typed parameter.
Besides, I've found that it's usually not *such* a big deal to adjust callers to a new parameter, or to provide a backward-compatible interface (which possibly just calls the new, extended routine, with the new parameters).
Frank
Frank Heckenbach wrote:
CBFalconer wrote:
Unknown attributions:
Not using a parameter usually indicates a bug
Not necessarily. You often want to design a procedure or function with a spare parameter to cover future extension, and probably document that it shall be called with that parameter zero. The actual procedure code has no reason (today) to use the parameter.
FWIW, I'm not really a fan of this practice (which I've seen in some places, and occasionally tried myself). For one, unless you actually know what the future extensions will be, it's hard to foresee which type the future parameter should have (and if one is enough actually). In C, you might get away with an integer parameter, since almost everything is an integer in C. ;-) In Pascal, you'd often want a better typed parameter.
Besides, I've found that it's usually not *such* a big deal to adjust callers to a new parameter, or to provide a backward-compatible interface (which possibly just calls the new, extended routine, with the new parameters).
Frank
Procedures and functions with unused parameters appear in good code all the time. You build programs by constructing outlines with the routines stubbed out, simply serving as placeholders for routes yet to be constructed. At some point, the program is even going to become operational with many of the unfinished routines left stubbed out. This is a good, organized design method, and its to be encouraged. To me, it means the programmer plans ahead.
At 10:32 -0700 27/9/04, Scott Moore wrote:
Procedures and functions with unused parameters appear in good code all the time. You build programs by constructing outlines with the routines stubbed out, simply serving as placeholders for routes yet to be constructed. At some point, the program is even going to become operational with many of the unfinished routines left stubbed out. This is a good, organized design method, and its to be encouraged. To me, it means the programmer plans ahead.
Yes, I agree entirely, and it is a good argument for the need to be able to explicitly mark parameters that are unused. Not for the functions you describe, but for everywhere else they might happen so that the warnings for the functions you describe appear cleanly to remind the programmer of what is still unfinished, without being buried by lots of spurious warnings for callback functions and such that will never use the extra parameters. Peter.
CBFalconer wrote:
This brings up the more general subject of the attitude to warnings. Pascal is not C. In C many, if not most, warnings indicate a serious situation where the probability of bad code is high, if not certain. Pascal has so many more internal checks that warnings tend to be just that, and the probability that the code does what is intended is much higher.
Thus the Pascal programmer should be prepared to evaluate and accept warnings on compilation. This attitude is probably not fatal, as it would be in C. In particular an unused parameter falls into this classification.
I don't really agree. First, most of the warnings I see from C programs are alllso harmless on closer inspection. I haven't done any statistics to find out the relative relevance of Pascal vs. C warnings, though.
However, the main point is that warnings that are left in will be seen by everyone who compiles the software, not only by the one who wrote the code. In the end, this will lead to the situation we mostly have in C now, where everyone expects to see some warnings when compiling something and almost nobody cares about them. We could just as well turn them all off then.
So I agree with Adriaan that distributed software should compile without warnings, either (preferably) in a clean way by changing the code, otherwise by force, i.e. turning off warnings (as locally and specific as possible).
BTW, using `-Werror' when compiling things helps you keep that discipline and forces you to fix warnings immediately (rather than having them accumulate until there are so many you don't want to start fixing them anymore ;-).
Frank
Frank Heckenbach wrote:
CBFalconer wrote:
This brings up the more general subject of the attitude to warnings. Pascal is not C. In C many, if not most, warnings indicate a serious situation where the probability of bad code is high, if not certain. Pascal has so many more internal checks that warnings tend to be just that, and the probability that the code does what is intended is much higher.
Thus the Pascal programmer should be prepared to evaluate and accept warnings on compilation. This attitude is probably not fatal, as it would be in C. In particular an unused parameter falls into this classification.
I don't really agree. First, most of the warnings I see from C programs are alllso harmless on closer inspection. I haven't done any statistics to find out the relative relevance of Pascal vs. C warnings, though.
However, the main point is that warnings that are left in will be seen by everyone who compiles the software, not only by the one who wrote the code. In the end, this will lead to the situation we mostly have in C now, where everyone expects to see some warnings when compiling something and almost nobody cares about them. We could just as well turn them all off then.
So I agree with Adriaan that distributed software should compile without warnings, either (preferably) in a clean way by changing the code, otherwise by force, i.e. turning off warnings (as locally and specific as possible).
BTW, using `-Werror' when compiling things helps you keep that discipline and forces you to fix warnings immediately (rather than having them accumulate until there are so many you don't want to start fixing them anymore ;-).
Frank
Pascal and C deserve to be treated completely differently with regards to warnings. The following is perfectly valid C:
while (c = 1) ...;
But probally generates a warning on many C compilers nowdays. C compilers have to determine what is "likely" to be a problem. This a good lesson for Pascalers. We were blessed with a language that does not have such grey areas.
PS. IP Pascal does not have warnings at all. If the option is on to check for problem N, then the occurrance of problem N is an error, end of story. This means the compiler returns an error to the build processor, and in fact deletes any output files, to prevent a false build being created for the bad build.
I agree with the other posters. C warnings are a mess. Avoid at all costs.
Scott Moore wrote:
Pascal and C deserve to be treated completely differently with regards to warnings. The following is perfectly valid C:
while (c = 1) ...;
But probally generates a warning on many C compilers nowdays. C compilers have to determine what is "likely" to be a problem. This a good lesson for Pascalers. We were blessed with a language that does not have such grey areas.
PS. IP Pascal does not have warnings at all. If the option is on to check for problem N, then the occurrance of problem N is an error, end of story. This means the compiler returns an error to the build processor, and in fact deletes any output files, to prevent a false build being created for the bad build.
I agree with the other posters. C warnings are a mess. Avoid at all costs.
While I agree that we're far better off than C, there are dubious areas. Unused parameters, as discussed here, as well as unneed function results, are some.
Even if the compiler always flags them as errors (as GPC will do with `-Werror'), or especially then, there must be a way for the programmer to tell the compiler that in some places, this is intended, and that's what this discussion is for ...
I still prefer adding a built-in `Discard' dummy procedure which will solve both problems, without adding new syntax.
Frank
Frank Heckenbach wrote:
... snip ...
I still prefer adding a built-in `Discard' dummy procedure which will solve both problems, without adding new syntax.
This is probably cleaner, since if defined at the system level 0 it will be overridden immediately by any user definition.
CBFalconer wrote:
Frank Heckenbach wrote:
... snip ...
I still prefer adding a built-in `Discard' dummy procedure which will solve both problems, without adding new syntax.
This is probably cleaner, since if defined at the system level 0 it will be overridden immediately by any user definition.
Exactly. (And for the same reasone it's easiest to implement because it'll be just one more in the long list of routines we have there already.)
So, if there are no serious objections anymore, I'll implement that.
Frank
On Tue, 28 Sep 2004, Frank Heckenbach wrote:
CBFalconer wrote:
Frank Heckenbach wrote:
... snip ...
I still prefer adding a built-in `Discard' dummy procedure which will solve both problems, without adding new syntax.
This is probably cleaner, since if defined at the system level 0 it will be overridden immediately by any user definition.
Exactly. (And for the same reasone it's easiest to implement because it'll be just one more in the long list of routines we have there already.)
So, if there are no serious objections anymore, I'll implement that.
Fine, I think many Pascal enthusiasts will breathe again.
Ernst-Ludwig
Frank Heckenbach wrote:
... snip ...
However, the main point is that warnings that are left in will be seen by everyone who compiles the software, not only by the one who wrote the code. In the end, this will lead to the situation we mostly have in C now, where everyone expects to see some warnings when compiling something and almost nobody cares about them. We could just as well turn them all off then.
To me, that is a sign of bug-ridden C code.
CBFalconer wrote:
Frank Heckenbach wrote:
... snip ...
However, the main point is that warnings that are left in will be seen by everyone who compiles the software, not only by the one who wrote the code. In the end, this will lead to the situation we mostly have in C now, where everyone expects to see some warnings when compiling something and almost nobody cares about them. We could just as well turn them all off then.
To me, that is a sign of bug-ridden C code.
Sorry, what's your point? Last time you said: "Thus the Pascal programmer should be prepared to evaluate and accept warnings on compilation." Now you say "[getting lots of warnings is] a sign of bug-ridden C code." Do you want us to get to the same situation where C already is?
Frank
Frank Heckenbach wrote:
CBFalconer wrote:
Frank Heckenbach wrote:
... snip ...
However, the main point is that warnings that are left in will be seen by everyone who compiles the software, not only by the one who wrote the code. In the end, this will lead to the situation we mostly have in C now, where everyone expects to see some warnings when compiling something and almost nobody cares about them. We could just as well turn them all off then.
To me, that is a sign of bug-ridden C code.
Sorry, what's your point? Last time you said: "Thus the Pascal programmer should be prepared to evaluate and accept warnings on compilation." Now you say "[getting lots of warnings is] a sign of bug-ridden C code." Do you want us to get to the same situation where C already is?
I was talking specifically about C there, not Pascal.
CBFalconer wrote:
Frank Heckenbach wrote:
CBFalconer wrote:
Frank Heckenbach wrote:
... snip ...
However, the main point is that warnings that are left in will be seen by everyone who compiles the software, not only by the one who wrote the code. In the end, this will lead to the situation we mostly have in C now, where everyone expects to see some warnings when compiling something and almost nobody cares about them. We could just as well turn them all off then.
To me, that is a sign of bug-ridden C code.
Sorry, what's your point? Last time you said: "Thus the Pascal programmer should be prepared to evaluate and accept warnings on compilation." Now you say "[getting lots of warnings is] a sign of bug-ridden C code." Do you want us to get to the same situation where C already is?
I was talking specifically about C there, not Pascal.
But I still can't see why getting lots of warnings should be more acceptable in Pascal.
Frank
Frank Heckenbach wrote:
CBFalconer wrote:
Frank Heckenbach wrote:
CBFalconer wrote:
Frank Heckenbach wrote:
... snip ...
However, the main point is that warnings that are left in will be seen by everyone who compiles the software, not only by the one who wrote the code. In the end, this will lead to the situation we mostly have in C now, where everyone expects to see some warnings when compiling something and almost nobody cares about them. We could just as well turn them all off then.
To me, that is a sign of bug-ridden C code.
Sorry, what's your point? Last time you said: "Thus the Pascal programmer should be prepared to evaluate and accept warnings on compilation." Now you say "[getting lots of warnings is] a sign of bug-ridden C code." Do you want us to get to the same situation where C already is?
I was talking specifically about C there, not Pascal.
But I still can't see why getting lots of warnings should be more acceptable in Pascal.
First, there won't be many warnings. Secondly, things that generate C warnings because they are suspicious are normally just not allowed in Pascal. For example, you can't assign a char to an integer, or an integer to or from an enumeration, or a real to an integer, etc. Those things will generate Pascal errors, but at most a C warning, if that. Any attempts to play C style games with pointers will result in errors.
Thus warnings should usually be about things that harm portability, but are understandable to this implementation. This includes the use of extensions in Standard mode. Unused parameters would probably be an exception to this generality. Unused function return values should be handled by assignment to a specific junk variable, and should be very rare. Many C foulups are due to ignoring error returns from functions, so making this hard to do in Pascal is a GOOD THING.
CBFalconer wrote:
This includes the use of extensions in Standard mode. Unused parameters would probably be an exception to this generality. Unused function return values should be handled by assignment to a specific junk variable, and should be very rare. Many C foulups are due to ignoring error returns from functions, so making this hard to do in Pascal is a GOOD THING.
Fortunately, most I/O errors (e.g.) in Pascal are not signaled via function results in the first place.
Apart from that, we could discuss what's "hard" enough. I'm content if it's explicit -- either at function declaration time (when the function's implementer knows that this result can be harmlessly ignored), or at call time for other cases. As others have pointed out, assignment to a junk variable might fail (i.e., still produce warnings) with better optimization, so writing `Discard (MyFunc (...))' there seems preferable.
Frank
Frank Heckenbach wrote:
... snip ...
Fortunately, most I/O errors (e.g.) in Pascal are not signaled via function results in the first place.
I have always considered this an error in Pascals basic design, at least as far as things that do not fit the format are concerned. Consider:
read(intvar);
which has to cause an i/o error and usually program abort (barring other extensions) if the interactive input is not properly formatted. So I have always provided (as an extension) an alternative standard function:
FUNCTION readx(something) : boolean;
which returns true on a formatting error, and extends to reals, etc. just as does the normal read function. Unlike read, it cannot be used as shorthand for multiple reads. Thus interactive usage is normally:
IF readx(something) THEN correctiveaction ELSE BEGIN (* all is well *) END;
with the knowledge that the offensive character is in input^.
Once readx is implemented, read is built by calling readx, except at the library level these are all specific closely typed functions, such as readxi.
CBFalconer wrote:
Frank Heckenbach wrote:
... snip ...
Fortunately, most I/O errors (e.g.) in Pascal are not signaled via function results in the first place.
I have always considered this an error in Pascals basic design, at least as far as things that do not fit the format are concerned. Consider:
read(intvar);
which has to cause an i/o error and usually program abort (barring other extensions) if the interactive input is not properly formatted.
I agree. In fact, here's where I prefer (in many situations) Borland's `{$I-}'/`IOResult' extension since it allows me to handle errors from a bunch of I/O statements together. Though exceptions (yet another extension) might be even better in the long run ...
So I have always provided (as an extension) an alternative standard function:
FUNCTION readx(something) : boolean;
which returns true on a formatting error, and extends to reals, etc. just as does the normal read function. Unlike read, it cannot be used as shorthand for multiple reads. Thus interactive usage is normally:
IF readx(something) THEN correctiveaction ELSE BEGIN (* all is well *) END;
with the knowledge that the offensive character is in input^.
BP has `Val (StringValue, TargetVariable, ErrorPosition)'. I usually use this, but I find the procedure-style usage rather clumsy often (the need for an extra variable which is usually just tested in a following conditional).
Therefore I've considered implementing such a Boolean function -- though my thoughts were more about parsing from a string, just like `Val' (it's more general -- you can always read from a file to a string first, but if you have the value in a string already, it would be rather inefficient to write it to a file first), and I'd have the result value the opposite way (True for success) ...
So my proposal is to add (now or later):
function String2Num(???) (const s: String; var n: <numeric type>): Boolean;
Comments?
Frank
At 18:22 +0200 29/9/04, Frank Heckenbach wrote:
So my proposal is to add (now or later):
function String2Num(???) (const s: String; var n: <numeric type>): Boolean;
Comments?
Isn't that just a utility function? I suspect that sort of thing belongs more in a utility unit that users can include if they desire. Especially since there are hundreds of ways of converting a string to a number and the requirements change depending on the usage. For example:
Do you strip spaces? What decimal separator do you use (".", "," or " " (space))? What thousand separator do you allow if any (".", "," or " " (space), "'", none)? What about stripping a currency symbol? What about supporting exponent symbols like K, M, G, T? Metric or Computer (1024) multipliers? What about hex, octal, binary support? And the ability to specify a default base?
And so on.
In my code, I have about half a dozen different String2Num functions and I'm not all that serious about internationalization and hardly ever let users enter numbers directly.
Enjoy, Peter.
Peter N Lewis wrote:
At 18:22 +0200 29/9/04, Frank Heckenbach wrote:
So my proposal is to add (now or later):
function String2Num(???) (const s: String; var n: <numeric type>): Boolean;
Comments?
Isn't that just a utility function? I suspect that sort of thing belongs more in a utility unit that users can include if they desire.
Then we'd need one for each type (and subrange types would generally be impossible since there are "infinitely" many of them). As a built-in function, the compiler could handle all integer and real types.
Especially since there are hundreds of ways of converting a string to a number and the requirements change depending on the usage. For example:
Do you strip spaces?
No, the user can do this before calling the function, if desired (e.g., by using `TrimBothStr').
What decimal separator do you use (".", "," or " " (space))? What thousand separator do you allow if any (".", "," or " " (space), "'", none)?
The real syntax as specified in the standards (plus BP extensions, according to dialect options as usual).
What about stripping a currency symbol? What about supporting exponent symbols like K, M, G, T? Metric or Computer (1024) multipliers?
Up to the user.
What about hex, octal, binary support? And the ability to specify a default base?
As defined in the respective standards (EP: `base#number') and dialects (BP: `$' for hex).
It's all the same we have for `Read[Ln|Str]' and `Val' already. (I don't really plan to enhance the actual reading routines, just provide another interface to them.)
In my code, I have about half a dozen different String2Num functions and I'm not all that serious about internationalization and hardly ever let users enter numbers directly.
In my code, I use `Val' most of the time (with numbers entered by users, read from files and what not), and apart from the clumsy procedure-style syntax, it's alright -- apart from monetary input for which I have a separate routine (http://fjf.gnu.de/misc/moneyutils.pas -- not very general yet) which uses `Val' in turn.
Frank
On 29 Sep 2004 at 18:22, Frank Heckenbach wrote:
[...]
So my proposal is to add (now or later):
function String2Num(???) (const s: String; var n: <numeric type>): Boolean;
Comments?
TurboPower had many of these (str2byte, str2long, str2real, etc.) in their tpstring unit. I think one that can cater for all numeric types would be very useful.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/
On Thu, Sep 30, 2004 at 09:20:33AM +0100, Prof A Olowofoyeku (The African Chief) wrote:
On 29 Sep 2004 at 18:22, Frank Heckenbach wrote:
function String2Num(???) (const s: String; var n: <numeric type>): Boolean; Comments?
TurboPower had many of these (str2byte, str2long, str2real, etc.) in their tpstring unit. I think one that can cater for all numeric types would be very useful.
{ converts a string by using current locale to a numeric value Example using de_DE locale: if String2NumLocale ('1,50', MyMoney) then ... True on success } function String2NumLocale (const s: String; var n: <numeric type>): Boolean;
Eike
Eike Lange wrote:
{ converts a string by using current locale to a numeric value Example using de_DE locale: if String2NumLocale ('1,50', MyMoney) then ... True on success } function String2NumLocale (const s: String; var n: <numeric type>): Boolean;
IMHO, monetare values are different enough from other numbers (e.g., at least in some countries, always written with two decimal digits, i.e. 4.20 not 4.2), also because it's fixed-point (two decimal digits, not floating point). In addition, negative values are written differently in some locales, etc. So I'd recommend using a routines specialized for monetary values.
Frank
Prof A Olowofoyeku (The African Chief) wrote:
On 29 Sep 2004 at 18:22, Frank Heckenbach wrote:
[...]
So my proposal is to add (now or later):
function String2Num(???) (const s: String; var n: <numeric type>): Boolean;
Comments?
TurboPower had many of these (str2byte, str2long, str2real, etc.) in their tpstring unit. I think one that can cater for all numeric types would be very useful.
Oh yeah, I remember (we've implemented them in our GPCUtils as well). In fact, my suggestion would be quite the same, just generalized, as you say. So it would be a drop-in replacement for all of those.
Frank
Frank Heckenbach wrote:
CBFalconer wrote:
Frank Heckenbach wrote:
... snip ...
Fortunately, most I/O errors (e.g.) in Pascal are not signaled via function results in the first place.
I have always considered this an error in Pascals basic design, at least as far as things that do not fit the format are concerned. Consider:
read(intvar);
which has to cause an i/o error and usually program abort (barring other extensions) if the interactive input is not properly formatted.
I agree. In fact, here's where I prefer (in many situations) Borland's `{$I-}'/`IOResult' extension since it allows me to handle errors from a bunch of I/O statements together. Though exceptions (yet another extension) might be even better in the long run ...
So I have always provided (as an extension) an alternative standard function:
FUNCTION readx(something) : boolean;
which returns true on a formatting error, and extends to reals, etc. just as does the normal read function. Unlike read, it cannot be used as shorthand for multiple reads. Thus interactive usage is normally:
IF readx(something) THEN correctiveaction ELSE BEGIN (* all is well *) END;
with the knowledge that the offensive character is in input^.
BP has `Val (StringValue, TargetVariable, ErrorPosition)'. I usually use this, but I find the procedure-style usage rather clumsy often (the need for an extra variable which is usually just tested in a following conditional).
Therefore I've considered implementing such a Boolean function -- though my thoughts were more about parsing from a string, just like `Val' (it's more general -- you can always read from a file to a string first, but if you have the value in a string already, it would be rather inefficient to write it to a file first), and I'd have the result value the opposite way (True for success) ...
So my proposal is to add (now or later):
function String2Num(???) (const s: String; var n: <numeric type>): Boolean;
Comments?
Pascal is somewhat unique in the way it encourages use of input streams. All input parsing leaves the terminating char in f^, so that the reason for rejection, or the existance of further data in a line, can be detected from that and the eoln condition. So I consider the existance of such things as my "readx(file, var) : boolean;" essential. Combined with a routine as:
PROCEDURE skipblks(f : text);
BEGIN WHILE NOT eoln(f) AND (f^ = ' ') DO get(f); END;
it allows complex input routines to be written as:
WHILE NOT eof(f) AND NOT eoln(f) DO BEGIN skipblks(f); IF readx(f, param[index]) THEN BEGIN (* corrective action, using f^ etc. *) readln(f); (* discard remainder of line *) END ELSE BEGIN (* possible tests on value *) (* possible tests on terminating char *) index := succ(index); END; END;
where param[index] can stand for many things. This sort of thing allows easy handling of input supplied as individual lines, or on one line with comma or blank separators, or whatever. Note especially that there is _no need_ for a buffer string of unknown length.
Once you have this sort of input routine, there is very little need for a string parsing mechanism. The problem is largely that C programmers are used to such a technique, and many will be lost without it.
Therefore I would try to make any such string parser logically equivalent to the use of readx*(f, var), maybe with sreadx*(s, var). There is no need for seof, and seoln(s) can detect the string end. It may be useful to include a var parameter for the current string index, by which time the function looks much like your proposal above, so that the programmers rule is to replace f with the s, index pair.
In PascalP I did not implement the set of sread* functions, preferring to build them to taste for an application. However I did provide a read(f, string) procedure. You already have that.
In PascalP I used the rule that extensions should almost always be in the form of standard functions or procedures, so that the only porting effort to purely standard Pascal was the writing of such functions. Thus there were no such things as unsigned integers, instead there was the "uadd(a, b : integer) : integer;" function, which ignored overflow and implemented the usual modulus rules.
CBFalconer wrote:
Pascal is somewhat unique in the way it encourages use of input streams. All input parsing leaves the terminating char in f^, so that the reason for rejection, or the existance of further data in a line, can be detected from that and the eoln condition. [...]
Once you have this sort of input routine, there is very little need for a string parsing mechanism. The problem is largely that C programmers are used to such a technique, and many will be lost without it.
I don't follow your last paragraph. Do you mean that any input data must come from files, or that if you have data in a string, you'd rather want to put it to a (temporary?) file first to parse it?
In the first case, I can only say that this is just not true. There are many other input sources (whether self-written graphical input routines, various communication-protocols and much more) which return the data in the form of strings (i.e., sequences of chars) naturally.
In the second case, I think it's very inefficient, even if you don't have to use actually temporary files, but say in-memory "virtual" files. That's because using a file involves several operations to start with (Rewrite, Write, Reset, Read for a minimum), and because the internal overhead in using files in Pascal is quite high (exactly because of `f^' and `EOLn', among other things). Sure, there may be lower-overhead implementations than GPC's current one, but I'm generally skeptical of using "virtual" files as a means in string processing.
In fact, I do string-processing a lot in my programs, and I'm quite happy to be able to do so, and it's not C-like at all.
I don't know -- perhaps you only know C's string routines (with pointer arithmetic, 0 terminators, hand-made memory allocation and all that dirty stuff). This might explain your aversion, but that's not a property of string handling in general, just of C's particular implementation. Even if you don't like Extended Pascal, you might want to look at its string handling routines (or, if you prefer, at BP's which are mostly the same with slightly different syntax), to see that it can be comfortable and not dangerous (no pointer arithmetics etc.).
So my question is really not whether to convert between strings and numbers, but only how to (most elegantly). Numbers to strings are easy to do with standard functions (such as `Integer2String') because the integer is a value parameter and thus quite flexible, and there are no error conditions (since the result type can be chosen big enough to hold any possible value). Strings to numbers is a little more tricky, since there are error conditions, so the result and the error cannot both be the result.
Therefore I would try to make any such string parser logically equivalent to the use of readx*(f, var), maybe with sreadx*(s, var). There is no need for seof, and seoln(s) can detect the string end.
If anything, then otherwise. Though it may seem unfamiliar to you, a string can store several lines of text. Even standard Pascal doesn't prohibit an "end of line" character value. (It does require reading a char from a `Text' file to yield space at end-of-line, but not so for `file of Char'.)
It may be useful to include a var parameter for the current string index, by which time the function looks much like your proposal above,
Not really. My intention (with the Boolean return value) is, e.g., to be able to use the function in conditionals, and not having to declare an extra variable, when (as most of the time) I just want to convert a string to a number and reject anything invalid. (Corrective action can be nice sometimes, but since it's necessarily heuristic, I often find it better to just reject invalid input and let the user correct things.)
In PascalP I used the rule that extensions should almost always be in the form of standard functions or procedures, so that the only porting effort to purely standard Pascal was the writing of such functions. Thus there were no such things as unsigned integers, instead there was the "uadd(a, b : integer) : integer;" function, which ignored overflow and implemented the usual modulus rules.
I see your point about porting, but apart from that, this idea seems quite uncomfortable to me. When you want to have an "unsigned integer" this way, if I get you right, you'd declare is as a regular `Integer', but you had to remember to always use `uadd', `uread', `uwrite' (or whatever you call them, i.e. special I/O routines that handle unsigned integers) and similar for all the other operations.
IMHO, this doesn't look very nice (not being able to use operators for `+', `-' etc., or `ReadLn'/`WriteLn' with a sequence of values), and it's quite dangerous because the compiler can't tell you when you once forget to use the special routines. In fact it's what assembler programmers have to do (there are no signed and unsigned types in assembler, just signed and unsigned operations).
There's no question that any extension *can* be written in a standard declaration scheme, but is it always a good idea? Isn't this just the C way where any "compiler magic" is frowned upon, and even the dubious varargs declarations were introduced, just so `printf' etc. could be declared in a standard way? IMHO, Pascal (or perhaps any higher-level language) is also about writing things in a more comfortable syntax and to let the compiler/interpreter do many nasty little things for you (such as here remembering whether your variable is signed or unsigned, once declared).
Frank
Frank Heckenbach wrote:
CBFalconer wrote:
Pascal is somewhat unique in the way it encourages use of input streams. All input parsing leaves the terminating char in f^, so that the reason for rejection, or the existance of further data in a line, can be detected from that and the eoln condition. [...]
Once you have this sort of input routine, there is very little need for a string parsing mechanism. The problem is largely that C programmers are used to such a technique, and many will be lost without it.
I don't follow your last paragraph. Do you mean that any input data must come from files, or that if you have data in a string, you'd rather want to put it to a (temporary?) file first to parse it?
No, I mean that C programmers have no built-in way of dealing with streams other than with scanf, which is normally a horror for error recovery. So they prefer to read complete strings (normally requiring a presized buffer [1]) and do conversions from there.
[1] Apart from using my ggets, available at: http://cbfalconer.home.att.net/download/ggets.zip
... snip ...
So my question is really not whether to convert between strings and numbers, but only how to (most elegantly). Numbers to strings are easy to do with standard functions (such as `Integer2String') because the integer is a value parameter and thus quite flexible, and there are no error conditions (since the result type can be chosen big enough to hold any possible value). Strings to numbers is a little more tricky, since there are error conditions, so the result and the error cannot both be the result.
The conversion routines for this normally pre-exist to implement write(textfile, ...). The only thing necessary is to extend that mechanism to strings. I would consider a cleaner method to be providing a way to attach a file to an internal string. However, as you say, the need to perform reset/rewrite on such a 'stringfile' might be exorbitant. Thus a family of sread and swrite(string, index, ....) might be easier. Again, they would draw on the same underlying routines. The usual colon syntax for field size etc. would be useful.
To me, once a programmer has learned to use the Pascal i/o facilities (read, write, readln, writeln, put, get, f^, eof, eoln) he should not need to learn anything more. Adding a letter to the routine names, and substituting "string, index" for "file" covers the added knowledge to deal with string conversions. That is why I simply added the letter x to provide error returns in read. String writing will need the error returns to handle overflowing the string capacity.
AFAICS read and write are the only routines that are 'overloaded' in Pascal, and that overloading is only apparent, since the compiler expands them to non-overloaded calls.
Therefore I would try to make any such string parser logically equivalent to the use of readx*(f, var), maybe with sreadx*(s, var). There is no need for seof, and seoln(s) can detect the string end.
If anything, then otherwise. Though it may seem unfamiliar to you, a string can store several lines of text. Even standard Pascal doesn't prohibit an "end of line" character value. (It does require reading a char from a `Text' file to yield space at end-of-line, but not so for `file of Char'.)
True. Then we need a seof routine.
It may be useful to include a var parameter for the current string index, by which time the function looks much like your proposal above,
Not really. My intention (with the Boolean return value) is, e.g., to be able to use the function in conditionals, and not having to declare an extra variable, when (as most of the time) I just want to convert a string to a number and reject anything invalid. (Corrective action can be nice sometimes, but since it's necessarily heuristic, I often find it better to just reject invalid input and let the user correct things.)
I include 'let the user' in corrective actions.
In PascalP I used the rule that extensions should almost always be in the form of standard functions or procedures, so that the only porting effort to purely standard Pascal was the writing of such functions. Thus there were no such things as unsigned integers, instead there was the "uadd(a, b : integer) : integer;" function, which ignored overflow and implemented the usual modulus rules.
I see your point about porting, but apart from that, this idea seems quite uncomfortable to me. When you want to have an "unsigned integer" this way, if I get you right, you'd declare is as a regular `Integer', but you had to remember to always use `uadd', `uread', `uwrite' (or whatever you call them, i.e. special I/O routines that handle unsigned integers) and similar for all the other operations.
IMHO, this doesn't look very nice (not being able to use operators for `+', `-' etc., or `ReadLn'/`WriteLn' with a sequence of values), and it's quite dangerous because the compiler can't tell you when you once forget to use the special routines. In fact it's what assembler programmers have to do (there are no signed and unsigned types in assembler, just signed and unsigned operations).
Depends on the machine. Some have unsigned and signed operators, with overflow in signed operators triggering traps.
There's no question that any extension *can* be written in a standard declaration scheme, but is it always a good idea? Isn't this just the C way where any "compiler magic" is frowned upon, and even the dubious varargs declarations were introduced, just so `printf' etc. could be declared in a standard way? IMHO, Pascal (or perhaps any higher-level language) is also about writing things in a more comfortable syntax and to let the compiler/interpreter do many nasty little things for you (such as here remembering whether your variable is signed or unsigned, once declared).
I second your attitude to varargs. However I have usually found that unsigned operations are relatively rare, given proper subrange typing. Depending on how the typing actually works, the definition "TYPE unsigned = integer;" should avoid misuse. Making unsigned operations stand out avoids many silly errors. To me, the compiler magic to which you object is using the same operators as for integers.
CBFalconer wrote:
No, I mean that C programmers have no built-in way of dealing with streams other than with scanf, which is normally a horror for error recovery. So they prefer to read complete strings (normally requiring a presized buffer [1]) and do conversions from there.
Actually, I prefer to do the same in Pascal most of the time, because my parsing needs are more complex than a simple field-by-field numeric input. (Actually, most of the time, at least some of my input fields, usually the first one(s), are strings. And since strings can contain spaces, and reading strings doesn't (and shouldn't) terminate at a space, I'll have to parse things myself anyway). The distinction between generic I/O errors (in the `Read (MyFile, StringVar)' calls) and numeric parsing errors (which I usually get via `Val') usually comes in nicely because I often handle them differently. (The former would be more like an internal/fatal error (after proper checks before `Reset' and for `EOF'), while the latter is usually a user error.)
So my question is really not whether to convert between strings and numbers, but only how to (most elegantly). Numbers to strings are easy to do with standard functions (such as `Integer2String') because the integer is a value parameter and thus quite flexible, and there are no error conditions (since the result type can be chosen big enough to hold any possible value). Strings to numbers is a little more tricky, since there are error conditions, so the result and the error cannot both be the result.
The conversion routines for this normally pre-exist to implement write(textfile, ...). The only thing necessary is to extend that mechanism to strings. I would consider a cleaner method to be providing a way to attach a file to an internal string. However, as you say, the need to perform reset/rewrite on such a 'stringfile' might be exorbitant. Thus a family of sread and swrite(string, index, ....) might be easier. Again, they would draw on the same underlying routines. The usual colon syntax for field size etc. would be useful.
That's all already there (`WriteStr' (EP), `Str' (BP)).
AFAICS read and write are the only routines that are 'overloaded' in Pascal,
Not really. `Reset' etc. are as well (different file types), many file routines (optional `Input'/`Output'), `Abs' (Integer and Real) plus several more mathematical functions (especially if you take complex numbers in EP), `New' (varying number of arguments even!), `Dispose', `Pack', `Unpack', `Succ', `Pred', `Ord' and probably some more ...
It may be useful to include a var parameter for the current string index, by which time the function looks much like your proposal above,
Not really. My intention (with the Boolean return value) is, e.g., to be able to use the function in conditionals, and not having to declare an extra variable, when (as most of the time) I just want to convert a string to a number and reject anything invalid. (Corrective action can be nice sometimes, but since it's necessarily heuristic, I often find it better to just reject invalid input and let the user correct things.)
I include 'let the user' in corrective actions.
My "let the user" usually means aborting (the program if batch, or the routine) and let them try again.
I second your attitude to varargs. However I have usually found that unsigned operations are relatively rare, given proper subrange typing.
I think so too (especially on 32+ bit machines -- on 16 bit machines the additional range between 32768 and 65535 was sometimes more valuable, whereas the difference between 2G and 4G is less often important).
Depending on how the typing actually works, the definition "TYPE unsigned = integer;" should avoid misuse.
Unfortunately not, since such types are entirely compatible. E.g., if `u' is of this type, it wouldn't prevent `u + u', `Read (u)', `Write (u)', `MyIntegerFunc (u)', which would be all be wrong when applied to an such an "unsigned" value outside of the `Integer' range.
Making unsigned operations stand out avoids many silly errors. To me, the compiler magic to which you object is using the same operators as for integers.
I did not object to compiler magic (I said C does). In fact, I endorse it (in this and several other cases).
Frank
On Wed, Sep 29, 2004 at 06:22:50PM +0200, Frank Heckenbach wrote:
So my proposal is to add (now or later):
function String2Num(???) (const s: String; var n: <numeric type>): Boolean;
Comments?
I would find it more appropriate to have a routine that works more like read, but then on a string instead of a text file. It should accommodate various types, and it should somehow indicate how much of the string has actually been converted, so that you can easily pick up where the conversion stopped.
The latter can be done in several ways:
1. Somehow return the character index of the first character that was NOT converted. In that case, it might be convenient to provide the conversion routine with a starting index for the conversion, rather than just start at the beginning. This could be handled by a single var parameter, whose initial value is the starting position, and whose final value is the ending position (beginning of next item in the string).
2. Make the string parameter a var parameter, and let the conversion routine chop off that part that has been converted.
It would be nice if you could easily "string" together a sequence of conversions to extract a sequence of values from a string. And it would also be nice if you could write your own customized conversion routines (e.g. for more complex types), using same approach.
Let's assume var S: String; n, i: Integer; x: Real; r: MyRec;
In case of 1, you would have
function String2Num ( const S: String; var i: Integer; var n: <numeric type>): Boolean;
and you could "string" together
i := StartValue ; String2Num ( S, i, n ) ; String2Num ( S, i, x ) ; String2MyRec ( S, i, r )
In case of 2, you would have
function String2Num ( var S: String; var n: <numeric type>): Boolean;
String2Num ( S, n ) ; String2Num ( S, x ) ; String2MyRec ( S, r )
Of course, this ignores the issue of error (exception) handling. But I hope that the idea is clear.
An alternative is to take the approach of sscanf from C, where you extract a sequence of items from a string according to some format, but it doesn't tell you where conversions stopped (though it does return the number of items actually converted, which could be less than the number of conversions requested due to an error).
By the way, I don't like the name "String2Num". How about "StrToNum"? Delphi has a whole set of StrTo... functions. These raise the exception EConvertError in case of an error. FreePascal implements them as well in its SysUtils unit.
Skipping of leading white space seems natural to me when converting numbers (that is what "read" does as well). But, as you say, it could be handled separately (basically it is a TrimLeft). On the other hand, it is also awkward to dilute your code with many such Trim operations. I would surmise that users will (also) want a single routine that converts a number, while skipping leading whitespace.
Best regards,
Tom Verhoeff
Tom Verhoeff wrote:
On Wed, Sep 29, 2004 at 06:22:50PM +0200, Frank Heckenbach wrote:
So my proposal is to add (now or later):
function String2Num(???) (const s: String; var n: <numeric type>): Boolean;
Comments?
I would find it more appropriate to have a routine that works more like read, but then on a string instead of a text file. It should accommodate various types, and it should somehow indicate how much of the string has actually been converted, so that you can easily pick up where the conversion stopped.
That's `Val' (BP routine, implemented in GPC for a long time).
- Somehow return the character index of the first character that was NOT converted.
That's what `Val' does (in the 3rd parameter).
In that case, it might be convenient to provide the conversion routine with a starting index for the conversion, rather than just start at the beginning.
No need to since it can easiy be accomplished using `SubStr', `Copy' or a string slice (`s[i .. j]').
It would be nice if you could easily "string" together a sequence of conversions to extract a sequence of values from a string. And it would also be nice if you could write your own customized conversion routines (e.g. for more complex types), using same approach.
Let's assume var S: String; n, i: Integer; x: Real; r: MyRec;
In case of 1, you would have
function String2Num ( const S: String; var i: Integer; var n: <numeric type>): Boolean;
and you could "string" together
i := StartValue ; String2Num ( S, i, n ) ; String2Num ( S, i, x ) ; String2MyRec ( S, i, r )
In case of 2, you would have
function String2Num ( var S: String; var n: <numeric type>): Boolean;
String2Num ( S, n ) ; String2Num ( S, x ) ; String2MyRec ( S, r )
Of course, this ignores the issue of error (exception) handling. But I hope that the idea is clear.
Well, error handling is what this discussion is all about. Otherwise you can just use ReadStr:
ReadStr (S, n, x, r);
An alternative is to take the approach of sscanf from C, where you extract a sequence of items from a string according to some format,
Even if Scott hasn't yet posted his usual rant by the time my mail is sent ;-), I'd also express my objections against using runtime format strings. I can't see a reason they'd be useful (since the parameters, and therefore the types to be read, must be known at compil time, anyway).
So in a way, `ReadStr' is `sscanf' without the obnoxious format string. (The compiler knows the types to read already by itself.)
By the way, I don't like the name "String2Num". How about "StrToNum"? Delphi has a whole set of StrTo... functions. These raise the exception EConvertError in case of an error.
So I suppose they don't return a Boolean then? Then in fact it may be preferable to use a different name here to avoid confusion. Apart from that, I wouldn't mind StrToNum personally.
Skipping of leading white space seems natural to me when converting numbers (that is what "read" does as well). But, as you say, it could be handled separately (basically it is a TrimLeft). On the other hand, it is also awkward to dilute your code with many such Trim operations. I would surmise that users will (also) want a single routine that converts a number, while skipping leading whitespace.
In fact `Val' does so (in BP and GPC), as well as `ReadStr' (EP and GPC). Sorry if I stated this wrongly. So the new function would also do it.
Frank
Frank Heckenbach wrote:
BTW, a future GPC version might allow macros that expand to compiler-directives, but AFAICS this wouldn't help here since you'd need this on the MW side where it apparently isn't possible.
Still, this is an interesting idea in other situations. For example {$align powerpc} is a much needed compiler directive in MW. If we can define {$align powerpc} to be a macro in GPC, writing source-code for two compilers becomes easier. For example.
{$align powerpc} Type ... {$align reset}
is better readable than:
{$ifc defined __GPC__} {$local maximum-field-alignment=32} {$endc} {$ifc defined __MWERKS__} {$align powerpc} {$endc} Type ... {$ifc defined __GPC__} {$endlocal} {$endc} {$ifc defined __MWERKS__} {$align reset} {$endc}
Unfortunately, there are still reasons to use MW Pascal and thus to keep library code compatible with both GPC and MW:
(1) MW Pascal produces CFM/PEF binaries (that are compatible with both Mac OS and Mac OS X) (2) Many plug-in architectures on the Macintosh still require CFM/PEF rather than Mach-O (as produced by GPC for Mac OS X) (3) Millions of lines of existing code.
(But I don't want to complain, just elaborating on a theme)
Regards,
Adriaan van Os
Adriaan van Os wrote:
Frank Heckenbach wrote:
BTW, a future GPC version might allow macros that expand to compiler-directives, but AFAICS this wouldn't help here since you'd need this on the MW side where it apparently isn't possible.
Still, this is an interesting idea in other situations. For example {$align powerpc} is a much needed compiler directive in MW. If we can define {$align powerpc} to be a macro in GPC, writing source-code for two compilers becomes easier.
That's not actually what I meant, sorry. I meant macros, not compiler directives that expand to other compiler directives. The latter would probably be more work. For macros, it's natural (and easier) to do this since they expand to program text -- only the current preprocessor architecture gets a bit in the way.
At least, you might then be able to define a macro, say `ALIGN_POWERPC' that expands to `{$local maximum-field-alignment=32}' in GPC and nothing in MW ...
Frank