Board index » cppbuilder » Re: Borland has broken it's promises once again

Re: Borland has broken it's promises once again


2005-11-26 03:17:30 AM
cppbuilder16
At 14:37:55, 25.11.2005, Alisdair Meredith [TeamB] wrote:
Quote
This is why Delphi allows you to control timing of
chaining the base ctor call - it is your responsibility to make your
class usable in event of a virtual function call.
There are few things to remark here. Since all objects are initialized
with 0 first, many Delphi classes do not initialize values before they
chain down to the base class constructor, but simply check these values
for 0 or nil in the virtual functions.
In Delphi for .NET, you can't have any code before the call to the base
constructor (the call is still explicit, but it must be the first thing
in the code of a constructor, otherwise the compiler barks at you),
because in .NET, like in C++, the base object must be initialized first.
So while it may look as if the derived constructor runs first, this is
not the case. I also think that there are issues with calling virtual
functions from a constructor, in .NET.
--
Rudy Velthuis [TeamB] velthuis.homepage.t-online.de
"It isn't pollution that's harming the environment. It's the impurities
in our air and water that are doing it." -- Dan Quayle.
 
 

Re:Re: Borland has broken it's promises once again

"Rudy Velthuis [TeamB]" < XXXX@XXXXX.COM >writes:
Quote
Actually, that is not true. AFAIK, you can also overwrite new() or use
placement new or whatever you call it. So the C++ mechanism is different,
and not necessarily tied to the class, but it can affect the same stages.
Since in Delphi, all objects are derived from TObject, it made sense to
put the functionality there. This greatly simplified language design, I
guess.
That is true, except
1) A "new" expression does two things: it allocates memory, and then
creates an object in that memory. The two steps are semi-unrelated
activities, especially as far as the object implementor is
concerned.
2) Not all objects are created on the heap, and thus a "new"
expression is not even necessary part of object construction. It
is just one way way. A stack-allocated object bypasses the
heap-allocation entirely.
3) As such, the act of allocating memory is not inherently related
with the actual creation an object. (Except that some physical
location must already exist before before an object can be
created.)
In Delphi I don't believe you can seperate the concerns at all (but
I'm not sure about that)--all TObject-derived objects are heap
allocated.
In C++ you can seperate those concerns, meaning that the allocation is
not truly an intrinsic part/stage of the creation of an object.
Thus, creation of the object is solely a function of the constructor.
--
Chris (TeamB);
 

Re:Re: Borland has broken it's promises once again

At 21:17:54, 25.11.2005, Chris Uzdavinis (TeamB) wrote:
Quote
3) As such, the act of allocating memory is not inherently related
with the actual creation an object. (Except that some physical
location must already exist before before an object can be
created.)
Yes, an in C++, that is handled by the compiler/RTL combination. In
Delphi, it is handled by the object itself. Fact is that it is part of
construction alright, even if it is not handled by the object.
Quote
In Delphi I don't believe you can seperate the concerns at all (but
I'm not sure about that)--all TObject-derived objects are heap
allocated.
Well, I guess it would be possible to make them stack based, if you were
very bold. It would require some overriding of some virtual functions,
but it should be possible.
Quote
In C++ you can seperate those concerns, meaning that the allocation is
not truly an intrinsic part/stage of the creation of an object.
I understand that. But in Delphi, you have the stages Alisdair mentioned,
and they are all handled by the class, and can be overridden.
--
Rudy Velthuis [TeamB] velthuis.homepage.t-online.de
"An inconvenience is only an adventure wrongly considered; an adventure
is an inconvenience rightly considered."
- Gilbert Keith Chesterton (1874-1936)
 

{smallsort}

Re:Re: Borland has broken it's promises once again

