Jump to content
Erik@Grijjy

Automate Restorable Operations with Custom Managed Records

Recommended Posts

It is not obvious to me what is the advantage in respect to using an interface-based (or custom variant-base) instance holder.
You can auto-generate the same try/finally hosting the data within an interface, or a custom variant. Since the oldest Delphi revisions.

Interfaces can host regular objects with no problem. A custom record may be slightly faster, by allocating its memory on stack and not on heap - but performance is not the main point here, this is about code writability - less source lines, more hidden behavior.

 

Share this post


Link to post

@Arnaud Bouchez Wait until the next great articles from Erik will arrive, more closer towards the C++ SmartPointer ecosystem.

The advantage: its a linear, simple, local record, no ref-counting issues, no TInterfacedObject hazzle.

Yes, long waiting for such thing, and it seems Delphi can do it now.

ProbablyI need to make some first tests soon.

Edited by Rollo62

Share this post


Link to post
Guest

Without "inline vars" it would become almost as dangerous as with. With them, ok... less typing. I try to refrain from copy-pasting code, but... well it's logged deep down in the back of my spine 😞

Considering readability, copy-paste "safety", you could argue it's the same with interfaces... sure, but you can effortlessly write "instance = nil" for "explaining".

I dunno... using things that "go out of scope" is intimately understood, so i might be out on another discourse here.

Anyhow;

procedure Name;
begin
  STUFF

  BU
  try
    DO!
  finally
   EU
  end;

  STUFF
end;

 

procedure Name
begin
  STUFF

  begin
    var magick = TMagic.Create(...);
    DO!
  end;

  STUFF
end;

If we could do JS-like stuff and omit the "var magick ="-part then it would look more clean.

Also, i am trying to name my records RWhatever instead of TWhatever more often. Maybe the CRM's constuctor should have a different name; RMagic.Instatiate().

In this context i would find it a plus because it indicates automatic management (scope).

 

Bottom line, i tend to agree with @Arnaud Bouchez in this case though i generally agree with @Rollo62 that @Erik@Grijjy's blogs is a goldmine!

 

????

 

/D

Share this post


Link to post

I guess it is also a matter of taste.

It took a while for me to get used to the "aesthetic" of inline variables, but now I love them (especially with type inference) and can't imagine why I had an aversion against them.

 

I have seen this type of CMR in C++ code so much, that I got used to it and started to miss it in Delphi (until now). Now, I actually think it improves readability and safety, although I can imagine people feel the opposite. (For some reason, I tend to write "Mutex.Free" in finally parts instead of "Mutex.Release" to leave a lock, because of the muscle memory of freeing stuff inside of finally blocks. With CMRs, this kind of mistake is not possible😉).

 

An yes, coding conventions can help improve readability. The name Create for a constructor has an association with classes for many people. Calling it something else (like Instantiate) could help, as would turning it into a static class function instead of a constructor.

 

As with many things, there are often many solutions to a problem. A CMR is just an additional tool in your toolbox...

Share this post


Link to post

The current implementation of CMRs is full of lost opportunities:

 

In C++ you can prevent copy/assignment simply by removing the copy/assign operator and it will not compile if you try - in Delphi we have to use runtime exceptions, yugh...

 

In C++ you can directly access members on a unique_ptr or shared_ptr because you can override the * and -> operator - in Delphi you have to make some property to access the wrapped object.

 

Oh, and thank you CMRs for making my code slower which does not even use them!

  • Like 3

Share this post


Link to post

@Stefan Glienke I agree that the implementation is lacking and would like to see a more C++ like implementation. And it would be great if you could overload the "." or "^" operator.

 

That being said, the current implementation still has its uses...

Share this post


Link to post

Maybe all these nice improvements could still be added in CMR V2.0 🙂

 

Only the choice of ".Create" was not so good indeed, and this could be changed similar to custom constructors in classes.

Where then there is the default Create constructor still dangling around.

Would be maybe a good idea to add an additional accessibility control, like "hidden, private, protected, public", to hide away Create at compile time,
instead of e.g. dirty-hack away the access to Create constructor in classes
(although I dislike such basic changes in a language, but such addition would not harm any existing code).

Maybe that would make records and classes even more compatible (not sure if that is for good or bad, maybe depends on the viewer).

 

Edited by Rollo62

Share this post


Link to post

Side note: see for instance the ProtectMethod use of https://synopse.info/files/html/Synopse mORMot Framework SAD 1.18.html#TITLE_57 which is similar.

 

What I miss with records is inheritance.
Static inheritance, I mean, not virtual inheritance.

This is why I always like the `object` type, and find it weird that is deprecated and buggy since Delphi 2010...

Check https://blog.synopse.info/?post/2013/10/09/Good-old-object-is-not-to-be-deprecated-it-is-the-future almost seven years ago... already...

 

I tend to search for alternatives not in C++, where alternate memory models were added later on - as with Delphi.
But in new languages like Rust which has a new built-in memory model. Rust memory management is perhaps the most interesting/tricky/difficult/powerful/promising (pickup your own set) feature of this language.

Both C++ and Delphi suffer from the complexity of all their memory model. COW, TComponent, interface, variant, new/dispose, getmem/freemem, create/free... it may be confusing for newcomers. My guess is that 80% of Delphi RAD users seldom allocate manually memory (just for a few TStringList), and rely on the TComponent ownership and visual design.
At least they removed ARC from the landscape! 🙂

 

CMR is a nice addition - which FPC featured since some time, by the way...
We still need to check the performance impact of this initial release - writing efficient RTL was not the main point of Embarcadero these latest years. I hope it won't reduce regular record/class performance. 

Edited by Arnaud Bouchez
  • Like 2

Share this post


Link to post
5 hours ago, Arnaud Bouchez said:

CMR is a nice addition - which FPC featured since some time, by the way...

Have not checked CMR yet, neither Delphi nor FPC.

Are the implementatons compatible at least, or is this FLP CMR a completely different animal ?

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×