понедельник, 23 марта 2015 г.

Link. If there were an automatic memory manager (i.e. a garbage collector) for the version of Delphi you currently use what would you be willing to pay for it?

Original in Russian: http://18delphi.blogspot.ru/2015/03/link-if-there-were-automatic-memory.html

Link. If there were an automatic memory manager (i.e. a garbage collector) for the version of Delphi you currently use what would you be willing to pay for it?
https://plus.google.com/u/0/+KennethCochran/posts/gAjF4mQrkd8?cfem=1

It makes me laugh.

I’ve already written that I don’t like – About "hazards" of ARC and other “automats” (set of references) http://programmingmindstream.blogspot.ru/2014/10/arc.html

All the more I don’t like GC.

By the way, if you need ARC for Win 32, you should read:

Containers 2. My own implementation of IUnknown and reference counting. And mixins.
Containers 1. Implementation of reference counting.

REMEMBER that we can do like this:

type
 IMyClassPtr = interface;
 
 TMyClass = class
  ...
  class function CreatePtr: IMyClassPtr;
 end;//TMyClass
 
 IMyClassPtr = interface
  function AsHolded: TMyClass;
 end;//IMyClassPtr

Needless to remind you about Generic's.

(+) Records.
(+) Implicit.

Do you understand the idea?

AutoPtr сan be done something like this:

type
 TAutoPtr<T> = record
  class operator Implicit(aValue: <T>): TAutoPtr<T>;
  class operator Explicit(const aValue: TAutoPtr<T>): <T>;
 end;//TAutoPtr

Link. If there were an automatic memory manager (i.e. a garbage collector) for the version of Delphi you currently use what would you be willing to pay for it?

https://plus.google.com/u/0/+KennethCochran/posts/gAjF4mQrkd8?cfem=1

It makes me laughing.

Я уже писал, что и ARC то я не люблю - Об "опасностях" ARC и прочих "автоматов" (набор ссылок)

А уж GC - тем более.

И кстати если кому-то нужен ARC для Win 32, то читаем вот:

Собственная реализация IUnknown и подсчёт ссылок. И примеси.
Containers 1. Implementation of reference counting.

И ПОМНИМ о том, что можно сделать:

type
 IMyClassPtr = interface;

 TMyClass = class
  ...
  class function CreatePtr: IMyClassPtr;
 end;//TMyClass

 IMyClassPtr = interface
  function AsHolded: TMyClass;
 end;//IMyClassPtr

Ну и Generic'и конечно.

(+) Records.
(+) Implicit.

Мысль понятна?

Вот как-то так можно сделать AutoPtr:

type
 TAutoPtr<T> = record
  class operator Implicit(aValue: <T>): TAutoPtr<T>;
  class operator Explicit(const aValue: TAutoPtr<T>): <T>;
 end;//TAutoPtr

четверг, 19 марта 2015 г.

Launch on the emulator


  1. We download Android SDK if it was not installed along with Rad Studio
  2. We launch AVD Manager

3. We create a device

We have to define using of GPU and exclude SnapShot. Otherwise, it hangs and slows down. Perhaps, I’ve got butterfingers.

Anyway, at these settings, the emulator does slows down but it works.

After pressing ОК.

4. We launch the emulator

We press Launch

We can see the launch window

5. While the emulator is being launched (at my PC it takes about 3 to 7 minutes; AMD 8x3,5 Mhz. 8 gb DDR3.), we launch Rad Studio

After launching the emulator, we can see the following window:


7. We select the Android platform, and, in our case, Target is MyDevice7

8. We do Build
It ate up about 800 Mb and took about 6 minutes.
Build.gif



9. We launch and catch

First chance exception at $B6F34CE2. Exception class Illegal instruction (4). Process MindStream.apk (1433)

We press OK and wait.

The result:
Run.gif

How I built friendship between Delphi XE7 with Samsung devices


I’ve expressed my “indignation” here - http://18delphi.blogspot.ru/2015/03/to-be-honest-delphi-for-android-evokes.html


Now, let’s get to the point.

