Sign in Join

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

Mailing lists / fpc-pascal / 2008-01

class constants

32 messages · 14 people · –

Reply by email Subscribe to this list Your subscription

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

Jonathan Benedicto

Hello,

Does FPC support class constants, and if it doesn't, are there any plans to add this support?

Example:
type
  TMyClass = class
    begin
      private
        const MyConst = '123';
    end;

Jon

Cox, Stuart TRAN:EX
to Jonathan Benedicto

Have a look at http://delphi.about.com/library/weekly/aa031505a.htm as a (not too bad) way to do it in Delphi. FPC too?

Stu Cox
Project Management Technician
Southern Interior Region
Ministry of Transportation
342-447 Columbia St.,
Kamloops, BC V2C 2T3
p: 250-828-4320
f: 250-828-4229

Earlier message 24 lines
-----Original Message----- From: On Behalf Of Jonathan Benedicto Sent: Wednesday, January 23, 2008 11:26 AM To: FPC-Pascal Subject: [fpc-pascal] class constants Hello, Does FPC support class constants, and if it doesn't, are there any plans to add this support? Example: type TMyClass = class begin private const MyConst = '123'; end; Jon
Leonardo M. Ram�
to Jonathan Benedicto: Does FPC support class constants, and if it doesn't, are there any plans to add this…

Jonathan,
I never needed such type of feature, a propossed solution is to create one unit per class, and declare your constants in the implementation section of each unit.

Example:

unit People

interface
type
  TPeople = class
  ..
  end;
implementation
const
   name = 'default name';

...

end.
--- Jonathan Benedicto wrote 20 lines
Hello, Does FPC support class constants, and if it doesn't, are there any plans to add this support? Example: type TMyClass = class begin private const MyConst = '123'; end; Jon _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal

____________________________________________________________________________________ Be a better friend, newshound, and
know-it-all with Yahoo! Mobile. Try it now. http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ

Joao Morais
to Leonardo M. Ram�: I never needed such type of feature, a propossed solution is to create one unit per…
Leonardo M. Ramé wrote
Jonathan, I never needed such type of feature, a propossed solution is to create one unit per class, and declare your constants in the implementation section of each unit.

A class function would be a better approach.

Show quoted text 39 lines
Example: unit People interface type TPeople = class .. end; implementation const name = 'default name'; ... end. --- Jonathan Benedicto wrote: > Hello, > > Does FPC support class constants, and if it doesn't, are there any plans to > add this support? > > Example: > type > TMyClass = class > begin > private > const MyConst = '123'; > > end; > > Jon >
Joao Morais
to Leonardo M. Ram�
Leonardo M. Ramé wrote
With your response I assume he meant something like "static attributes" when he said "class constants".

Yup. A class variable is another matter, which afaik cannot be reached with one class per unit approach.

Show quoted text 6 lines
--- Joao Morais wrote: > A class function would be a better approach. > >
Jonathan Benedicto
to Marco van de Voort: Have a look at http://www.freepascal.org/faq.var#extensionselect The question would be…
Marco van de Voort wrote 8 lines
> > Does FPC support class constants, and if it doesn't, are there any plans > to add this support? Have a look at http://www.freepascal.org/faq.var#extensionselect The question would be "what would make this possible?"

Hi Marco,

I'm not sure what you mean - do you mean would I be willing to write the support myself?

Jon

Henry Vermaak
to Jonathan Benedicto
Jonathan Benedicto wrote
I'm not sure what you mean - do you mean would I be willing to write the support myself?

i think he's asking what the use of it is. number 2 under the link he gave.

henry

Jonathan Benedicto
to Henry Vermaak
Henry Vermaak wrote 5 lines
> I'm not sure what you mean - do you mean would I be willing to write the > support myself? i think he's asking what the use of it is. number 2 under the link he gave.

Oh, ok. Well, I'll try to summarize:

Class constants add the ability to provide scoped, "namespaced" constants. Although one can handle basic scoping with global constants, by placing them in interface vs implementation, they were not designed to be scope-limited. They also do not provide a way to group several constants under a common name, though one can simulate this functionality using creative constant names.

Some of the benefits of class constants are: 1. They provide object-oriented constants, 2. They simplify coding by saving the developer from having to write long constant names to distinguish global constants from each other.
3. They reduce coding errors due to the ability to only make public what is necessary, keeping what is visible to outside units/classes to a mimimum.

