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

Mailing lists / fpc-pascal / 2008-01
32 messages · 14 people · –
Reply by email Subscribe to this list Your subscription
Read-only archive. Use j and k to move between messages.
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
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
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.____________________________________________________________________________________ Be a better friend, newshound, and
know-it-all with Yahoo! Mobile. Try it now. http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ
Does FPC support class constants, and if it doesn't, are there any plans to add this…
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?"
I never needed such type of feature, a propossed solution is to create one unit per…
Leonardo M. Ramé wroteJonathan, 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.
With your response I assume he meant something like "static attributes" when he said "class constants".
--- Joao Morais wroteA class function would be a better approach.
____________________________________________________________________________________ Be a better friend, newshound, and
know-it-all with Yahoo! Mobile. Try it now. http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ
Leonardo M. Ramé wroteWith 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.
Have a look at http://www.freepascal.org/faq.var#extensionselect The question would be…
What about class vars?
Same answer.
Have a look at http://www.freepascal.org/faq.var#extensionselect The question would be…
Hi Marco,
I'm not sure what you mean - do you mean would I be willing to write the support myself?
Jon
Jonathan Benedicto wroteI'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
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
A constant is already in a scope, the unit.
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.
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
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
I don't mean to step on Jeff Duntemann's toes but it looks like he is going to release that book.
Read his blog entry for Jan 24th.
http://www.duntemann.com/Diary.htm
Anthony
Suggestion: Perhaps this is worthy of a News item
on the FreePascal Web Page.
Anthony
_______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Anthony W.Henry wroteSuggestion: Perhaps this is worthy of a News item on the FreePascal Web Page.
Better wait until it's ready.
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
There is already support for static field in objects and classes. These act like globals, but scope is limited to the object/class.
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.
1 unit for every unique constant prefix is asking a lot. Some applications have many (>100) different constant prefixes.
Constants are not OOP, adding class constants provides OOP constants.
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
Thanks for the info.
Jon
To be honest, if we wouldn't be able to do that now, and a request for implementation…
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.
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.
I strongly disagree with that answer to those points. Jonas
No surprise there. I know you are a bit more focussed on informationhiding :-)
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.
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)
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.
(:= '')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.
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.
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)
The setlengths to 0 aren't needed.
Not if you do not have a create that creates embedded_cls. But normally: yes.
Joost.
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:
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
Op zaterdag 21-06-2008 om 19:23 uur [tijdzone -0700], schreef David Emerson: I think you…
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.
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.
It does clean up everything (and this is guaranteed).
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).
Yes, it will. The reason is that dynamic arrays are reference counted and hence properly finalized to the full extent that is necessary.
Setting the ansistrings to '' isn't either, so it indeed does not do anything that doesn't happen automatically.
Correct, except that you have to call .Free rather than .Destroy.
Jonas
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.
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).