Sign in Join

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

Mailing lists / fpc-pascal / 2008-03

Re: Initializing Records Automatically

29 messages · 8 people · –

Reply by email Subscribe to this list Your subscription

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

Florian Klaempfl
to L: http://stanleyxu2005.blogspot.com/2008/01/potential-memory-leak-by-initializing.html…
Show quoted text 33 lines
http://stanleyxu2005.blogspot.com/2008/01/potential-memory-leak-by-initializing.html Interesting.. So with procedure InitRecord(out R; SizeOfRecord: Integer); begin FillChar(R, SizeOfRecord, #0); end; Even if it has dynamic array, ansistrings, shortstrings, integers, I assume it is okay to initialize it this way (assumptions are bad). The problem: initializing records with automated types by going through each and every field is error prone because if you expand the record later on with more fields, you might forget to update your custom init procedure.. And a question: does old borland style "object" initialize anything as classes do? Stack based ones? heap ones? Interesting pondering: what would be nicee is an auto initialized record: procedure example; var something: somerec autoinit; begin end; Many times I find myself initializing stuff tediously and error prone when you do it a human way without automation.

Records and objects containing automated fields are initialized? Or do I miss something? The whole blog post is nonsense, the proper way to finalize a record before cleaning it with fillchar is calling finalize with the record.

Reply by email

Marco van de Voort
to Florian Klaempfl
Show quoted text 6 lines
L schrieb: > > Many times I find myself initializing stuff tediously and error prone > when you do it a human way without automation. Records and objects containing automated fields are initialized?

Are they? Or only the automated fields?

Reply by email