We were doing the project - MindStream. Table of contents, under FMX.

BUT we tested and launched it only under Windows.

The reason is – we “took on trust” the words of Embarcadero about the “single code base” and that “the code once written works on all devices”.

We had a strong belief in this “dream”.

And, finally, Samsung sent us pads to test - Offtopic. Samsung прислал планшеты для тестирования .

So, yesterday I decided to “launch our precious” on the devices we got.

I spent eight hours on it, may be even more.

So.

Step by step.

NUMBER ONE

We install the drivers for the device.

We check if the device is NOT CONNECTED to the computer.

We take the drivers from here:
http://androidxda.com/download-samsung-usb-drivers

Or directly from here:
https://bitbucket.org/ingword/mindstream/src/125e663326c754319dbfe8532b2f362c5d365691/TestApp/Drivers/?at=B-Samsung-Try

Why do I give these links? For I had no appropriate results from searching in Google and on Samsung website.

Perhaps, I have butterfingers.

NUMBER TWO

May be we’ll have to install Kies. Learn what it is from Samsung website.

The direct link:
https://bitbucket.org/ingword/mindstream/src/125e663326c754319dbfe8532b2f362c5d365691/TestApp/Drivers/Kies3Setup.exe?at=B-Samsung-Try

How can it be possible?

Well, that’s because I’ve installed Kies FIRST, but I have not SEEN the devices. Only after, I’ve installed the drivers.

One of these would possibly be enough.

NUMBER THREE.

May be, you will have to restart your computer.

NUMBER FOUR.

We launch Delphi and CREATE or open the project FireUI.

NUMBER FIVE.

We look at the Project Manager.
http://3.bp.blogspot.com/-OqOI-dAarUQ/VQnP0uTeqHI/AAAAAAAFt_0/3KGEMUmxY10/s1600/pm1.png


We press the right mouse button and select Refresh.

We’d have the following:
http://1.bp.blogspot.com/-lCqXlBkybHw/VQnQgID16UI/AAAAAAAFt_8/RWu48SK5GLM/s1600/pm2.png

If the devices do not show up, the icon with arrows would stick and you’d have to reset Delphi a couple of times, each time pressing Refresh.

In the end, the device will show up and Delphi will “memorize it somewhere”. Then, everything will be OK.

NUMBER SIX.

We select Target Android.

We press Build.

