Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2023-06

Function to create a record ?

10 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Steve Litt

Hi all,

I'm trying to create a function (called newperson()) that creates a new instance of a record. The following compiles with no errors or warnings in FPC, but multiple calls to newperson() produce exactly the same variable, so in the preceding changing person changes person2, and vice versa:

===================================================
program test2;
const
	junkvar_size = 20000000;
type
	personrecord = record
	name: string;
	end;
var
	person: personrecord;
	person2: personrecord;
	junkvar: array[1..junkvar_size] of char;
function newperson(): personrecord;
var newp: personrecord;
begin
	newp.name := '';
	newperson := newp;
end;
function modperson(person: personrecord; name: string): personrecord;
begin
	person.name := name;
	modperson := person;
end;
procedure writeperson(person: personrecord);
begin
	writeln(person.name);
end;
begin
	person := newperson();
	fillchar(junkvar, junkvar_size, 'a');
	person2 := newperson();
	fillchar(junkvar, junkvar_size, 'b');
	person := modperson(person, 'Martin');
	person := modperson(person2, 'Maria');
	{writeln(junkvar);}
	writeperson(person);
	writeperson(person2);
end.
===================================================

What is the best way for me to construct newperson() so that every time called it would return a new variable?

Thanks,

SteveT

Steve Litt
Autumn 2022 featured book: Thriving in Tough Times http://www.troubleshooters.com/bookstore/thrive.htm

Ralf Quint
to Steve Litt
Steve Litt wrote 56 lines
Hi all, I'm trying to create a function (called newperson()) that creates a new instance of a record. The following compiles with no errors or warnings in FPC, but multiple calls to newperson() produce exactly the same variable, so in the preceding changing person changes person2, and vice versa: =================================================== program test2; const junkvar_size = 20000000; type personrecord = record name: string; end; var person: personrecord; person2: personrecord; junkvar: array[1..junkvar_size] of char; function newperson(): personrecord; var newp: personrecord; begin newp.name := ''; newperson := newp; end; function modperson(person: personrecord; name: string): personrecord; begin person.name := name; modperson := person; end; procedure writeperson(person: personrecord); begin writeln(person.name); end; begin person := newperson(); fillchar(junkvar, junkvar_size, 'a'); person2 := newperson(); fillchar(junkvar, junkvar_size, 'b'); person := modperson(person, 'Martin'); person := modperson(person2, 'Maria'); {writeln(junkvar);} writeperson(person); writeperson(person2); end. =================================================== What is the best way for me to construct newperson() so that every time called it would return a new variable?

W.T.F.?

Sorry, but for how long are you programming, in general, and for how long in Pascal?