"Rudy Velthuis [TeamB]" < XXXX@XXXXX.COM >wrote in message
Quote
ISTM that you saw construction purely as the part where the constructor
code runs.
And I still do. A constructor builds an object. If you want to assign
a value to the object's variables at construct time, you assign
them. If you assign them in the intializer list, you basically construct
those objects with their values. If you want to assign them in the body
of the ctor, you construct them unitialized and then assign them a
value during the construction of the class instance that you're creating.
If you don't use the init list or the body of the constructor,
you have a bunch of unitialized values. They're still created but are
not initialized.
My understanding may be flawed but construction and assignment
are not the same thing. I assume by "fill with values" you mean
assignment. In C++, whether you use new or not, you construct
something once. You can initialize it when it's constructed or
you can initialize it later (and repeatedly) or you can not initialize
it at all.
From what you're saying, you can make Delphi work the
same way. The difference is that in C++ when you construct
an object that's derived from another object (base) the base
is constructed before the derived class. When you delete
the derived class, it's deleted before the base class. You cannot
change this sequence. There are no virtual constructors in C++,
for example. There are virtual destructors and they must be used
to make polymorphism work.
My point is not that C++ is better than Delphi, though I probably
would say that it is. My point is that the languages are different.
Some of the differences are as basic as object construction/destruction.
In BCB we have to deal with this. This is not a trivial problem
at times.
 

Re:Re: Borland has broken it's promises once again

At 21:54:21, 25.11.2005, Duane Hebert wrote:
Quote

"Rudy Velthuis [TeamB]" < XXXX@XXXXX.COM >wrote in message
news:xn0ea652pg3c8c00i-velthuis@www.teamb.com...

>ISTM that you saw construction purely as the part where the
>constructor code runs.

And I still do. A constructor builds an object.
Define "build". What does a constructor actually do?
--
Rudy Velthuis [TeamB] velthuis.homepage.t-online.de
"Chaos Theory is a new theory invented by scientists panicked by the
thought that the public were beginning to understand the old ones."
-- Mike Barfield.
 

Re:Re: Borland has broken it's promises once again

"Rudy Velthuis [TeamB]" < XXXX@XXXXX.COM >wrote in message
Quote
At 21:54:21, 25.11.2005, Duane Hebert wrote:

>
>"Rudy Velthuis [TeamB]" < XXXX@XXXXX.COM >wrote in message
>news:xn0ea652pg3c8c00i-velthuis@www.teamb.com...
>
>>ISTM that you saw construction purely as the part where the
>>constructor code runs.
>
>And I still do. A constructor builds an object.

Define "build". What does a constructor actually do?
Chris's explanation a bit further down describes it
better than I could. One thing that it doesn't do is
initialize the object. If you want to init it, you have
to do that.
 

Re:Re: Borland has broken it's promises once again

Duane Hebert wrote:
Quote
And I still do. A constructor builds an object. If you want to
assign a value to the object's variables at construct time, you assign
them. If you assign them in the intializer list, you basically
construct those objects with their values. If you want to assign
them in the body of the ctor, you construct them unitialized and then
assign them a value during the construction of the class instance
that you're creating. If you don't use the init list or the body
of the constructor, you have a bunch of unitialized values. They're
still created but are not initialized.
While remembering the C++ construction is simpler than Delphi... ;?
This is a close approximation but could be more precise.
If you do not specify an sub-object in the initializer list (base or
member subobject) it will be 'default initialized' if it is a
class-type, or array-of-class-types. Other types will have
indeterminate values. Default initializing a POD class (or array of
POD classes) will also leave those objects in an indeterminate state.
Otherwise, the default constructor will be implicitly called.
And I'm not even going to mention the cases where the constructor is
malformed if you do not explicitly initialise base/member objects
(virtual inheritance, const members, references-as-members, ... )
--
AlisdairM(TeamB)
 

Re:Re: Borland has broken it's promises once again

"Alisdair Meredith[TeamB]"
<alisdair.meredith@ XXXX@XXXXX.COM >wrote in message
Quote
While remembering the C++ construction is simpler than Delphi... ;?

This is a close approximation but could be more precise.

If you do not specify an sub-object in the initializer list (base or
member subobject) it will be 'default initialized' if it is a
class-type, or array-of-class-types. Other types will have
indeterminate values. Default initializing a POD class (or array of
POD classes) will also leave those objects in an indeterminate state.
Otherwise, the default constructor will be implicitly called.