If Internal Error appear, as in my “indignant” post (http://18delphi.blogspot.ru/2015/03/to-be-honest-delphi-for-android-evokes.html), we divide the project in two and try to build.

We do it till the error disappears.

When the project is built, the Messages window will print Success.

Note. The build process can take about 20 minutes and eat up to 1.5 Gb of the memory.

NUMBER SEVEN.

We press Run.

Delploying is written here.

At this stage, I’ve been trapped by an error:
[PAClient Error] Error: E2820 Could not find program, 'C:\Users\Public\Documents\Embarcadero\Studio\15.0\PlatformSDKs\adt-bundle-windows-x86-20131030\sdk\tools\ZipAlign.exe'

There was not some utility from SDK - ZipAlign.exe

I don’t know why.

I found it in the previous Delphi XE6 installation and copied it to the specified directory.

This utility is put to the repository for you: https://bitbucket.org/ingword/mindstream/commits/fafb709a95b1352b82709e464659e4da9d5a9ac5?at=B-Samsung-Try
https://bitbucket.org/ingword/mindstream/src/fafb709a95b1352b82709e464659e4da9d5a9ac5/TestApp/Tools/zipalign.exe?at=B-Samsung-Try

NUMBER EIGHT.

We press Run again and wait for the end of Deploying.

At this point, again, it can fail to launch. The dialog about “finger print” begins on the device.

We HAVE to accept it.

I did not do it at once. But later I saw and did it.

YES!

One more note – the mode Debug via USB or USB Debug has to be enabled on the device.

For this, we open Options and About Device.

We search for the field Build (Number) and press it SEVEN times.

As a result, the group of Developer Options will appear.

THERE we select USB Debug.

Actually, that is all.

Have a nice DEBUGGING.

Briefly. About “partially initialized objects” (or again about factories)

Original in Russian: http://programmingmindstream.blogspot.ru/2014/10/blog-post_88.html

Based on:

Briefly. About constructors
Depression, or Falsity of hResult and other ErrorCode
Briefly. Once again about factories (in Russian)
Briefly. Again about factories
Briefly. About factories
Briefly. “Why we need tests” (in Russian)
Factory method (in Russian)

Today, after all, (I hope) I found an error that didn’t “let me live” many years.

We could trace it in various logs.

But we could not “vasten”  it.

But today I “seized it by the tail”, under a debugger.

Although it sounds trite – the reason is the same old “partially initialized objects”.

Something like this (naturally, I simplified the code to the maximum):

construstor TStorageHeader.Create(aPosition: Int64);
begin
 Assert(aPosition >= 0);
 inherited Create;
 FillChar(f_Data, SizeOf(f_Data), 0); // - we initialize the data
 f_Position := aPosition;
 LockFile(f_Position, SizeOf(f_Data)); // - we lock the file region where EXCEPTION can be RAISED - LOCK_VIOLATION
 LoadData(f_Position, f_Data, SizeOf(f_Data)); // - we read data 
end;
 
destructor TStorageHeader.Destroy;
begin
 SaveData(f_Position, f_Data, SizeOf(f_Data)); // - we write data 
 UnLockFile(f_Position, SizeOf(f_Data)); // - we unlock the file region
 inherited;
end;

What is the problem here?

This one is:

var
 l_H : TStorageHeader;
begin
 l_H := TStorageHeader.Create(aSomePosition);
 try
  ...
 finally
  FreeAndNil(l_H);
 end;//try..finally
end;


- if there’s NO EXCEPTION in the constructor, all goes well.

But if there IS an EXCEPTION in the constructor, the destructor is called AUTOMATICALLY.

On the PARTIALLY INITIALIZED object.

What happens? If exception is triggered in LockFile, then LoadData code will fail.

But! The destructor will be called (we read documentation).

I quote:

"Destructors called because of exceptions thrown from constructors"

So, what happens?

SaveData code will save what FillChar has initialized instead of what we've READ.

Do you understand the problem?

It is trivial. However, it was “alive” for many years. Why? Because the probability of the exception raised from LockFile was extremely low. Due to the fact that locking is adjusted to time-out, which is adequate for the most operations to eliminate the exception.

Moreover – we had code (above) that synchronised the access to the resources at a level of “business logic”.

But!

The synchronization caused a negative effect on the performance. The “bottleneck”  (in Russian).

Customers “waited for each other” and kept out of the “shared resource”. That is why we did not come to LockFile that might “trigger the exception”. It’s just – “all waited in line” and worked in series instead of in parallel.

(By the way, it is worth reading - E.W. Dijkstra “Co-operating sequential processes”  (in Russian). Although it has “nothing to do with the case”.)

But!

We managed this “bottleneck” and customers started to work “truly independently and in parallel”.

The probability of getting the exception and the “problem code” – has increased dramatically.

Especially on automatic tests  (in Russian) , since they work without delays and pauses of human being.

As a result, the error began to appear more regularly and more often.

Especially it appears when we launch tests under a debugger and pause at break-points “in the right place” emulating “network latencies”.

What should we do?

Well, it’s simple. For example, we can do the following:

construstor TStorageHeader.Create(aPosition: Int64);
begin
 Assert(aPosition >= 0);
 inherited Create;
 f_DataIsLoaded := false; // - for “safety”... in reality, to POSTULATE our intentions
 FillChar(f_Data, SizeOf(f_Data), 0); // - we initialize data
 f_Position := aPosition;
 LockFile(f_Position, SizeOf(f_Data)); // - we lock the file region where EXCEPTION can be RAISED - LOCK_VIOLATION
 LoadData(f_Position, f_Data, SizeOf(f_Data)); // - we read data
 f_DataIsLoaded := true; // - we postulate that we have read data
end;
 
destructor TStorageHeader.Destroy;
begin
 if f_DataIsLoaded then // - we only write what we have READ, not “garbage”
  SaveData(f_Position, f_Data, SizeOf(f_Data)); // - we write data 
 UnLockFile(f_Position, SizeOf(f_Data)); // - we unlock the file region
 inherited;
end;

Or in this way:

construstor TStorageHeader.Create(aPosition: Int64);
begin
 Assert(aPosition >= 0);
 inherited Create;
 FillChar(f_Data, SizeOf(f_Data), 0); // - we initialize data
 f_Position := aPosition;
 LockFile(f_Position, SizeOf(f_Data)); // - we lock the file region where EXCEPTION can be RAISED - LOCK_VIOLATION
 // - we also “raise the flag” - IsLocked
 LoadData(f_Position, f_Data, SizeOf(f_Data)); // - we read data 
end;
 
destructor TStorageHeader.Destroy;
begin
 if Self.IsLocked then // - we write only if we “lock the region", hence – we’ve read it
  SaveData(f_Position, f_Data, SizeOf(f_Data)); // - we write data 
 UnLockFile(f_Position, SizeOf(f_Data)); // - we unlock the file region
 inherited;
end;

But “for my taste” – it is better to make "factory method"

Something like this:

construstor TStorageHeader.InternalCreate(aPosition: Int64);
begin
 inherited Create;
 FillChar(f_Data, SizeOf(f_Data), 0); // - we initialize data
 f_Position := aPosition;
 LoadData(f_Position, f_Data, SizeOf(TData)); // - we read data 
end;
 
class function TStorageHeader.Create(aPosition: Int64): TStorageHeader;
var
 l_H :TStorageHeader; 
begin
 Assert(aPosition >= 0); // - all PRECONDITIONS are transferred from CONSTRUCTOR to FACTORY METHOD
 // Next – we transfer ALL code that POTENTIALLY raises exceptions from constructor to FACTORY METHOD:
 LockManager.LockFile(aPosition, SizeOf(TData)); // - we lock the file region where EXCEPTION can be RAISED - LOCK_VIOLATION
 // - if the exception is raised, it does not come to the constructor (hence – destructor)
 //   and we do not have to raise “flags”
 l_H := InternalCreate(aPosition);
 Result := l_H;
end;
 
destructor TStorageHeader.Destroy;
begin
 SaveData(f_Position, f_Data, SizeOf(f_Data)); // - we write data 
 UnLockFile(f_Position, SizeOf(f_Data)); // - we unlock the file region
 inherited;
end;

I also recommend to read this - BeforeRelease  (in Russian).

The article gives reasons why “saving code” has to be executed before destructing the object.

As for me, it is obvious that the “undestructed object” has to be saved.

It is worth to move all “saving code” from destructor to BeforeRelease (BeforeDestruction (in Russian)).

https://groups.google.com/forum/#!topic/borland.public.delphi.language.objectpascal/d7ajc3wkngY

I quote:

"I just stumbled upon some behaviour of Delphi, which I find pretty
confusing: I prefer using "AfterConstruction" and "BeforeDestruction"
for creating/destroying class members. Now, if an exception is raised in
"AfterConstrucion", Delphi immediately destroys the object (ok so far)
but "BeforeDestruction" is not called (not ok). Online help is not clear
about this, but one could guess that it is *always* called. My
conclusion is: always override "Destroy" instead of "BeforeDestruction"
to safely clean up. Is that right? What's the use of "BeforeDestruction"
then?"

In fact - is ok.

We read documentation:

http://docwiki.embarcadero.com/VCL/2010/en/System.TObject.BeforeDestruction

I quote:

"BeforeDestruction is called automatically before the object's first destructor executes. Do not call it explicitly in your applications."

"Note:  BeforeDestruction is not called when the object is destroyed before it is fully constructed. That is, if the object's constructor raises an exception, the destructor is called to dispose of the object, but BeforeDestruction is not called."

May be it is written in a “florid style” and the problem is made “out of the thin air” (I suppose), but I will be glad if you “rethink” it and find such errors (not simple, though trivial) of your own.

If you do not have them, I am all the more glad for you :-)