I'm sure that there are other benefits, I just can't think of them off the top of my head.

Personally, the main reason I need them is for compatibility. I have a large Delphi codebase that I'm porting to FPC and it uses class constants all over the code.

Here is an example of their use:

-- Start of Unit1.pas --
unit Unit1;
interface
type
  TTest = class
    private
      const PrivateConst = '1';
    public
      const PublicConst = '1';
      constructor Create;
  end;
implementation
constructor TTest.Create;
var
  Str: String;
begin
  Str := PrivateConst;
  Str := PublicConst;
end;
end.
-- End of Unit1.pas --
-- Start of Unit2.pas --
unit Unit2;
interface
type
  TTest2 = class
      constructor Create;
  end;
implementation
uses
  Unit1;
constructor TTest.Create;
var
  Str: String;
begin
  Str := TTest.PrivateConst; // Will cause compiler error because
PrivateConst is not visible to this class.
  Str := TTest.PublicConst;
end;
end.
-- End of Unit2.pas --

Jon

Marco van de Voort
to Jonathan Benedicto
Show quoted text 10 lines
Henry Vermaak wrote: >> I'm not sure what you mean - do you mean would I be willing to write the >> support myself? > > i think he's asking what the use of it is. number 2 under the link he > gave. Oh, ok. Well, I'll try to summarize: Class constants add the ability to provide scoped, "namespaced" constants.

A constant is already in a scope, the unit.

Show quoted text 5 lines
Although one can handle basic scoping with global constants, by placing them in interface vs implementation, they were not designed to be scope-limited. They also do not provide a way to group several constants under a common name, though one can simulate this functionality using creative constant names.

Stuff them in one unit. unitname.constant.

Some of the benefits of class constants are: 1. They provide object-oriented constants,

That's a description, not a benefit. Taste matters are difficult to measure.

2. They simplify coding by saving the developer from having to write long constant names to distinguish global constants from each other. 3. They reduce coding errors due to the ability to only make public what is necessary, keeping what is visible to outside units/classes to a mimimum.

Units/move them to implementation. The chance that random classes in the same unit clash is negliable.

Personally, the main reason I need them is for compatibility. I have a large Delphi codebase that I'm porting to FPC and it uses class constants all over the code.

IMHO that is the only decent reason. Technically IMHO it doesnt make much sense, it's just a dotnetism, copying blindly from a different world to make nice feature butlletlists.

And like the rest of the dotnetims, they are relatively little used, probably mostly out D7- compat reasons. And thus they are waiting for an implementor. I'm not aware of work being done on any of them (though I have a vaguely recollection that the strict private and protected exist, but I'm not sure if in fully compat form).

Besides implementing, making a good study of what they _EXACTLY_ do, and a bunch of testcases/unittests could really further the cause also.

Jonas Maebe
to Marco van de Voort
Marco van de Voort wrote 15 lines
> Henry Vermaak wrote: >>> I'm not sure what you mean - do you mean would I be willing to >>> write the >>> support myself? >> >> i think he's asking what the use of it is. number 2 under the >> link he >> gave. > > Oh, ok. Well, I'll try to summarize: > > Class constants add the ability to provide scoped, "namespaced" > constants. A constant is already in a scope, the unit.

So are constants local to a function. Being able to restrict the scope to a certain function or group of functions is nevertheless useful.

Jonas

Marco van de Voort
to Jonas Maebe
Show quoted text 8 lines
On 24 Jan 2008, at 19:45, Marco van de Voort wrote: >> constants. > > A constant is already in a scope, the unit. So are constants local to a function. Being able to restrict the scope to a certain function or group of functions is nevertheless useful.

To be honest, if we wouldn't be able to do that now, and a request for implementation came, my answer would be pretty much the same.

Jonas Maebe
to Marco van de Voort
Marco van de Voort wrote 11 lines
> On 24 Jan 2008, at 19:45, Marco van de Voort wrote: > > >> A constant is already in a scope, the unit. > > So are constants local to a function. Being able to restrict the > scope to a certain function or group of functions is nevertheless > useful. To be honest, if we wouldn't be able to do that now, and a request for implementation came, my answer would be pretty much the same.

I strongly disagree with that answer to those points.

Jonas

