fLock : Boolean;
....
property Lock : Boolean read fLock write fLock default TRUE;
Now, why does it start off as FALSE? What is the default for?
I don't mind this, but I had to force it TRUE in my create constructor.
Why? Is this only for the Property Editor of the component?
Hector Santos/Santronics
Think of what happens when you FillChar(Rec, SizeOf(Rec), #0) which
contains (at least) a field of boolean. If you recall, False = 0 and True
= 1. When a class gets instantiated all the "fields" are FillChar'd to 0's
and that why this happens. Make sense now?
Hector Santos <hsa...@secured.santronics.com> wrote in article
<9064...@santronics.com>...
>
> I have a published property in my class:
>
>
> fLock : Boolean;
> ....
> property Lock : Boolean read fLock write fLock default TRUE;
>
> Now, why does it start off as FALSE? What is the default for?
Default value (TRUE) not saved in .DFM file .
If Lock <> true ,then Lock --> .DFM
This is all.
>
> I don't mind this, but I had to force it TRUE in my create constructor.
This is true.
cw...@EUNet.yu
This is a common "gotcha" but it is working as designed. You must *always*
set your desired default values in the constructor (if not zero, nil, False,
etc - object instances are cleared when their memory is allocated)
The purpose of the default clause in the property definition is to allow the
class streaming mechanism to decide whether or not it needs to save the
value of this property when the object is written to storage (e.g. when the
IDE saves your form to the .dfm file, this stuff comes into play, but you
can also use it yourself too).
In your example, the Lock property would be written to storage *only* if
Lock was False. You are telling it there is no need to save it if it's True
because upon loading it, your constructor will set it to True anyway. The
purpose of this is to reduce storage space (affects your exe size since DFMs
are stored as RCDATA resources in your exe) and this enhances speed in
storing/loading classes.
--
Wayne Niddery - WinWright Consulting
Delphi, C++Builder, JBuilder, InterDev -- Amazon.com Associate
at http://home.ican.net/~wniddery/RADBooks.html
...remove chaff when replying...
>> property Lock : Boolean read fLock write fLock default TRUE;
>>
>> Now, why does it start off as FALSE? What is the default for?
>> Why? Is this only for the Property Editor of the component?
JM> Think of what happens when you FillChar(Rec, SizeOf(Rec), #0) which
JM> contains (at least) a field of boolean. If you recall, False = 0 and
JM> True = 1. When a class gets instantiated all the "fields" are
JM> FillChar'd to 0's and that why this happens. Make sense now?
Joe, I should of asked:
Whats the purpose of DEFAULT in the property statement?
I found the answer in the on-line help. The DEFAULT value is not used
to initialize the property. Its also is not used to initialized
the property editor field either.
I still don't understand whats it for. I need to re-read the help.
See ya
Hector Santos/Santronics
>>Now, why does it start off as FALSE? What is the default for?
WN> This is a common "gotcha" but it is working as designed.
I can see why its a gotcha. You know some things are just
taken for granted, "Default" is a "default" and since you
can't initialize data in a class as you could with a VAR
or CONST statement, one would think "this" is the mechanism :-)
No doubt. A gotcha <g>
I read the help, but I didn't understand it.. Let me see
if you are explaining where I can understand.
WN> The purpose of the default clause in the property definition is to
WN> allow the class streaming mechanism to decide whether or not it needs
WN> to save the value of this property when the object is written to
WN> storage (e.g. when the IDE saves your form to the .dfm file, this stuff
WN> comes into play, but you can also use it yourself too).
hmmmm, trying to see the "why" here... let me continue... :-)
WN> In your example, the Lock property would be written to storage *only* if
WN> Lock was False. You are telling it there is no need to save it if it's
WN> True because upon loading it, your constructor will set it to True
WN> anyway. The purpose of this is to reduce storage space (affects your
WN> exe size since DFMs are stored as RCDATA resources in your exe) and
WN> this enhances speed in storing/loading classes.
Ok, I trust there is a reason, but I don't see it why in its entirely.
Ok,
#1, it is unrelated to any "run time" initializing.
#2, it is designed as a speed/resource space saving feature.
So why not just set all boolean properties to TRUE? There is no harm?
It sounds like its 100% positive.
I suppose, this is not something OOPs designers wish to add to
OOPS? (real variable/property initialization OOP syntax)
Thanks for the information.
Hector Santos/Santronics
Hector --
It's to notify the streaming mechanism (you know, the chunk of code that
dumps your published properties into a DFM file and reads it back) of
what value YOU default the property to.
In other words, if you have a property as
property Active: boolean read FActive write FActive default True;
...then you're informing the streaming mechanism that when this object is
constructed, YOU will make the value true...ex:
constructor TMyComp.Create( AOwner: TComponent );
begin
inherited Create( AOwner );
FActive := True;
end;
The result of this is that when TMyComp gets dumped to a form file, it
won't include a value for Active if Active = True; it doesn't need to,
because you made it True on construction, so the streaming code can just
leave it alone.
Geo
--
George Mealer
g...@snarksoft.com
"Let your mind wander / It may never come back." -- Skyclad
hope this helps,
Kimo
GM> The result of this is that when TMyComp gets dumped to a form file, it
GM> won't include a value for Active if Active = True; it doesn't need to,
GM> because you made it True on construction, so the streaming code can just
GM> leave it alone.
Ok, make sense... I think. <g>
Just one thing I still don't understand. I don't see the relationship
between the streamer and the constructor because there is none.
It has no clue what the run time value is going to be and it has
no effect whatsoever on the run time initial value. So what does
it care whether I set it to TRUE or not?
Whats the point of even making it an option if it has no bearing on
the actual initalization of the variable at run time?
The eventual variable is going to be zero loaded anyway regardless of
the property default value - TRUE or FALSE.
Conversely, regardless of a TRUE or FALSE property DEFAULT value, you
still need to initialize the variable in the constructor if its going
to be something other than zero.
So either way, DELPHI should just always avoid the storoage.
If I understand it now, I might as well make all my boolean
properties have a TRUE property DEFAULT value because whether I do
this or not, it has no bearing in the actual run time code. It would be
a feature to help the streamer load the resource.
Other than that, the only other usefulness I see, is to serve as a
"reminder" of what you put in a constructor. :-)
Anyway, Thanks for the explaination.
Hector Santos/Santronics
If you view a form as text, you will see the properties that are
actually streamed. If you compare the properties there with the
properties actually displayed in the object inspector you will see that
the streamed properties are only a small subset.
When a component is loaded, the initial values of properties can come
from three places:
1) whatever binary zeroes means to the property (e.g boolean false or
null string.
2) value set in the constructor
3) value streamed in
The default property value is merely telling the compiler what value
doesn't have to be streamed out because the correct value is being set
via (1) or (2) - but it is your responsibility to ensure the two values
match.
Appropriately chosen defaults can make an enormous difference to the
size of streamed data.
Mike Orriss (m...@3kcc.co.uk)
http://www.3kcc.co.uk/notetree.htm
It makes a lot of sense to me:
1) Setting a property value in the constructor is many times faster
than loading it from a file.
2) Besides the simple 'default True' you can also use a function that
will return the 'default value' at design time. Delphi has no way to
detect what this default value should be at compile time. It would be
very illogical to me to add implicit code in one case and not in the
other. So what Delphi does (use 'default' purely as a streaming
facility) is the only logical thing to do.
Jan
On Tue, 22 Sep 1998 02:11:21 -0400, Hector Santos
<hsa...@secured.santronics.com> wrote:
>
>On Sep 21, 1998 04:38pm, G...@SNARKSOFT.COM (GEORGE MEALER) wrote to HECTOR
>SANTOS:
>
Well, not directly. Think of it as a statement of intent.
> It has no clue what the run time value is going to be and it has
> no effect whatsoever on the run time initial value. So what does
> it care whether I set it to TRUE or not?
>
> Whats the point of even making it an option if it has no bearing on
> the actual initalization of the variable at run time?
>
> The eventual variable is going to be zero loaded anyway regardless of
> the property default value - TRUE or FALSE.
>
> Conversely, regardless of a TRUE or FALSE property DEFAULT value, you
> still need to initialize the variable in the constructor if its going
> to be something other than zero.
>
> So either way, DELPHI should just always avoid the storoage.
>
> If I understand it now, I might as well make all my boolean
> properties have a TRUE property DEFAULT value because whether I do
> this or not, it has no bearing in the actual run time code. It would be
> a feature to help the streamer load the resource.
>
Well, let's see. Take the proverbial boolean property Active.
property Active { ... } default True;
If the constructor sets Active := True, then...
If Active = True and component is streamed out, then the streaming
mechanism doesn't save the property (Active = default). Upon streaming
in, the constructor sets Active = True, so we're happy.
If Active = False and the component is streamed out, then the streamining
mechanism saves the property. Upon streaming in, the constructor sets
Active = True. The TReader then sets Active = False. We're happy.
So far so good.
If the constructor sets Active := False, or doesn't set anything at all
(since Booleans default to False) then...
If Active = False and component is streamed out, then the streaming
mechanism saves the property. Upon streaming in, the constructor sets
Active = False. The TReader also sets Active = False. We're happy.
If Active = True and component is streamed out, then the streaming
mechanism doesn't save the property (Active = default). Upon streaming
in, the constructor sets Active = False. We've got a problem. The read
value doesn't match the written value.
Whoops! As you can see, it's important to make your default match your
constructor's behavior. You could extrapolate this situation to setting
default False all the time. The point is, you need to set your default
string to whatever your constructor is doing or leave it out altogether
(always stored).
> Other than that, the only other usefulness I see, is to serve as a
> "reminder" of what you put in a constructor. :-)
>
That too. :)
> If the property value is unequal to the default, stream it to the .dfm.
> Otherwise, don't stream it and assume that it will be taken care of
> in initialization code
Exactly. This is how the Delphi component streaming system works. It
writes out the property name + type identifier + value, which is a bit
different from database tables or files of records, which only write
out values to each row (or record).
With database tables and records, the Nth field will always be the
same, because the same number of values (one for each field) are
written out to the row (or record). In the component stream, the Nth
field can vary, because properties whose value is the default aren't
written to the stream. This is quite different from databases and
records, and takes some getting used to.
The Delphi component streaming system can easily determine the "field"
(actually, property) to which the value belongs because the property
name is saved into the stream with each value. This approach allows
the component streaming system to skip writing out properties whose
value is the default.
--
Rick Rogers (TeamB) | Fenestra Technologies
http://www.fenestra.com/
There is an order of operations that makes the connection - the streamer
relies on the constructor to do what it claims it is doing in the default
clauses in order to reduce its work.
Take the example of loading the dfm for a form at runtime.
1. Loading mechanism sees (in binary format) "object = TMyForm" and calls
TMyForm.Create
2. As part of calling Create, memory is allocated and cleared to binary
zero.
3. The Create constructor is executed and sets various properties to their
defaults (e.g. FormStyle is set to fsNormal).
4. The loading mechanism *then* reads all the properties that have been
stored for TMyForm and sets those properties accordingly - overriding the
defaults if they are different.
So, if in TMyForm at design time, you:
A) Leave FormStyle alone (fsNormal) and save, the saving process will see
that there is a "default fsNormal" directive for the property, see that you
have not changed it, and will therefore not save this property. At runtime
FormStyle is set to fsNormal in the constructor (#3 above). In step #4, the
loading process never encounters a line for FormStyle because it was not
saved.
B) At design time, you change FormStyle to fsStayOnTop and compile. The
saving process sees that FormStyle is different than the default set for
that property and so *does* save it to the dfm. At runtime, the constructor
sets the property to fsNormal as before (step 3) but this time in step 4 it
will see a line for that property in the dfm telling it to set it to
fsStayOnTop.
Think of it this way: when you set a default value in a property definition,
you are, in effect, making a promise to the streamer that you will be
setting that property to this default value in your constructor, and the
streamer is then able to take advantage of that to optimize its work. It is
a way for you to tell the streamer directly in the class definition what you
will be doing in the constructor.
>2) Besides the simple 'default True' you can also use a function that
>will return the 'default value' at design time. Delphi has no way to
>detect what this default value should be at compile time. It would be
>very illogical to me to add implicit code in one case and not in the
>other. So what Delphi does (use 'default' purely as a streaming
>facility) is the only logical thing to do.
You're right that the compiler should not generate code to set the
initial values of properties. TPersistent.Create is the right place.
TPersistent's constructor can read the RTTI for the class and find out
which properties have default values, and set those properties to
their corresponding default values. A derived class can, of course,
override the Create constructor and change that behavior, but it gives
an inexpensive, easy baseline--one that is much less confusing to new
Delphi programmers.
Secrets of Delphi 2 shows you how you can do this for your code, but
the code to initialize properties to their default values belongs in a
base class, namely, TPersistent.
--
Ray Lischner (http://www.tempest-sw.com/)
Author of "Hidden Paths of Delphi 3: Experts, Wizards, and the Open Tools API"
I know what you mean - it would be nice at least if the class
completion wizard automatically added the initialization to the
constructor for you...
Colin
e-mail :co...@wilsonc.demon.co.uk
web: http://www.wilsonc.demon.co.uk/delphi.htm
> You're right that the compiler should not generate code to set the
> initial values of properties. TPersistent.Create is the right place.
>
> TPersistent's constructor can read the RTTI for the class and find out
> which properties have default values, and set those properties to
Now if we could only get the default to include non ordinals too.
--
Chad Z. Hower - Surgoinsville, TN - "Programming is an art form that fights back"
*** ICon 98 Report now avialable at http://www.pbe.com/Kudzu/Icon98 ***
Free Delphi, CGI, Web and other things at: http://www.pbe.com/Kudzu
Delphi Open Source Internet effort at http://www.pbe.com/Winshoes (Also free
download)
>You're right that the compiler should not generate code to set the
>initial values of properties. TPersistent.Create is the right place.
>
>TPersistent's constructor can read the RTTI for the class and find out
>which properties have default values, and set those properties to
>their corresponding default values. A derived class can, of course,
>override the Create constructor and change that behavior, but it gives
>an inexpensive, easy baseline--one that is much less confusing to new
>Delphi programmers.
>
Ray,
You're absolutely right that it _is_ possible. Question is: do we
_want_ default properties to be initialized by Delphi,
TPersistent.Create or whatever?
I think not.
If you take the simple 'default True' then it seems to be a good idea
to initialize it automatically. If you consider the default to be
calculated at design time by a function GetDefaultActive, however,
this isn't obvious anymore. Sure, you could add a call to this
function in TPersistent.Create. But mostly you need to calculate the
default by a function because it depends on other property values.
This means that the order in which default values are set might be
very important.
That's why I think the Delphi solution is the only logical one. I
rather don't have a particular feature than a feature that works only
partially.
Jan
Jan