I do not want to make anybody "happy by force"  (in Russian) . But what if…

May be, I’ve got “butter fingers” and other people do not have such problems, but it is hardly so.

P.S. One more thing (Briefly. “Why we need tests”  (in Russian)) – the error “lived” for 15 years already. It “poisoned existence”, but did not “prevent from living”.

During this time hundreds (even thousands) of users (internal ones) worked with it.

But!

One should have made tests (Briefly. Load tests have been made  (in Russian) ) – and the error “crept out” at once. Despite the fact that it was found not on “hundreds of clients”, but on two. I repeat, on two… Two but DETERMINED ones.

So, begin to think... About the “extrapolation”  ...

On two...

I’ll just say - “When you tell “I have no time for this”, in fact you mean it is not important for you. No time for self-development? For sport, for family?”  (in Russian).

And also - “Nobody controls a developer, but himself who “slaps on the wrist”. This is not masochism. Instead a developer gets something important - the feel of stability and confidence in his professional future. He develops two times more than usually. He creates, but he does not “plough”. He actually ploughs less  (in Russian).


среда, 18 марта 2015 г.

Briefly. About constructors

Original in Russian: http://programmingmindstream.blogspot.ru/2014/09/blog-post_26.html

Depression  – has “partly” vanished.

Lots of errors have been found.