Felipe Monteiro de Carvalho
to Anthony W.Henry
Anthony W.Henry wrote
Suggestion: Perhaps this is worthy of a News item on the FreePascal Web Page.

Better wait until it's ready.

Felipe Monteiro de Carvalho
Marc Weustink
to Marco van de Voort: Same answer.
Marco van de Voort wrote 10 lines
> Marco van de Voort wrote: >>> Does FPC support class constants, and if it doesn't, are there any plans >>> to add this support? >> Have a look at >> http://www.freepascal.org/faq.var#extensionselect >> >> The question would be "what would make this possible?" > What about class vars? Same answer.

Some form of classvars would make it possible to do something I do in
1) the Lazarus LCLComponent to set a class variable. (now I'm forced to do that on every instance of that class or a derived class).
2) Store debugger configuration like is done for lazarus debuggers. (now I store a seprate config instance in a stringlist based on the debuggerclassname)
3) there was another case, but I don't recall it atm.

Anyway I worked my way around it, but classvars would have made this easier. I do realize that providing patches is the best way to get something implemented, but since my workarounds, there is no big need anymore.

Marc

Peter Vreman
Show quoted text 24 lines
Marco van de Voort wrote: >> Marco van de Voort wrote: >>>> Does FPC support class constants, and if it doesn't, are there any plans >>>> to add this support? >>> Have a look at >>> http://www.freepascal.org/faq.var#extensionselect >>> >>> The question would be "what would make this possible?" >> What about class vars? > > Same answer. Some form of classvars would make it possible to do something I do in 1) the Lazarus LCLComponent to set a class variable. (now I'm forced to do that on every instance of that class or a derived class). 2) Store debugger configuration like is done for lazarus debuggers. (now I store a seprate config instance in a stringlist based on the debuggerclassname) 3) there was another case, but I don't recall it atm. Anyway I worked my way around it, but classvars would have made this easier. I do realize that providing patches is the best way to get something implemented, but since my workarounds, there is no big need anymore.

There is already support for static field in objects and classes. These act like globals, but scope is limited to the object/class.

Jonathan Benedicto
to Marco van de Voort: A constant is already in a scope, the unit. Stuff them in one unit. unitname.constant.…

Marco van de Voort:

> Class constants add the ability to provide scoped, "namespaced" > constants. A constant is already in a scope, the unit.

The unit scope is a very open scope. Via class constants, one gets private, protected and public scoping for constants, all of which are essential scope levels for OOP.

Show quoted text 9 lines
> Although one can handle basic scoping with global constants, by placing > them > in interface vs implementation, they were not designed to be > scope-limited. > They also do not provide a way to group several constants under a common > name, though one can simulate this functionality using creative constant > names. Stuff them in one unit. unitname.constant.

1 unit for every unique constant prefix is asking a lot. Some applications have many (>100) different constant prefixes.

Show quoted text 6 lines
> Some of the benefits of class constants are: 1. They provide > object-oriented > constants, That's a description, not a benefit. Taste matters are difficult to measure.

Constants are not OOP, adding class constants provides OOP constants.

Show quoted text 6 lines
> 3. They reduce coding errors due to the ability to only make public what > is > necessary, keeping what is visible to outside units/classes to a mimimum. Units/move them to implementation. The chance that random classes in the same unit clash is negliable.

What if the developer wishes to provider the ability to override their class, and allow access to the constants from descendant classes? The constants inside the implementation section are invisible to descendant classes in other units. Class constants provide protected-level scoping

Show quoted text 21 lines
> Personally, the main reason I need them is for compatibility. I have a > large > Delphi codebase that I'm porting to FPC and it uses class constants all > over > the code. IMHO that is the only decent reason. Technically IMHO it doesnt make much sense, it's just a dotnetism, copying blindly from a different world to make nice feature butlletlists. And like the rest of the dotnetims, they are relatively little used, probably mostly out D7- compat reasons. And thus they are waiting for an implementor. I'm not aware of work being done on any of them (though I have a vaguely recollection that the strict private and protected exist, but I'm not sure if in fully compat form). Besides implementing, making a good study of what they _EXACTLY_ do, and a bunch of testcases/unittests could really further the cause also.

Thanks for the info.

Jon

