On 9 Mar 2005 at 2:01, Waldek Hebisch wrote:
[...]
The differences are:
- GPC allows casting integers to function types
- Inside a cast to function type GPC calls `foo'. It seems that FPC just uses adress of `foo'.
Concering 1: it is dangerous, but sometimes convenient. Usually we prefer safe constructs and implement unsafe versions only for compatibility. But casts are dangerous anyway... Of course, we could requrire double casts (which even now are sometimes necessary) like: tfunc (pointer(foo))
Concering 2: There is genuine ambiguity here. Namely, for parameterless function we can either call the function and cast the value or cast the reference to the function. Arguably, the second choice is more natural.
That is what I was intending in the "bar := tfunc (foo);" assignment (i.e., to assign to "bar" the address of "foo") - not to call "foo". You are right that the call is ambiguous. Perhaps Delphi and BP just refuse to guess what the programmer is trying to do, and issue a compiler error - however, perhaps they also assume that I want to call the function "foo", but refuse to do so because they don't like the type-cast.
GPC guesses (wrongly, as far my intentions are concerned) that I want to call "foo", and does so. But "bar" is not assigned a valid address, and so the call to it crashes the program. FPC guesses (rightly, as far as my intentions are concerned) that what I want is the address of "foo", and issues it. Bottom line - the compiler should really not have to guess what I am trying to do, especially since I could have removed any ambiguity by using "bar := tfunc (addr (foo));" or "bar := tfunc (@foo);", as I eventually did.
But assuming that we need to mix functions and integers (say, in an interpreter for untyped language), then we may wish to write:
program bug1; {$X+} type tfunc = function : pointer; function baz : integer; begin baz := 1024 * 2; end; var bar : tfunc; function foo : integer; begin foo := integer(@baz); end; begin bar := tfunc (foo); { this is where Delphi and BP barf } writeln (integer (bar)); end.
For this program GPC gives "correct" result.
This result is correct if the assumption that the intention is to call "foo", rather than to assign the address of "foo".
In default mode FPC rejects it, in Delphi mode FPC accepts it but gives "wrong" result.
As above. FPC assumes that what I want is the address of "foo", and gives it to me. That is as far my original intentions are concerned. The code, as written, does actually mean that "foo" should be called. This is the assumption (correct, regardless of my intentions) of GPC, BP and Delphi (even though BP and Delphi do not like the call).
BTW, when I write:
bar := tfunc (foo());
then my copy of FPC (1.9.4 on Debian) still gives wrong result.
What it gives is the value of "foo", which, inside "foo", you assign the address of "baz" (i.e., foo returns the address of baz as an integer). That seems correct to me.
As you can see there is real mess here.
Indeed.
I agree that on your example FPC way is more usefull than GPC way. But before we change GPC we should know what _exact_ rules BP, Delphi and FPC use
Well, it seems to me that BP and Delphi and GPC are all assuming that, by assigning a value to "bar", what we really want to do is to call "foo", rather than to assign it's address to "bar". However, since both BP and Delphi reject the call, perhaps GPC should also reject it in BP and Delphi mode (Virtual Pascal also rejects it by the way). If GPC will accept it at all (which it should when in GPC mode), then it should assign the address of "foo", rather than to call the function (just like FPC).
(BTW any dialect with casts and function types is worth checking (Mac ???)). Also, we need to distinguish intended behaviour and bugs (I consider FPC treatment of `tfunc (foo());' as an obvious bug).
Not necessarily. Since "bar" is a pointer to a function, when we assign a value to it, it would seem natural to expect that what we are assigning to it is an address, since that is all that can be assigned to it. However, Delphi accepts 'tfunc (foo());' and treats it as a call to "foo", rather than the assignment of "foo's" address. So the trailing brackets make all the difference to Delphi's acceptance or rejection of the code.
In conclusion, I think this is what GPC should do:
1. "bar := tfunc (foo)" = assign to bar the address of foo, but don't call foo
2. "bar := tfunc (foo ())" = call foo (and also assign to bar the address of foo?) so that "writeln (integer (bar))" should result in a second call to foo - otherwise, what value does bar hold?
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.greatchief.plus.com/