Particularly – THANKS to NameRec - http://programmingmindstream.blogspot.ru/2014/09/blog-post_23.html?showComment=1411514362019#c1699121675114974966 (in Russian)

Load tests based on GUI-testing have been written.

They emulate the work of real-life users in the distributed system.

On a number of computers.

According to the order:

1. Open a document (out of the predefined list) randomly.
2. Insert “two or three words”.
3. Save it.
4. Close the document.

By the way, the test code:

USES
 QuickTestsUtils.script
;
 
Test TK565491886
 
 ARRAY VAR "Documents list"
 [ Document name ] >>> "Documents list"         
 
 BOOLEAN VAR Eternity
 TRUE >>> Eternity
 WHILE Eternity (
          INTEGER VAR "Random document"
          ( "Documents list" array:Count Random "Documents list" [i] ) >>> " Random document" 
     Parameters: ( "Document from base {("Random document")}" )
     Execute ( 
  "Input the text {('We change the text and save it!!!')}"
  "Press Enter" // - in order to separate documents paragraphs, otherwise they be perceived as “too long” 
  "Save the document"
  "Process the messages" // - to redraw the application
   )
        )
;
 
TK565491886

My tests have been working for three days now.

About 9 Gbs of data has been processed.

I left it for a week-end. We’ll see what we’ll have.

I’ll write a profound analysis of results.

I can tell one thing now – even if function ReadFile has “read something” and returned ReadSize = SizeToRead – “that is not the reason to calm down”. Even if it “read” what it was intended to. Even if the results coincide with the file data.

One should check Result of ReadFile function, the BOOL. Finally, GetLastError.

For example, it can return LockViolation or NetworkBusy.

Trivial. Yeah.

But I’ll write about it “some time later”.

Now I’d like to write about constructors.

Based on:
Link. Getting of resource is initialization (RAII). Some of “my own ideas” (in Russian)
Briefly. Once again about factories
Briefly. Some more “reasoning about RAII”
Briefly. Again about factories
Briefly. About factories
My own implementation of IUnknown and reference counting. And mixins

Why we always need to use FreeAndNil instead of Free (in Russian)  – this one worth a particular and attentive reading, since my thought comes from “the same paradigm”. Virtuality. And descendant classes.

Briefly. For those who don’t like FreeAndNil (in Russian)
Today I’ve got a five-time evidence of the fact that we have to write FreeAndNil instead of Free (in Russian)
Rule 9: Never call virtual functions in constructor or destructor (in Russian)
Virtual functions in constructor or destructor(in Russian)
Gunsmoker wrote about destructors and I want to write about constructors.