Vinzent Hoefler
to Marco van de Voort: To be honest, if we wouldn't be able to do that now, and a request for implementation…
Marco van de Voort wrote 11 lines
> On 24 Jan 2008, at 19:45, Marco van de Voort wrote: > >> constants. > > > > A constant is already in a scope, the unit. > > So are constants local to a function. Being able to restrict the > scope to a certain function or group of functions is nevertheless > useful. To be honest, if we wouldn't be able to do that now, and a request for implementation came, my answer would be pretty much the same.

Oh, well. That would make my logging much harder.

|unit
| Foo;
|
| ...
|
|const
| MODULE_PREFIX = 'Foo.';
|
|procedure Foobar;
|const
| PROC_PREFIX = MODULE_PREFIX + 'Foobar';
|begin
| ...

I would have to declare a different name for each subroutine and they wouldn't have the local scope (in case the subroutine gets refactored, the log name should also be changed).

Names of nested subroutines would be almost impossible to maintain.

Of course, this is of no practical use. It's just in about 70K lines of code of a real world project. Yes, I'm being a bit cynic here.

Regarding class constants: I missed them, too, already, although not too much. ;)

Vinzent.

Peter Vreman
Regarding class constants: I missed them, too, already, although not too much. ;)

Maybe you should read the documentation. Static fields are supported already for 10 years:

~/fpc/compiler>>> cat p.pp
{$mode objfpc}
{$static on}
type
  cl=class
    l : longint;static;
  end;
var
  c1,c2 : cl;
begin
  c1:=cl.create;
  c2:=cl.create;
  c1.l:=2;
  writeln(c2.l);
  c2.l:=3;
  writeln(c1.l);
end.

~/fpc/compiler>>> ./p
2
3

~/fpc/compiler>>>

Vinzent Hoefler
to Peter Vreman
Peter Vreman wrote 29 lines
> Regarding class constants: I missed them, too, already, although > not too much. ;) Maybe you should read the documentation. Static fields are supported already for 10 years: ~/fpc/compiler>>> cat p.pp {$mode objfpc} {$static on} type cl=class l : longint;static; end; var c1,c2 : cl; begin c1:=cl.create; c2:=cl.create; c1.l:=2; writeln(c2.l); c2.l:=3; writeln(c1.l); end. ~/fpc/compiler>>> ./p 2 3 ~/fpc/compiler>>>

Well, once upon a time I learned that there's a difference between a variable and a constant, but ok; Borland might have changed that a bit when they introduced the notion of a "typed constant". ;)

More interesting here is that not only "c1.L" and "c2.L" works, but you can even access the variable without an instance at all: "cl.L", just like it should. So at least there are class variables.

(It might prove a bit tricky to correctly initialize them, though. AFAICS you can't give them initial values, can you? So to be on the safe side, you're probably back to doing it in the initialization section of the unit where the class is declared. This is a bit nasty.)

Still, something like

|cl =
|class
|   const VersionId = '1.3.9a';
|end;

seems not possible. Of course, this is easily modeled by a simple class method returning a constant value. That's why I said, I didn't miss that feature "too much".

Vinzent.

David Emerson
to Anthony W.Henry: I don't mean to step on Jeff Duntemann's toes but it looks like he is going to release…

Hi all,

I'm pretty new to both "open arrays" and OOP, and am feeling a bit concerned about memory management and leaks in my code. I will jump straight into examples and questions:

type
   T_my_object = object (TObject)
      {...}
   end;
   T_my_class = class (TComponent)
      {...}
   end;
type
   str_array_type = array of ansistring;
   int_array_type = array of integer;
   obj_array_type = array of T_my_object;
   cls_array_type = array of T_my_class;
var
   str_arr : str_array_type;
   int_arr : int_array_type;
   obj_arr : obj_array_type;
   cls_arr : cls_array_type;
begin
   {...}
   setlength(str_arr, some_maximum);
   setlength(int_arr, some_maximum);
   setlength(obj_arr, some_maximum);
   setlength(cls_arr, some_maximum);
   {...}

First: what does setlength do about initialization? There are a couple different cases here...

1. If the setlength function is creating an array of things which happen to be stored as pointers (ansistrings in str_arr or class instances in cls_arr) then will the pointers be initialized to nil by setlength? Or do I need to manually initialize all pointers to nil, after calling setlength? (I guess for ansistrings that would require using fillchar ... but maybe setlength is already doing this?)

2. Of course the primary concern is cleaning up. For the ansistring case, can I simply call:

   setlength (str_arr, 0);