Seriously, you should take some very basic Pascal tutorials, work through them, and in particular, pay close attention to the "scope" of variables as well as parameter passing. You seem to be completely oblivious to those very basics here... :(

Ralf

Steve Litt
to Henry Vermaak

Henry Vermaak via fpc-pascal said on Fri, 2 Jun 2023 09:38:17 +0100

Show quoted text 9 lines
On Fri, 2 Jun 2023 at 01:36, Steve Litt via fpc-pascal wrote: > fillchar(junkvar, junkvar_size, 'b'); > person := modperson(person, 'Martin'); > person := modperson(person2, 'Maria'); Maybe a typo? (E.g. person2 := modperson(person2, 'Maria')) Henry

Thanks Henry!

You're right: Changing the second person := to person2 := did just what
I wanted it to do.

Because returning a local array or string as a function return in C leads to horrible intermittents due to the local going out of scope and relinquishing the local's stack, which can then be overwritten, I added a procedure, a function, and a main program statement which each consumed two million bytes of local variables, and the person and person2 didn't get overwritten. Very cool.

When I increased the huge local vars to three million bytes, the program segfaulted. I figure I just ran it out of stack, but until I did, the huge local vars didn't trash the contents of person and person2.

Thanks for your help.

SteveT

Steve Litt
Autumn 2022 featured book: Thriving in Tough Times http://www.troubleshooters.com/bookstore/thrive.htm

Steve Litt
to Ralf Quint: W.T.F.? Sorry, but for how long are you programming, in general, and for how long in…

Ralf Quint via fpc-pascal said on Thu, 1 Jun 2023 17:43:58 -0700

Show quoted text 17 lines
On 6/1/2023 5:36 PM, Steve Litt via fpc-pascal wrote: > > What is the best way for me to construct newperson() so that every > time called it would return a new variable? W.T.F.? Sorry, but for how long are you programming, in general, and for how long in Pascal? Seriously, you should take some very basic Pascal tutorials, work through them, and in particular, pay close attention to the "scope" of variables as well as parameter passing. You seem to be completely oblivious to those very basics here... :( Ralf

Feeling better after getting that off your chest Ralf?

My <solved> post reveals the outcome of my investigation.

SteveT

Steve Litt
Autumn 2022 featured book: Thriving in Tough Times http://www.troubleshooters.com/bookstore/thrive.htm

Unknown author
to Steve Litt: Henry Vermaak via fpc-pascal said on Fri, 2 Jun 2023 09:38:17 +0100 Thanks Henry! You're…

Depending on the compiler *not* to overwrite local variables is most certainly the wrong way to go with this.  You really should create either a global record/object, or use functions to pass around the information you need.  Expecting the operating system to keep local variables after the area goes out of scope is just begging for errors later on when the compiler/os treatment of said areas changes.

Steve Litt wrote 37 lines
Henry Vermaak via fpc-pascal said on Fri, 2 Jun 2023 09:38:17 +0100 > On Fri, 2 Jun 2023 at 01:36, Steve Litt via fpc-pascal > wrote: >> fillchar(junkvar, junkvar_size, 'b'); >> person := modperson(person, 'Martin'); >> person := modperson(person2, 'Maria'); > Maybe a typo? (E.g. person2 := modperson(person2, 'Maria')) > > Henry Thanks Henry! You're right: Changing the second person := to person2 := did just what I wanted it to do. Because returning a local array or string as a function return in C leads to horrible intermittents due to the local going out of scope and relinquishing the local's stack, which can then be overwritten, I added a procedure, a function, and a main program statement which each consumed two million bytes of local variables, and the person and person2 didn't get overwritten. Very cool. When I increased the huge local vars to three million bytes, the program segfaulted. I figure I just ran it out of stack, but until I did, the huge local vars didn't trash the contents of person and person2. Thanks for your help. SteveT Steve Litt Autumn 2022 featured book: Thriving in Tough Times http://www.troubleshooters.com/bookstore/thrive.htm _______________________________________________ fpc-pascal maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Steve Litt
to Unknown author

Travis Siegel via fpc-pascal said on Sun, 4 Jun 2023 19:38:44 +0000

Show quoted text 32 lines
On 6/4/2023 1:37 PM, Steve Litt via fpc-pascal wrote: > Henry Vermaak via fpc-pascal said on Fri, 2 Jun 2023 09:38:17 +0100 > >> On Fri, 2 Jun 2023 at 01:36, Steve Litt via fpc-pascal >> wrote: >>> fillchar(junkvar, junkvar_size, 'b'); >>> person := modperson(person, 'Martin'); >>> person := modperson(person2, 'Maria'); >> Maybe a typo? (E.g. person2 := modperson(person2, 'Maria')) >> >> Henry > Thanks Henry! > > You're right: Changing the second person := to person2 := did just > what I wanted it to do. > > Because returning a local array or string as a function return in C > leads to horrible intermittents due to the local going out of scope > and relinquishing the local's stack, which can then be overwritten, > I added a procedure, a function, and a main program statement which > each consumed two million bytes of local variables, and the person > and person2 didn't get overwritten. Very cool. > > When I increased the huge local vars to three million bytes, the > program segfaulted. I figure I just ran it out of stack, but until I > did, the huge local vars didn't trash the contents of person and > person2. > > Thanks for your help. > > SteveT
Show quoted text 6 lines
Depending on the compiler *not* to overwrite local variables is most certainly the wrong way to go with this.  You really should create either a global record/object, or use functions to pass around the information you need.  Expecting the operating system to keep local variables after the area goes out of scope is just begging for errors later on when the compiler/os treatment of said areas changes.

Thanks Travis,

This is the info I was asking for. Yeah, passing the local as a function return worked, but because of a horrible experience doing that in C, I was suspicious and leery of actually using that technique.

I'll just use new and dispose.

Thanks,

SteveT

Steve Litt
Autumn 2022 featured book: Thriving in Tough Times http://www.troubleshooters.com/bookstore/thrive.htm

Jean SUZINEAU
to Steve Litt: I'm trying to create a function (called newperson()) that creates a new instance of a…

Hello, I have a hard time trying to understand what you want to test.

In your functions, you are using a record, not a class or a pointer to record or an object.

The personrecord just behave in your parameters and return value as an Integer or a String, and your fillchar doesn't write outside of the memory allocated for you junkvar, so I don't see what can go wrong.

If you trace the address of person.name like this:

//begin code
begin
	person := newperson();
         writeln('1, person.name address: ', IntToHex(Int64(Pointer(@(person.name)))));
	fillchar(junkvar, junkvar_size, 'a');
	person2 := newperson();
	fillchar(junkvar, junkvar_size, 'b');
	person := modperson(person, 'Martin');
	person := modperson(person2, 'Maria');
         writeln('2, person.name address: ', IntToHex(Int64(Pointer(@(person.name)))));
	{writeln(junkvar);}
	writeperson(person);
	writeperson(person2);
end.
//end code

You'll see that the address doesn't change, for example:

1, person.name address: 000000000050C7F0
2, person.name address: 000000000050C7F0

But if you declare your personrecord as a class, the things doesn't behave the same way:

//begin code
const
	junkvar_size = 20000000;
type
	personclass = class
	name: string;
	end;
var
	person: personclass;
	person2: personclass;
	junkvar: array[1..junkvar_size] of char;
function newperson(): personclass;
var newp: personclass;
begin
      newp:= personclass.Create;
	newp.name := '';
	newperson := newp;
end;
function modperson(person: personclass; name: string): personclass;
begin
	person.name := name;
	modperson := person;
end;
procedure writeperson(person: personclass);
begin
	writeln(person.name);
end;
begin
	person := newperson();
         writeln('1, person.name address: ', IntToHex(Int64(Pointer(@(person.name)))));
	fillchar(junkvar, junkvar_size, 'a');
	person2 := newperson();
	fillchar(junkvar, junkvar_size, 'b');
	person := modperson(person, 'Martin');
	person := modperson(person2, 'Maria');
         writeln('2, person.name address: ', IntToHex(Int64(Pointer(@(person.name)))));
	{writeln(junkvar);}
	writeperson(person);
	writeperson(person2);
end.
//end code

You'll get a different address, something like:

1, person.name address: 00007FFFF7F910E8
2, person.name address: 00007FFFF7F91108

Jean SUZINEAU
to Jean SUZINEAU

Oops, I hit "Send message" too quickly.

The only difference in the second code is:

- personrecord renamed to personclass and declared as "personclass = class"

- "newp:= personclass.Create;" added in function newperson

Of course for a clean code, you'll need to call something like "FreeAndNil( person);" or "person.free" to release properly the memory allocated.

Steve Litt
to Jean SUZINEAU: Hello, I have a hard time trying to understand what you want to test. In your functions,…

Jean SUZINEAU via fpc-pascal said on Mon, 5 Jun 2023 11:56:59 +0200

Show quoted text 93 lines
Hello, I have a hard time trying to understand what you want to test. In your functions, you are using a record, not a class or a pointer to record or an object. The personrecord just behave in your parameters and return value as an Integer or a String, and your fillchar doesn't write outside of the memory allocated for you junkvar, so I don't see what can go wrong. If you trace the address of person.name like this: //begin code begin person := newperson(); writeln('1, person.name address: ', IntToHex(Int64(Pointer(@(person.name))))); fillchar(junkvar, junkvar_size, 'a'); person2 := newperson(); fillchar(junkvar, junkvar_size, 'b'); person := modperson(person, 'Martin'); person := modperson(person2, 'Maria'); writeln('2, person.name address: ', IntToHex(Int64(Pointer(@(person.name))))); {writeln(junkvar);} writeperson(person); writeperson(person2); end. //end code You'll see that the address doesn't change, for example: 1, person.name address: 000000000050C7F0 2, person.name address: 000000000050C7F0 But if you declare your personrecord as a class, the things doesn't behave the same way: //begin code const junkvar_size = 20000000; type personclass = class name: string; end; var person: personclass; person2: personclass; junkvar: array[1..junkvar_size] of char; function newperson(): personclass; var newp: personclass; begin newp:= personclass.Create; newp.name := ''; newperson := newp; end; function modperson(person: personclass; name: string): personclass; begin person.name := name; modperson := person; end; procedure writeperson(person: personclass); begin writeln(person.name); end; begin person := newperson(); writeln('1, person.name address: ', IntToHex(Int64(Pointer(@(person.name))))); fillchar(junkvar, junkvar_size, 'a'); person2 := newperson(); fillchar(junkvar, junkvar_size, 'b'); person := modperson(person, 'Martin'); person := modperson(person2, 'Maria'); writeln('2, person.name address: ', IntToHex(Int64(Pointer(@(person.name))))); {writeln(junkvar);} writeperson(person); writeperson(person2); end. //end code You'll get a different address, something like: 1, person.name address: 00007FFFF7F910E8 2, person.name address: 00007FFFF7F91108

Thanks Jean,

The problem I was trying to fix was that I accidentally said:

person := modperson(person2, 'Maria');

instead of

person2 := modperson(person2, 'Maria');
^^^^^^^  Note the 2

But wait, there's more...

As Travis Siegel pointed out, my method relied on the compiler not to overwrite RAM of a variable that had gone out of scope, and that's the highway to heartache. So I was first going to implement a non-OOP solution using New and Dispose, and then implement an OOP solution. Now that you provided the OOP solution, I'll make sure I can get your solution to work, and then go back to the non-OOP solution.

So **THANK YOU** ! ! !

SteveT

Steve Litt
Autumn 2022 featured book: Thriving in Tough Times http://www.troubleshooters.com/bookstore/thrive.htm