And I'm not even going to mention the cases where the constructor is
malformed if you do not explicitly initialise base/member objects
(virtual inheritance, const members, references-as-members, ... )
It wasn't really a question of which has simpler construction though
it seems to have denegrated to that <g>. The initial question was
whether c++ and Delphi has the same sequence of construction.
Rudy was arguing that they did. I was saying that they don't. AFAICT,
Delphi constructs derived classes before base classes. This is the
opposite of c++. I mean, Delphi even has virtual ctors which makes
no sense at all from a c++ POV.
When using BCB it's necessary to take this into
account. It's especially interesting when part of the construction is
delphi and part is c++.
I think this all started as a response to VCL being written in
C++. Someone asked what the benefit would be. To me
the benefit would be to not introduce delphi behavior into
an already complex language.
 

Re:Re: Borland has broken it's promises once again

Chris Uzdavinis (TeamB) wrote:
Quote
Edward Diener < XXXX@XXXXX.COM >writes:


>C++ not having a reflection mechanism that is part of the language
>specification makes it more difficult to implement RAD in standard
>C++. It means that RAD must either be done through language extensions
>and/or through extensions to a given compiler at compile time which
>allow the equivalent of reflection data to be written to persistent
>storage and read back again at run-time.


Not necessarily. It could also simply pass the work onto the user, to
provide a function that returns a name-to-factory table, or somesuch.
Then component developers would just have a little more boilerplate
code to write in order for it to work. Not attractive, but doesn't
require a change to a compiler.
The work that this would entail on the part of the end-user, for every
set of C++ elements being used at any given time, would be ridiculous.
You are essentially asking the programmer to provide reflection
facilities. Sorry if I do not see that as C++ reflection in any
realistic sense.
 

Re:Re: Borland has broken it's promises once again

"Edward Diener" wrote:
Quote
The work that this would entail on the part of the end-user, for every set
of C++ elements being used at any given time, would be ridiculous. You are
essentially asking the programmer to provide reflection facilities. Sorry
if I do not see that as C++ reflection in any realistic sense.
Most of the work can be implemented in base classes. That's how Delphi does
it too. People seem to forget that every class you create in Delphi inherits
from TObject. You can not create a 'stand alone (leightweight) class'. From
a RAD point of view this is nice because every class you create fits nicely
in the framework, if you overload all necessary methods and register your
class properly. In C++ this works also, only you have the choice in what
framework you want your class, if any :-)
Peter
 

Re:Re: Borland has broken it's promises once again