...and expect that the ansistring references will be properly decremented and cleaned up?
Or do I need to explicitly clear them myself?

   for i := 0 to high(str_arr) do str_arr[i] := '';
   setlength(str_arr, 0);

3. Similarly for the cls_arr, do I need to explicitly call the destructor?

   for i := 0 to high(cls_arr) do
      if cls_arr[i]  nil then cls_arr[i].Destroy;
   setlength(cls_arr, 0);

...or will setlength call the destructor when the array is shrunk? (Assumably only for non-nil pointers :)

As for the other types... for int_arr it must be a non-issue, and for obj_arr ... objects DO need to be destroyed! Although this is only a matter of curiousity, since I'm not using any objects that aren't classes

And of course the "array in array" example comes to mind:

var
   str_arr_arr : array of str_arr;
begin
   setlength (str_arr_arr, 5);
   setlength (str_arr_arr[3], 17);
   {...}
   // is it necessary to free all of the members as seen below?
   for i := 0 to high(str_arr_arr) do setlength (str_arr_arr[i], 0);
   // or will setlength silently do the job anyway?
   setlength (str_arr_arr, 0);

Conversely, do open arrays get automatically cleaned up as part of an object destruction, or do I need to write that into the destructor?

type
   T_my_other_class = class (TComponent)
      private
         str_arr : str_array_type;
         int_arr : int_array_type;
         cls_arr : cls_array_type;
      public
         constructor Create (my_owner : TComponent; pass_size :
integer); override;
         destructor Destroy;
      end;
constructor T_my_other_class.Create (my_owner : TComponent; pass_size :
integer);
   begin
      inherited Create (my_owner);
      setlength (str_arr, pass_size);
      setlength (int_arr, pass_size);
   end;
destructor T_my_other_class.Destroy;
   begin
      for i := 0 to high(str_arr) do str_arr[i] := '';   // again :)
      setlength (str_arr, 0);
      setlength (int_arr, 0);
      // and what about cls_arr, even more messy of course :)
      inherited Destroy;
   end;

4. Is the above destructor actually doing anything that doesn't happen automatically?

And the last case, objects embedded in objects:

type
   T_my_third_class = class (TComponent)
      embedded_cls : T_my_other_class;
      bool_arr : bool_array_type;
      {...}
   end;

5. Do I need to override the destructor with one that explicitly calls embedded_cls.Destroy?

Of course, I didn't ask until I was already knee-deep in several layers of this stuff...

type
   third_class_array_type = array of T_my_third_class;
   T_group_array = class(TComponent)
      third_arr : third_class_array_type
      {...}
   end;
var
   g_arr : array of T_group_array;

... and so on. Actually, I think that's as many layers as I've got! whew.

Happily the program runs! I am doing a lot of this cleanup manually, though, and am now wondering if I should cut some of my cleanup code out as extraneous, or if I rather need to triple-check it and perhaps reinforce it with yet more cleanup code.

Thanks!

~David.

Joost van der Sluis
to David Emerson

Op zaterdag 21-06-2008 om 19:23 uur [tijdzone -0700], schreef David Emerson:

I'm pretty new to both "open arrays" and OOP, and am feeling a bit concerned about memory management and leaks in my code. I will jump straight into examples and questions:

I think you can find all this in the documentation, or elsewhere on the web. (Maybe search for Delphi, instead fpc)

Show quoted text 40 lines
type T_my_object = object (TObject) {...} end; T_my_class = class (TComponent) {...} end; type str_array_type = array of ansistring; int_array_type = array of integer; obj_array_type = array of T_my_object; cls_array_type = array of T_my_class; var str_arr : str_array_type; int_arr : int_array_type; obj_arr : obj_array_type; cls_arr : cls_array_type; begin {...} setlength(str_arr, some_maximum); setlength(int_arr, some_maximum); setlength(obj_arr, some_maximum); setlength(cls_arr, some_maximum); {...} First: what does setlength do about initialization? There are a couple different cases here... 1. If the setlength function is creating an array of things which happen to be stored as pointers (ansistrings in str_arr or class instances in cls_arr) then will the pointers be initialized to nil by setlength? Or do I need to manually initialize all pointers to nil, after calling setlength? (I guess for ansistrings that would require using fillchar ... but maybe setlength is already doing this?)

