[fpc-pascal] function returning a record vs paramaters

Anton Tichawa anton.tichawa at chello.at
Sun Jul 10 01:34:37 CEST 2005


L505 wrote:

>| procedure my_procedure(var a_record: t_my_record);
>|
>| In this case, a simple pointer is passed to my_procedure. This is also
>| the way most C libraries work, passing a pointer to a structure.
>
>Would a C program be able to call a Pascal SO or DLL file and directly read a
>record from pascal, as a structure in C? i.e. no hassles required (presuming the
>record didn't contain strings of course.. let's just say three integers)
>
>  
>
Yes. Hassles are still there:

1. The pascal record and the C structure have to allocate and pack data 
the same way, with the same data sizes and semantics (you mentioned 
strings, but also "int" and "integer" change their size every few years, 
bool / BOOL / boolean have different semantics, ...)

2. Calling conventions have to match. They can be set using procedure 
modifiers like "stdcall", "cdecl" etc. You have to check the docs here.

>|
>| When a function returns a record, an additional pointer parameter is
>| passed to it, invisibly to the pascal programmer, and the function fills
>| in the structure pointed to by that parameter.
>
>some performance loss then. But not actually twice the memory used to make a
>copy?
>
>  
>
No. Even no performance loss. The "additional pointer" is the same as 
the otherwise used "var parameter". The following two pascal procedure 
do essentially the same, they just differ in syntax:

function proc_1: t_record;
begin
  result.a := 1;
end;

procedure proc_2(var x: t_record);
begin
  x.a := 1;
end;

The first form, proc_1, is silently converted to the second form, by the 
compiler.

>|
>| For this reason, I personally tend to prefer a var-parameter: A function
>| returning a record looks like creating or allocating that record, which
>| is not true. A  var-parameter shows, in pascal, a structure similar to
>| what happens on the machine code level. But it's a matter of taste, and,
>| of how the function result is used: When the result is often used as
>| part of expressions, or as a parameter to other procedures, the "result"
>| way is more legible than the "var-parameter" way.
>
>Maybe make it easier, a result prefix or something like so could be used:
>
>procedure(integer, string, other, Result_Record);
>
>or
>
>function(integer, string, other, Result_Record): boolean;
>
>or
>
>function(integer, string, other, ResultRecord): boolean;
>
>Researching this topic, I found some arguments and discussions from people using
>other languages coming across the same questions - such as Ada people
>questioning the Out keyword in their functions, and so on. I just want to
>clarify what the best way is.. I do like returning a record since the code
>appears more clear to me this way, but I suppose I'll use a parameter for
>performance reasons.
>
>  
>
At least for free pascal, there is no lack in performance when you 
"return a record".

>When teaching people Pascal or learning Pascal, I'm sure people will question
>how a parameter can possibly return a variable.. "isn't that what the result is
>supposed to do?" So it does feel sort of hackish to do that. It feels very
>win32api-ish too. In this case, I wish there were a way to make code clearer
>while still offering the same performance/benefits. I think Result_Record is
>somewhat of a hack too.. almost like a "workaround" to something that might be
>possible to improve.. but I'm not so sure if it can. It's real high priority
>though, since most people know you can return a value as a parameter.
>
>  
>
I'm not sure if I get your point right, especially concerning Ada ... 
Anyway, if people question how a parameter can possibly return a value, 
tell them a "var parameter" allows more than a function result. It 
allows the called procedure to -act- on the data, including both reading 
and writing. That would be "in out" in Ada. In Pascal, this is also 
known as "call by reference", and not necessarily hackish ... Think of a 
procedure that calculates and inserts the checksum in a telegram that 
already contains valid data:

procedure insert_checksum(var a_telegram: t_telegram_record);

This procedure reads the telegram data, calculates some sort of checksum 
and fills in the telegram's checksum field. This cannot be done with the 
"return a record" method, except when passing the parameter twice (= 
performance loss).

But, if you just have to return data, without reading it's previous 
contents, you may use the "return a record" method without performance loss.

Anton.






More information about the fpc-pascal mailing list