Edward Diener < XXXX@XXXXX.COM >writes:
Quote
The work that this would entail on the part of the end-user, for every
set of C++ elements being used at any given time, would be
ridiculous. You are essentially asking the programmer to provide
reflection facilities. Sorry if I do not see that as C++ reflection in
any realistic sense.
I agree that it's a burden and unreasonable. But I reject the notion
that it CANNOT be done in C++ without compiler support. It just can't
be done as easily. (Also, I'm not calling this C++ reflection, I'm
just calling it "barely enough to get the job done for this specific
purpose.")
--
Chris (TeamB);
 

Re:Re: Borland has broken it's promises once again

Edward Diener wrote:
Quote
C++ not having a reflection mechanism that is part of the language
specification makes it more difficult to implement RAD in standard
C++. It means that RAD must either be done through language
extensions and/or through extensions to a given compiler at compile
time which allow the equivalent of reflection data to be written to
persistent storage and read back again at run-time.
VCF has a good reflection mechanism, and it works cross-compiler. They just
use macros and a ClassRegistry system, and it seems to work fine.
Jonathan
 

Re:Re: Borland has broken it's promises once again

Chris Uzdavinis (TeamB) wrote:
Quote
Edward Diener < XXXX@XXXXX.COM >writes:


>The work that this would entail on the part of the end-user, for every
>set of C++ elements being used at any given time, would be
>ridiculous. You are essentially asking the programmer to provide
>reflection facilities. Sorry if I do not see that as C++ reflection in
>any realistic sense.


I agree that it's a burden and unreasonable. But I reject the notion
that it CANNOT be done in C++ without compiler support.
I agree with you.
Quote
It just can't
be done as easily. (Also, I'm not calling this C++ reflection, I'm
just calling it "barely enough to get the job done for this specific
purpose.")
Yes, I understand. Aside from VCF, which another responder has
mentioned, I have also seen other class/type registration systems which
allow enough of a run-time reflection mechanism to implement RAD
programming in C++. Still I much prefer this to be part of the
language/compiler system, and for the burden of specifying what will be
available to a reflection system to be on the language/implementor and
not the programmer.
 

Re:Re: Borland has broken it's promises once again

Edward Diener wrote:
Quote
I too have seen mechanisms where it is up to the programmer to
register the classes, and information about the members of the
classes, which create a run-time reflection mechanism. I do not
reject that approach but I believe that one that is supported
intrinsically on a standard basis by the language and/or compiler is
far more regular and effective. It also takes the burden from the
programmer of having to "register" all of the information needed for
such a mechanism each and every time the programmer has some new type
of object. I do agree with you that such a system is doable to a
degree, as VCF has shown, without language and/or compiler support.
Personally, I find the VCF system to be complex. But I guess that is what
happens when one tries to make one's one reflecion mechanism.
Quote
I would really like to see C++ have a full reflection system, ala
Java, Python, or .NET, which goes beyond its usage in RAD, as
important as that may be. A reflection system can be a great
advantage when used by 3rd party tools to aid in program development,
and obviates the need for source code.
I don't know Python or .Net's one, but I do know that the Java one is
amazingly powerful. But Java is Java.
Jonathan
 

Re:Re: Borland has broken it's promises once again

Jonathan Benedicto wrote:
Quote
Edward Diener wrote:

>I too have seen mechanisms where it is up to the programmer to
>register the classes, and information about the members of the
>classes, which create a run-time reflection mechanism. I do not
>reject that approach but I believe that one that is supported
>intrinsically on a standard basis by the language and/or compiler is
>far more regular and effective. It also takes the burden from the
>programmer of having to "register" all of the information needed for
>such a mechanism each and every time the programmer has some new type
>of object. I do agree with you that such a system is doable to a
>degree, as VCF has shown, without language and/or compiler support.


Personally, I find the VCF system to be complex. But I guess that is what
happens when one tries to make one's one reflecion mechanism.


>I would really like to see C++ have a full reflection system, ala
>Java, Python, or .NET, which goes beyond its usage in RAD, as
>important as that may be. A reflection system can be a great
>advantage when used by 3rd party tools to aid in program development,
>and obviates the need for source code.


I don't know Python or .Net's one, but I do know that the Java one is
amazingly powerful. But Java is Java.
Python is even better when it comes to reflection in that reflection was
designed as part of the language and every type in Python is an object
itself. Essentially there is no type in Python which does not have
reflection built into it as part of the language and any new type which
may be added to the language in the future will have such information
added to it by design.
In .NET reflection is a library but the mechanism which makes this
possible is that the .NET compiler can completely discover what any
individual element contains since .NET's IL ( intermediate language )
provides this data and .NET is distributed with a library to discover
this data ( essentially read/interpret IL code ). In this sense .NET's
IL is closer to Java's JVM than it is to Python's language support for
reflection. But it is largely a moot point, except for ease of use, if
the results are the same.
I would much rather see C++ adopt the Python general model and make
types themselves objects with discoverable properties, but I believe
that C++ is going the other way by generating, for each compiled source
file, the necessary information to "reflect" on the types defined in
that source. This goes along with C++'s reticence to add features to the
language when anything can be done by compilers/libraries instead, a
fact whose reasons I understand but still find regrettable in this case.
However having been told to essentially "get lost" when I offered to be
part, in my own small way, of C++'s coming attempt to add "reflection"
to the language, I can only hope that the attempt is successful and that
the next version of C++ has a workable and rich reflection mechanism.