Jonas Maebe
to L: Florian wrote.. Oh...? This is something I have never been clear about :-( So a record…
Show quoted text 14 lines
So a record with an ansistring and an integer.. for example even local scope.. Will be all zeros? procedure test; var somerec: Tsomerec; begin // these checks are okay? if somerec.astring = '' if somerec.someint = 0 end; i.e. above is not random data?

The ansistring is initialised on entry, the someint is not. The reason that refcounted fields simply have to be initialised, is that otherwise you'd get a crash as soon as you'd try to assign something to them (since an assignment is basically "increfcount(source); decrefcount(target); pointer(target):=pointer(source)", which would go horribly wrong if target could contain garbage).

Jonas

Reply by email

ik
to L: http://stanleyxu2005.blogspot.com/2008/01/potential-memory-leak-by-initializing.html…

Since when are you using fillchar on a string in Pascal ? that's a C approach.

BTW Most Pascal's string functions will stop on the first #0 they encounter, at least the Delphi's tool that I remember.

I think he misses the entire point in his blog.

Ido

Show quoted text 36 lines
http://stanleyxu2005.blogspot.com/2008/01/potential-memory-leak-by-initializing.html Interesting.. So with procedure InitRecord(out R; SizeOfRecord: Integer); begin FillChar(R, SizeOfRecord, #0); end; Even if it has dynamic array, ansistrings, shortstrings, integers, I assume it is okay to initialize it this way (assumptions are bad). The problem: initializing records with automated types by going through each and every field is error prone because if you expand the record later on with more fields, you might forget to update your custom init procedure.. And a question: does old borland style "object" initialize anything as classes do? Stack based ones? heap ones? Interesting pondering: what would be nicee is an auto initialized record: procedure example; var something: somerec autoinit; begin end; Many times I find myself initializing stuff tediously and error prone when you do it a human way without automation. _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply by email

Jonas Maebe
to ik
ik wrote
Since when are you using fillchar on a string in Pascal ? that's a C approach.

He's using it on a record. Initialising records with fillchar (regardless of what they contain) is quite common in Pascal as well. And as Florian mentioned, if you do this for a record containing refcounted fields, you first have to call finalize() on it.

Jonas

Reply by email

L

http://stanleyxu2005.blogspot.com/2008/01/potential-memory-leak-by-initializing.html

Interesting..

So with

procedure InitRecord(out R; SizeOfRecord: Integer);
begin
  FillChar(R, SizeOfRecord, #0);
end;

Even if it has dynamic array, ansistrings, shortstrings, integers,

I assume it is okay to initialize it this way (assumptions are bad).

The problem: initializing records with automated types by going through each and every field is error prone because if you expand the record later on with more fields, you might forget to update your custom init procedure..

And a question: does old borland style "object" initialize anything as classes do? Stack based ones? heap ones?

Interesting pondering: what would be nicee is an auto initialized record:

procedure example;
var something: somerec autoinit;
begin
end;

Many times I find myself initializing stuff tediously and error prone when you do it a human way without automation.

Reply by email

L
to L

Florian wrote..

Records and objects containing automated fields are initialized? Or do I miss something?

Oh...?
This is something I have never been clear about :-(

So a record with an ansistring and an integer.. for example even local scope..

Will be all zeros?

procedure test;
var somerec: Tsomerec;
begin
  // these checks are okay?
  if somerec.astring = ''
  if somerec.someint = 0
end;

i.e. above is not random data?

The reason I ask is because some times i have had odd buggy behavior when I use local scope records... but when I use a global scope one it is okay..

If this is some bug or screwy code of mine I want to find out and solve this.

Reply by email

L
to L
Show quoted text 7 lines
Florian wrote.. > Records and objects containing automated fields are initialized? Or do I > miss something? Oh...? This is something I have never been clear about :-(

p.s. see also:

http://community.freepascal.org:10000/bboards/message?message_id=223327&forum_id=24082

So. let's clear up the confusion for good..

Ansistrings are initialized in the record?
But integers too?

Just ansistrings but not integers?

Then, I will write a clear article explaining it all for everyone to reference ;-)

Reply by email

L
to L

I think confusion was created also because that guys blog post only had a record with one field in it (a string).. he should have used more fields with integers, pointers, etc to demonstrate a point more.

Reply by email

Jonas Maebe
to L: One thing to ponder about: A class inside a record... trecord = record something:…
Show quoted text 10 lines
One thing to ponder about: A class inside a record... trecord = record something: TSomeClass; int: integer; //... etc end; My brain hurts.

A class field is just a pointer. Since classes are not reference counted, nothing special is done for record fields which are classes.

This will cause issues with a Fillchar for the class, or not?

No.

The idea is.. I want to create/ponder about a "standardized" way to init ANY sort of record because a lot of silly bugs in pascal are because of these uninitialized local scope records, or similar non initialized things.

If you have local record which was declared but not yet used, a simple fillchar(rec,sizeof(rec),0) will set everything to 0/nil/empty. If it may have been used earlier and contains refcounted fields, you first have to call finalize(rec).

Or you can let the compiler decide whether or not finalize() is required by using a wrapper with an out-parameter like the blog guy did.

Jonas

Reply by email

L
to L: I think confusion was created also because that guys blog post only had a record with one…

One thing to ponder about:

A class inside a record...
trecord = record
  something: TSomeClass;
  int: integer;
  //... etc
end;

My brain hurts.

This will cause issues with a Fillchar for the class, or not?

I wouldn't use this normally (a class inside a record), but it is still interesting to think about.. for a standardized initialization system for records..

The idea is.. I want to create/ponder about a "standardized" way to init ANY sort of record because a lot of silly bugs in pascal are because of these uninitialized local scope records, or similar non initialized things.

We need to improve safety of our programs through automated methods..we aren't programming in C!

(I recently noticed the compiler has some detection switch for uninitialized variables and have yet to try it.. sounds like a cool testing ability)

It is nice to have the performance benefit of non initialized records *but* at the same time it is nice to use SAFE features explicitely if we can.

I am *all for* an "autoinit" record switch feature, but then this breaks compatibility with delphi if such a feature is thought up. Maybe I suggest it in the "Delphi Wikia" website too just as useful pondering if anything.

procedure test;
var rec: AnyRecEvenWithInts AUTOINIT;
begin
end;

Are there are issues to think about if the classes are stored inside that record ? That may mean it is not such an easy feature to implement... or is it?

In the mean time, I will experiment with the fillchar/finalize tricks with "simple" records containing ansistrings and integers and such things. I didn't really have sincerity about it, or a correct standardized way to do it, until discussing on this list regarding finalize() and such things. Honestly, I didn't even know much about fillchar due to my lack of "turbopascal record" experience. I've always been manually initializing my records and a pain in the butt that is.

Reply by email

Jonas Maebe
to Jilani Khaldi
Jilani Khaldi wrote 5 lines
Jilani Khaldi wrote: > Which is better for my web application? > http://www.dotpas/org/cgi-bin/articles/a01 Soory, the URL is: http://www.dotpas.org/cgi-bin/articles/a01

I guess the main problem is that you are writing Pascal in a way which is very suited for a functional language (like Erlang), but which is extremely inefficient when used in an imperative language like Pascal (or C, C++, Java, ...).

Anyway, I don't think such posts are very much suited to this list (unless the idea is to instigate endless discussions about "which language is best"), so I'd prefer it if you could take this to the fpc- other list.

Thanks.

Jonas

Reply by email

Jonas Maebe
to L
Show quoted text 9 lines
So.. now I ask.. type something = class s: ansistring; int:integer end; Is "int" set to zero when it is a local scope var in a procedure created on the heap with Create()?

New class instances are always automatically filled with zeroes upon creation.

Jonas

Reply by email

Jonas Maebe
to L: What about old borland objects (heap and stack initialization) process? I am guessing…
What about old borland objects (heap and stack initialization) process? I am guessing they are more like records...

They are exactly like records.

or do heap objects act like classes in that they are filled with zeros?

Unlike classes, objects have no hidden dereferencing or whatever and follow exactly the same semantics as other types regardless of whether they are on the stack or on the heap.

p.s. I think the inconsistent behavior between local scope records and global scope records is kind of a flaw/danger in modern pascal.. as the bugs may not be caught until someone builds a program with local scope var..

Using uninitialised variables is virtually always bad, regardless of the scope. And the fact that global variables are zeroed at the program start is afaik not defined by the Pascal standard. It's just a side effect of the way most operating systems work.

Jonas

Reply by email

L
to L: Recently we discussed records and how to initialize them.. Jonas cleared up a lot for me…

What about old borland objects (heap and stack initialization) process?

I am guessing they are more like records... or do heap objects act like classes in that they are filled with zeros?

p.s. I think the inconsistent behavior between local scope records and global scope records is kind of a flaw/danger in modern pascal.. as the bugs may not be caught until someone builds a program with local scope var.. and for eg. many demonstrations are built in simple global console programs as test cases. Nowadays I always (try to) build things inside a procedure in a test case to ensure local scope is being used. But as humans make mistakes, again I think this part of modern pascal can be improved and we should push to the language less dangerous by default.

Reply by email

M Pulis
to Jonas Maebe: They are exactly like records. Unlike classes, objects have no hidden dereferencing or…
Show quoted text 11 lines
> p.s. I think the inconsistent behavior between local scope records > and global scope records is kind of a flaw/danger in modern > pascal.. as the bugs may not be caught until someone builds a > program with local scope var.. Using uninitialised variables is virtually always bad, regardless of the scope. And the fact that global variables are zeroed at the program start is afaik not defined by the Pascal standard. It's just a side effect of the way most operating systems work.

Affirmative.

Pascal does not define any variable initialization itself - one should always init all Pascal vars of any type. Doing so is an excellent coding habit also portable to any other language/OS - protects against low-level implementation changes.

I never trust a side effect I didn't code myself..... 8-))

Gary

Reply by email

Jonas Maebe
to L: program test1; type trec = record i: integer; end; tclass = class i: integer; end; tobj =…
Show quoted text 6 lines
Not a fool proof test since random values have a chance of being zero, but it basically shows: 1. global old heap object NOT zeroed 2. local old heap object NOT zeroed 3. local class zeroed 4. global class zeroed

The above terminology is wrong. Given your example

procedure show;
var rec: trec; c: tclass; o: tobj; po: pobj; begin ...

What's on the stack is c (i.e., a pointer to a tclass instance) and po (a pointer to a tobj instance). Neither c nor po is automatically initialised with any value. Completely orthogonal to that is whether class instances or objects are initialised. As mentioned before, class instances are filled with zero. Object instances are just like any other data, so only fields of reference-counted types are initialised by the compiler.

The class and object constructors have no clue where the actual instance is located (stack, heap, shared memory, ...) nor where the pointer to the instance (if any) will be stored, so that does have any influence on their behaviour.

Jonas

Reply by email

Joao Morais
to Jonas Maebe: They are exactly like records. Unlike classes, objects have no hidden dereferencing or…
Jonas Maebe wrote
Using uninitialised variables is virtually always bad, regardless of the scope. And the fact that global variables are zeroed at the program start is afaik not defined by the Pascal standard. It's just a side effect of the way most operating systems work.

I think I didn't get your point. What about this piece of code:

interface
function foo: tfoo;
implementation
var
   _foo: tfoo;
function foo: tfoo;
begin
   if not assigned(_foo) then
     _foo := tfoo.create;
   result := _foo;
end;

Is it safe?

Joao Morais

Reply by email

Jonas Maebe
to Joao Morais
Joao Morais wrote 25 lines
Jonas Maebe wrote: > Using uninitialised variables is virtually always bad, regardless > of the scope. And the fact that global variables are zeroed at the > program start is afaik not defined by the Pascal standard. It's > just a side effect of the way most operating systems work. I think I didn't get your point. What about this piece of code: interface function foo: tfoo; implementation var _foo: tfoo; function foo: tfoo; begin if not assigned(_foo) then _foo := tfoo.create; result := _foo; end; Is it safe?

It is safe on all currently supported targets (and we even go out of our way to ensure that it keeps working if global variables are turned into register variables), but it's still bad practice (and could in principle break one day, although it's unlikely given the backwards compatibility headaches that would cause).

Jonas

Reply by email

L
to L: What about old borland objects (heap and stack initialization) process? I am guessing…
What about old borland objects (heap and stack initialization) process?
program test1;
type
  trec = record i: integer; end;
  tclass = class i: integer; end;
  tobj = object i: integer; end;
  pobj = ^Tobj;
procedure show;
var rec: trec; c: tclass; o: tobj; po: pobj;
begin
  writeln('Record local:', rec.i);
  c:= tclass.create;
  new(po);
  writeln('Class local:', c.i);
  writeln('Stack Object local:', o.i);
  writeln('Heap Object local:', po^.i);
  c.free; c:= nil;
  dispose(po);
end;
var rec: trec; c: tclass; o: tobj; po: pobj;
begin
  show;
  writeln('Record global:', rec.i);
  c:= tclass.create;
  new(po);
  writeln('Class global:', c.i);
  writeln('Stack Object global:', o.i);
  writeln('Heap Object global:', po^.i);
  c.free; c:= nil;
  dispose(po);
  readln;
end.

Not a fool proof test since random values have a chance of being zero, but it basically shows:
1. global old heap object NOT zeroed
2. local old heap object NOT zeroed
3. local class zeroed
4. global class zeroed
5. global old stack object zeroed
6. local old stack object NOT zeroed
7. global stack record zeroed
8. local stack record NOT zeroed.

I didn't bother with heap records but we can see what will happen

L505

Reply by email

L
to L
Show quoted text 5 lines
Using uninitialised variables is virtually always bad, regardless of the scope. And the fact that global variables are zeroed at the program start is afaik not defined by the Pascal standard. It's just a side effect of the way most operating systems work.

I think something like:

procedure test;
var blah: integer = 0;
begin
end;

Is useful.. i.e. initialized variables that are done on the spot.

And similarily a record could be:

procedure test;
var blah: TRec autoinit;
begin
end;

This would allow safe programming without compromising backwards compatibility.

But... in the mean time.. a solution is to make a standard record init procedure and do it like:

procedure test;
var blah: TRec;
begin
  init(blah);
end;

Which will be what I use for now...

And always do this by habit for safety now that I know this trick of the fillchar and such - only ever avoiding it when needing speed (but that is premature optimization).

I realize that local scope uninitialized vars are the way systems work according to the system.. but we are humans and error prone humans...We can make languages safer I think and more consistent and human friendly at a higher level. Humans just make so many mistakes even though systems are supposed to work they way they are.

i.e. really it is just a convenience and a "standard good practice" being now recommended right within the programming language...and more safety as an option. Just as I am also a fan of reference counted ansistrings versus using less safe pchars.. etc.

Reply by email

L
to L
Show quoted text 10 lines
I think something like: procedure test; var blah: integer = 0; begin end; Is useful.. i.e. initialized variables that are done on the spot.

To expand on this.. not only local scope vars, but global..

var
  global: integer = 0;

I agree is much clearer than leaving it to the assumption:

// this will be zero.. bad assumption
var
  global: integer;
Show quoted text 7 lines
And similarily a record could be: procedure test; var blah: TRec autoinit; begin end;

This would be a good global habit to get into also for globals:

var
  global: Trec autoinit;

or

var
  global: Trec;
begin
  init(global)
end;

The problem with the above is that sometimes the global is further away in your code than you eyes can see, hence the inline declaring of initialization "right while you are at it" is safer for humans.

Relying on global variables being zero is bad, I agree.. and they should be iniitalized by habit.. too. Especially when one copies global code into local code does a problem exist, if one made the assumption of the globals being initialized then (which may have been true, but now that they are no longer globals... problem time).

Reply by email

L
to L: To expand on this.. not only local scope vars, but global.. var global: integer = 0; I…

Joao Morais replied to Jonas with:

Show quoted text 19 lines
I think I didn't get your point. What about this piece of code: interface function foo: tfoo; implementation var _foo: tfoo; function foo: tfoo; begin if not assigned(_foo) then _foo := tfoo.create; result := _foo; end; Is it safe?

What about this:

var
  _foo: tfoo = nil;

That way you declare it right there and then.. ensuring it is not assigned.

Hence why I think a good human practice is to always init everything even if it psychologically affects some people in ways such as "will this slow the program down though? Do I need to init this stuff if I am going to init some of it later"? which is evil premature optimization that causes bugs.

L505

Reply by email

L
to L: Recently we discussed records and how to initialize them.. Jonas cleared up a lot for me…
Pascal does not define any variable initialization itself - one should always init all Pascal vars of any type. Doing so is an excellent

coding > habit also portable to any other language/OS - protects against

low-level implementation changes. I never trust a side effect I didn't code myself..... 8-))

We have to stop thinking in standard pascal and think about safety and ways to automate safety in a human matter. We are not computers, we are humans. You can claim all you want that you will ALWAYS init all your pascal vars... but you are a human and you will not *always* init all your pascal vars. This is the reason features like this have been available:

var i: integer = 0; // handy
procedure test;
var i: integer = 0; // handy
begin
end;

If you accidentally delete the init code and forget to put it back, the above way is safer. If you accidently init something in a dangerous way such as using FillChar on old code that now no longer works with the newer automated types.. again this is dangerous. It may be "pascalish" to continue to use hacks like FillChar and init() code far away from the declaration (especially in globals).. but this is the same as a C programmer saying that ansistrings are not C ish so we should use pchars all the time?

Let's please stop the pascal fanboyism and consider humans, and safety.

Even Wirth has moved away from pascal greatly if you study his languages Oberon, Modula, and a derived ComponentPascal.

L505

Reply by email