After calling setlength, the items in the array are not initialised.

Note that in the pascal language allocated memory is never initialised/set to 0. The only exceptions are the variables in classes. (There are some functions that allocate memory and initialise is afterwards explicitely, see the documentation)

Initialising the strings you can do by setting them to an empty string.
(:= '')
Show quoted text 7 lines
2. Of course the primary concern is cleaning up. For the ansistring case, can I simply call: setlength (str_arr, 0); ...and expect that the ansistring references will be properly decremented and cleaned up?

You can expect this, but I woudn't know.

Or do I need to explicitly clear them myself? for i := 0 to high(str_arr) do str_arr[i] := ''; setlength(str_arr, 0);

Better save then sorry? You can also try this yourself: write a small console test program, and compile it with the -Gh compiler option and run it. It will show you if there are any memory-leaks.

Show quoted text 6 lines
3. Similarly for the cls_arr, do I need to explicitly call the destructor? for i := 0 to high(cls_arr) do if cls_arr[i] nil then cls_arr[i].Destroy; setlength(cls_arr, 0);

Yup, it's pretty consistent.

As for the other types... for int_arr it must be a non-issue, and for obj_arr ... objects DO need to be destroyed! Although this is only a matter of curiousity, since I'm not using any objects that aren't classes

Also here you have to destroy all the objects.

Show quoted text 9 lines
And of course the "array in array" example comes to mind: var str_arr_arr : array of str_arr; begin setlength (str_arr_arr, 5); setlength (str_arr_arr[3], 17); {...} // is it necessary to free all of the members as seen below?

Yes

for i := 0 to high(str_arr_arr) do setlength (str_arr_arr[i], 0); // or will setlength silently do the job anyway?

No

setlength (str_arr_arr, 0); Conversely, do open arrays get automatically cleaned up as part of an object destruction, or do I need to write that into the destructor?

Yes they are. But you have to take care of the objects in the array, offcourse. (as explained above)

Show quoted text 32 lines
type T_my_other_class = class (TComponent) private str_arr : str_array_type; int_arr : int_array_type; cls_arr : cls_array_type; public constructor Create (my_owner : TComponent; pass_size : integer); override; destructor Destroy; end; constructor T_my_other_class.Create (my_owner : TComponent; pass_size : integer); begin inherited Create (my_owner); setlength (str_arr, pass_size); setlength (int_arr, pass_size); end; destructor T_my_other_class.Destroy; begin for i := 0 to high(str_arr) do str_arr[i] := ''; // again :) setlength (str_arr, 0); setlength (int_arr, 0); // and what about cls_arr, even more messy of course :) inherited Destroy; end; 4. Is the above destructor actually doing anything that doesn't happen automatically?

The setlengths to 0 aren't needed.

Show quoted text 12 lines
And the last case, objects embedded in objects: type T_my_third_class = class (TComponent) embedded_cls : T_my_other_class; bool_arr : bool_array_type; {...} end; 5. Do I need to override the destructor with one that explicitly calls embedded_cls.Destroy?

Not if you do not have a create that creates embedded_cls. But normally: yes.

Joost.

David Emerson
to Joost van der Sluis

Thanks, Joost, for all of your answers! It looks like I need to write *more* cleanup code, and double-check it all.

One question remains:

Show quoted text 6 lines
After calling setlength, the items in the array are not initialised. [...] Initialising the strings you can do by setting them to an empty string. (s := '')

I had the impression that an ansistring is essentially a special kind of pointer. Since the *pointer* contains random (not nil) data, then ... if I assign it to empty-string, wouldn't fpc treat the old random pointer reference as an ansistring that needs to have its reference count decremented?

For this reason, I have previously used fillchar to nil those out.

Thanks,
David

Jonas Maebe
to Joost van der Sluis: Op zaterdag 21-06-2008 om 19:23 uur [tijdzone -0700], schreef David Emerson: I think you…
Joost van der Sluis wrote 14 lines
Op zaterdag 21-06-2008 om 19:23 uur [tijdzone -0700], schreef David Emerson: > 1. If the setlength function is creating an array of things which > happen > to be stored as pointers (ansistrings in str_arr or class instances > in > cls_arr) then will the pointers be initialized to nil by setlength? > Or > do I need to manually initialize all pointers to nil, after calling > setlength? (I guess for ansistrings that would require using > fillchar ... but maybe setlength is already doing this?) After calling setlength, the items in the array are not initialised.