And so, here I come.

Usually constructors are written in this way:

type
 TObject1 = class
 end;//TObject1
 
 TObject2 = class
 end;//TObject2
 
 TA = class
  private
   f_SomeObject1 : TObject1;
  public
   constructor Create;
 end;//TA
 
 TB = class(TA)
  private
   f_SomeObject2 : TObject2;
  public
   constructor Create;
 end;//TB
 
...
 
constructor TA.Create;
begin
 inherited Create;
 f_SomeObject1 := TObject1.Create;
end;
 
...
 
constructor TB.Create;
begin
 inherited Create;
 f_SomeObject2 := TObject2.Create;
end;

This “style” is left to us by Borland who deceased in bose.

We have “become used” to it.

What is wrong with it?

Actually, it is “more correct” to write like this:

type
 TObject1 = class
 end;//TObject1
 
 TObject2 = class
 end;//TObject2
 
 TA = class
  private
   f_SomeObject1 : TObject1;
  public
   constructor Create;
 end;//TA
 
 TB = class(TA)
  private
   f_SomeObject2 : TObject2;
  public
   constructor Create;
 end;//TB
 
...
 
constructor TA.Create;
begin
 f_SomeObject1 := TObject1.Create;
 inherited Create;
end;
 
...
 
constructor TB.Create;
begin
 f_SomeObject2 := TObject2.Create;
 inherited Create;
end;

What have we done here?

We have SWAPPED “aggregated objects” initialization and “the call of inherited constructors”.

This is IMPORTANT.

Why?

The key word is - virtuality.

What do I mean?

For now let’s write in this way:

type
 TObject1 = class
  public
   SomeField : SomeDataType;
 end;//TObject1
 
 TObject2 = class
  public
   SomeField : SomeDataType;
 end;//TObject2
 
 TA = class
  private
   f_SomeObject1 : TObject1;
   f_SomeData : Integer;
  protected
   function CalcSomeData: Integer; virtual;
  public
   constructor Create;
 end;//TA
 
 TB = class(TA)
  private
   f_SomeObject2 : TObject2;
  protected
   function CalcSomeData: Integer; override;
  public
   constructor Create;
 end;//TB
 
...
 
constructor TA.Create;
begin
 inherited Create;
 f_SomeObject1 := TObject1.Create;
 f_SomeData := CalcSomeData;
end;
 
function TA.CalcSomeData: Integer;
begin
 Result := SomeAlgorythm1(f_SomeObject1.SomeField);
 // - everything is OK here
end;
 
...
 
constructor TB.Create;
begin
 inherited Create;
 f_SomeObject2 := TObject2.Create;
end;
 
function TB.CalcSomeData: Integer;
begin
 Result := SomeAlgorythm2(f_SomeObject2.SomeField);
 // - we get AV, because on call of CalcSomeData from constructor TA.Create the field f_SomeObject2 is not initialized
end;

What is to be done?

Now let’s write in this way:

type
 TObject1 = class
  public
   SomeField : SomeDataType;
 end;//TObject1
 
 TObject2 = class
  public
   SomeField : SomeDataType;
 end;//TObject2
 
 TA = class
  private
   f_SomeObject1 : TObject1;
   f_SomeData : Integer;
  protected
   function CalcSomeData: Integer; virtual;
  public
   constructor Create;
 end;//TA
 
 TB = class(TA)
  private
   f_SomeObject2 : TObject2;
  protected
   function CalcSomeData: Integer; override;
  public
   constructor Create;
 end;//TB
 
...
 
constructor TA.Create;
begin
 f_SomeObject1 := TObject1.Create;
 inherited Create;
 f_SomeData := CalcSomeData;
end;
 
function TA.CalcSomeData: Integer;
begin
 Result := SomeAlgorythm1(f_SomeObject1.SomeField);
 // - everything is OK here
end;
 
...
 
constructor TB.Create;
begin
 f_SomeObject2 := TObject2.Create;
 inherited Create;
end;
 