That's incorrect, the array is set to 0. Also, note: this discussion is about dynamic arrays, not about open arrays. These are two completely different beasts.

Show quoted text 5 lines
Note that in the pascal language allocated memory is never initialised/set to 0. The only exceptions are the variables in classes. (There are some functions that allocate memory and initialise is afterwards explicitely, see the documentation)

And except in cases when you work with reference counted types (such as ansistrings and the dynamic arrays themselves (i.e., the pointers to the dynamic arrays)). And contents of dynamic arrays (regardless of the element type) are also an exception.

Initialising the strings you can do by setting them to an empty string. (:= '')

Ansistrings never need to be explicitly initialised to '', that's their default value.

Show quoted text 9 lines
> 2. Of course the primary concern is cleaning up. For the ansistring > case, can I simply call: > > setlength (str_arr, 0); > > ...and expect that the ansistring references will be properly > decremented and cleaned up? You can expect this, but I woudn't know.

It does clean up everything (and this is guaranteed).

Show quoted text 8 lines
> 3. Similarly for the cls_arr, do I need to explicitly call the > destructor? > > for i := 0 to high(cls_arr) do > if cls_arr[i] nil then cls_arr[i].Destroy; > setlength(cls_arr, 0); Yup, it's pretty consistent.

You have to call Free, not Destroy. And in this case you indeed do have to free the instances, because classes are not reference counted (unlike ansistrings) and hence not freed automatically (since you may still have pointers to these references elsewhere).

Show quoted text 16 lines
> And of course the "array in array" example comes to mind: > > var > str_arr_arr : array of str_arr; > begin > setlength (str_arr_arr, 5); > setlength (str_arr_arr[3], 17); > {...} > // is it necessary to free all of the members as seen below? Yes > for i := 0 to high(str_arr_arr) do setlength (str_arr_arr[i], 0); > // or will setlength silently do the job anyway? No

Yes, it will. The reason is that dynamic arrays are reference counted and hence properly finalized to the full extent that is necessary.

Show quoted text 15 lines
> destructor T_my_other_class.Destroy; > begin > for i := 0 to high(str_arr) do str_arr[i] := ''; // again :) > setlength (str_arr, 0); > setlength (int_arr, 0); > // and what about cls_arr, even more messy of course :) > inherited Destroy; > end; > > > 4. Is the above destructor actually doing anything that doesn't > happen > automatically? The setlengths to 0 aren't needed.

Setting the ansistrings to '' isn't either, so it indeed does not do anything that doesn't happen automatically.

Show quoted text 17 lines
> And the last case, objects embedded in objects: > > type > T_my_third_class = class (TComponent) > embedded_cls : T_my_other_class; > bool_arr : bool_array_type; > {...} > end; > > > 5. Do I need to override the destructor with one that explicitly > calls > embedded_cls.Destroy? Not if you do not have a create that creates embedded_cls. But normally: yes.

Correct, except that you have to call .Free rather than .Destroy.

Jonas

David Emerson
to Jonas Maebe

I would post this directly to the bugs database, but I've never received my confirmation email (I've tried a couple times now, perhaps my ISP greylisting is blocking it?)

- If a param is passed-by-reference to a function without being initialized first, a warning is issued by the compiler.

- If the function defines the param as "out" rather than "var" (mode objfpc) then (usually) no such warning is issued.

- If, however, the param passed happens to be an array element, then an errant warning is issued. See the example:

{$mode objfpc}
procedure assign_it (out x : longint);
   begin
      x := 7;
   end;
var
   a : array [0..1] of longint;
   b : longint;
begin
   assign_it (b);   // no warning
   assign_it (a[1]);   // errant warning issued
end.

~David.

Jonas Maebe
to David Emerson
David Emerson wrote 15 lines
{$mode objfpc} procedure assign_it (out x : longint); begin x := 7; end; var a : array [0..1] of longint; b : longint; begin assign_it (b); // no warning assign_it (a[1]); // errant warning issued end.

This bug has already been fixed and the fix will be in the next release.

Jonas

PS: please do not sent new messages to the list by replying to older ones, because it puts your new message in the same thread as the older messages in mail clients which are configured to group threads (because mail clients add a header referring to the message ID of the message you are replying to for exactly this purpose).