function TB.CalcSomeData: Integer;
begin
 Result := SomeAlgorythm2(f_SomeObject2.SomeField);
 // - everything is OK here because field f_SomeObject2 is initialized due to a MORE LATE call of constructor
end;

The problem has gone away.

Is the idea clear? http://programmingmindstream.blogspot.ru/2014/08/blog-post_64.html (in Russian)
I’ll note – “do not tell me about C++ and other languages”. They are organized in a different way http://ptgmedia.pearsoncmg.com/images/9780321334879/samplepages/0321334876.pdf (look at item 9, page 48).

Let me cite:

“It’s not a secret but a simple rule: virtual function is not virtual if it is called from constructor or destructor.

Rules should be learned by heart, which is inconvenient. To undersign the principle is more simple. In this case, the principle is in a cornerstone of inheritance implementation in C++: when creating the object, constructors in the hierarchy are called from base class up to the last inherited one. For destructors it is quite the reverse.

What do we get: class constructor always works with an assumption that descendant classes has not been yet created and, therefore, is has no right to call functions they define. As for virtual function, it has no choice but to call what it itself defines. It turns out that the virtual functions mechanism kind of does not work here. But it actually does not work since the table of descendant class virtual functions has not yet covered the current table.

It is quite the opposite for the destructor. Destructor “knows” that when it is called all the descendant classes have already been destructed and there’s nothing to call from them. For this reason it replaces the address of virtual functions table for its own table address and successfully calls virtual function version, which it itself defines.

So, virtual function is not virtual if it is called from constructor or destructor.”

Virtual functions in constructor or destructor  (in Russian)
That’s speaking about C++ and “other languages”.

BUT!

That is not all about Delphi.

Now, “pair of words” on “where this Borland’s style comes from”.

It “comes” from Turbo Pascal and Turbo Vision.

There constructors Init and the base object TObject were.

However, it had entirely DIFFERENT PARADIGM. I repeat – the PARADIGM. I use Caps Lock for a reason.

Once again I repeat – DIFFERENT PARADIGM.

What was there?

This:

constructor TObject.Init;
begin
 FillChar(@Self, InstanceSize, 0);
end;

Of course, InstanceSize – “looked differently”.

But I believe “the idea is clear”.

What happens with the descendant object?

We’ll write in this way:

type
 TA = object(TObject)
  public
   SomeField : Integer;
  public
   constructor Init;
 end;//TA
 
...
 
constructor TA.Init;
begin
 TObject.Init;
 SomeField := 123;
end;
 
...
var
 A : TA;
begin
 A := TA.Init;
 WriteLn(A.SomeField);
 // - here we get 123
end;

What about a “different paradigm”?

type
 TA = object(TObject)
  public
   SomeField : Integer;
  public
   constructor Init;
 end;//TA
 
...
 
constructor TA.Init;
begin
 SomeField := 123;
 TObject.Init;
end;
 
...
var
 A : TA;
begin
 A := TA.Init;
 WriteLn(A.SomeField);
 // - here we get 0
end;

Is the idea clear? http://programmingmindstream.blogspot.ru/2014/08/blog-post_64.html (in Russian)

“Many people” still “keep thinking” of this PARADIGM. At the same time, they somehow “forget” to call constructor from TObject.

I’ve seen such thing in A NUMBER of third-party libraries.

For example, in ImageEn.

The “discussion” about constructors/destructors, factories  (in Russian)  and"RAII"  – is not fully closed. It has just been opened.

Would you be interested, I’ll follow on it.

But “so far” that is “all I wanted to tell about constructors”.

About “where it came from” - Briefly. About triggering the exceptions

P.S. That is all due to the “one-eyed” architecture”  (in russian), but provides good “motivation for a special talk”.

P.P.S. Actually, the idea за the post was TRIVIAL - either “using of the factories” or “shattering of paradigm” . http://programmingmindstream.blogspot.ru/2014/09/blog-post_26.html?showComment=1412024065216#c6012843482459411429 (in Russian)
Although, “for some” simple “using factories” is already “shattering the paradigm”. Unfortunately.