The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,862 other subscribers

Archive for the ‘Conferences’ Category

If you use an implementation of TNonRefCountInterfacedObject, then document in the descendants how lifetime management is arranged for

Posted by jpluimers on 2021/01/21

There are a few TNonRefCountInterfacedObject (or maybe better named TNonReferenceCountedInterfacedObject) implementations around (see list of links below).

They can be used to expose interfaces, but do not provide interface reference counting. This means you have to do your own lifetime management, which can bring quite a few headaches.

So each class you descend from it must have proper motivation on why, and how lifetime management is performed.

One thing you can do is mark the class with a hint directive like [WayBack] library.

In addition, [Archive.is] TNonRefCountInterfacedObject / [Archive.is] TNonReferenceCountedInterfacedObject implementations should at least implement [WayBack] IInterface (or [WayBack] IUnknown in really old Delphi versions); I have seen implementations that don’t but just provide almost empty [WayBackQueryInterface, [WayBack] _AddRef and [WayBack] _Release methods).

Some examples via  “TNonRefCountInterfacedObject” – Google Search:

Delphi RTL/VLC/FMX

I used this GExperts Grep Search expression to find the entries below: (_AddRef|_Release|QueryInterface)

Delphi itself has a few implementations of non-standard interface management that have good documentation on their use cases. So take a look at at least these before doing something odd with interface implementations yourself:

  • [WayBack] TAggregatedObject in System
    • This redirects all IInterface implementations to a controller
    • It does not implement IInterface itself, so a descendent must add the interface reference
    • Descendants are TContainedObject and TPropertyPageImpl (the latter used by TActiveXPropertyPage)
  • [WayBack] TContainedObject in System
    • This redirects all IInterface implementations except QueryInterface to a controller
    • Descendants are for instance TSOAPHeaders (via TSOAPHeadersBase) used by TSoapPascalInvoker, TInvokableClass and TRIO, and TConnectionPoint used by TConnectionPoints
  • [WayBack] TInterfacedPersistent in System.Classes
    • This supports the notion of (potentially) being owned by another TPersistent. Classes like TCollectionItem, TFieldOptions and TEditButton implement this ownership behaviour.
    • When owned, then redirect reference counting to the owner (if that owner implements IInterface), but not QueryInterface
    • When not owned, then it is effectively non-reference counted
  • [WayBack] TComponent in System.Classes
    • This supports the notion of (potentially) being owned by another TComponent. Classes like TComponent and TCollectionItem implement this ownership behaviour.
    • When owned, then redirects all IInterface calls to the owner (including QueryInterface).
  • [Archive.is] TXPEditReaderStream in DUnit XP_OTAEditorUtils. It is largely undocumented.
  • TXPInterfacedObject in DUnit XPInterfacedObject. It is largely undocumented too.

Not so good examples:

  • [WayBack] TCustomVariantType in System.Variants (which is basically TSingletonImplementation with a lot of extra methods)
  • [WayBack] TSingletonImplementation in System.Generics.Defaults(which is basically what most TNonRefCountInterfacedObject implementations do; this is sort of OK as it is meant to be used only in [WayBack] TCustomComparer<T> and descendants that are supposed to be singletons).
  • IUnknown in Winapi.Ole2 (this whole unit is undocumented; the class only has virtual abstract methods; the unit – together with Winapi.OleCtl – seems to be only meant to support the depcrecated Vcl.OleAuto unit.)

And of course there is the standard implementation with proper multi-threading support:

There are quite a few classes that implement reference counting while descending from things like TComponent, usually without the proper multi-threading support that TInferfacedObject has:

Read the rest of this entry »

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development | Leave a Comment »

Don’t use global state to manage a local problem – The Old New Thing

Posted by jpluimers on 2021/01/20

The 20081211 article [WayBack] Don’t use global state to manage a local problem – The Old New Thing reminds me of a process I went through with a programming team a few years ago.

A lot of their source base came from the procedural era: global variables and global methods. No classes. No methods on records.

Taking them to the level of reference counted immutable instances that used dependency injection as an architectural design was a long journey.

Early in their journey, they would create a lot of methods on classes and records at the class level.

Then they started introducing instances that were basically singletons.

Finally they made real instances that could have more than one available at run-time. These would still create other instances when they needed, often through a few singletons that were still left (for instance session state, database connection state, etc).

Then they introduced caches and pools to keep things alive longer than as to speed up things. It also highly complicated life-time management.

Finally they backed down, and started hooking up things through dependency injection.

A lot of the above caused global state to be used for solving local problems.

It was a tough, but fun time, to get them on the right path, tickling them with the right puzzles at the right time to steer them through their journey..

–jeroen

Posted in Conference Topics, Conferences, Development, Event, Software Development | Leave a Comment »

GitHub – pierrejean-coudert/delphi-libraries-list: List of Delphi Libraries and Frameworks

Posted by jpluimers on 2021/01/14

For my link archive: [WayBackGitHub – pierrejean-coudert/delphi-libraries-list: List of Delphi Libraries and Frameworks

–jeroen

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development | Leave a Comment »

The difference between thread-safety and re-entrancy – The Old New Thing

Posted by jpluimers on 2021/01/13

Just in case I need a nice example about the difference: [WayBack] The difference between thread-safety and re-entrancy – The Old New Thing.

It has both that and the definition:

An operation is “thread-safe” if it can be performed from multiple threads safely, even if the calls happen simultaneously on multiple threads.

An operation is re-entrant if it can be performed while the operation is already in progress (perhaps in another context). This is a stronger concept than thread-safety, because the second attempt to perform the operation can even come from within the same thread.

–jeroen

Posted in Conference Topics, Conferences, Development, Event, Software Development | Leave a Comment »

Want to use SmartPointers in Delphi? Use the Spring4D one: it is unit tested and optimised

Posted by jpluimers on 2021/01/06

A while ago, there was a nice discussion on smart pointers at [WayBack] Smart Pointers – Generics vrs non-generic implementastion – RTL and Delphi Object Pascal – Delphi-PRAXiS [en].

Conclusion from that:

  • many people think that reference counted interfaces are the same as Smart Pointers
    (basically Smart Pointers are the next level and of course they are based on reference counting)
  • there are a lot of Smart Pointer implementations, but few have a test suite, nor are optimised , nor easy to use
  • The combo Shared/IShared<T>/TShared<T> from Spring4D has all of the above advantages
  • in order to optmise Smart Pointer implementations, you really have to well know the effects of modern Delphi language constructs on the compiler in various target platforms

The discussion mentioned above includes both feature and speed comparisons.

I was a bit amazed that at CodeRage 2018, Marco Cantu introduced yet another smart pointer implementation: one worse than existing implementations, and one with only basic demonstration code, leaving out a test suite.

There have many posts on my blog about smart pointers (see the list below), but Spring4D smart pointer implementation has been around for such a long time that any well respected Delphi developer by now should use them. The source is at  Shared/IShared (search for {$REGION 'Shared smart pointer'} at the current repository).

This list below on my Smart Pointer related blog posts might not be fully complete, but at least mentions that by now you should be using Spring4D.

Some comments on the CodeRage 2018 demos

Read the rest of this entry »

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development, Spring4D | Leave a Comment »

Delphi processing all Windows messages

Posted by jpluimers on 2020/12/30

Since I had captures messages inside the main message loop, I forgot it is straightforward: create a [WayBackTApplicationEvents instance, then use the [WayBackOnMessage event and hook it to a method like

procedure TMainForm.ApplicationEventsMessage(var Msg: TMsg; var Handled: Boolean);
begin
  // figure out if the TMsg should be handled; set Handled to True if you do not want it to be processed by your application any further
  // if you do not handle it: bail out as quickly as possible
  // for performance reasons, it might be wise to have only the decision in this method, and all actual handling (including any managed variables) inside another method.
end;

Capturing these messages is limited to the ones processed through the main message loop (or message pump): these are the asynchronous ones either put there by PostMessage or related functions (like PostQuitMessage), or generated by Windows.

This means you will not see any synchronous messages sent to specific Windows using SendMessage.

Unlike the documentation for the OnMessage event, the type inside the method is TMsg from the unit  [WayBack]WinApi.Windows, which is an alias for the (documentation mentioned) tagMSG in the same unit; neither type is documented at docs.embarcadero.com or docwiki.embarcadero.com. Luckily, it is documented in the Windows SDK as the structure [WayBacktagMSG.

That structure is not the same as the [WayBackTMessage type inside the unit WinApi.Messages [WayBack], as TMessage omits these fields from TMsg:

  • HWND hwnd;
  • DWORD time;
  • POINT pt;
  • DWORD lPrivate;

Luckily the [WayBack] TMessageEvent (that describes the type of the signature of the event method) is better in this regard:

TMessageEvent = procedure (var Msg: TMsg; var Handled: Boolean) of object;

TMessageEvent includes the following parameters:

  • Msg identifies the Windows message that triggered the event.
  • Handled indicates whether the event handler responded to the message. If the event handler sets Handled to True, the application assumes that the message has been completely handled and halts any subsequent processing of the message.

TApplicationEvents is actually a multi-cast component (one of the very few multi-casting things parts of the Delphi VCL): an undocumented TMultiCaster class inside the unit Vcl.AppEvnts [WayBack].

A bit reminder though: ALL queued (not sent!) Windows messages flow through this method, so make it as short and efficient as possible, so from the OnMessage documentation:

OnMessage only receives messages that are posted to the message queue, not those sent directly with the Windows API SendMessage function.

Warning: Caution:Thousands of messages per second flow though this event. Be careful when coding the handler, because it can affect the performance of the entire application.
Tip: Call the CancelDispatch method from an OnMessage event handler to prevent the application from forwarding the event to any other application events objects.
It took until Delphi 2010 for the method [Archive.isTCustomApplicationEvents.CancelDispatch to be documented:
Prevents other TCustomApplicationEvents objects from receiving the current event.

A few more relevant links if you want to also hook SendMessage based messages:

Read the rest of this entry »

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development | Leave a Comment »

Essential versus Accidental Complexity: 2 minute Kevlin Henney video and some links

Posted by jpluimers on 2020/12/24

The topic is as old as the 1986 “No Silver Bullet” book, still relevant, but few people are consciously aware of the difference of these fundamental ideas:

Essential versus Accidental Complexity

TL;DR:

  • Essential complexity is the problem you try to solve
  • Accidental complexity is the problems you have created while solving

The first is what it is all about (it is in your problem domain, and not reducible); the second is what you want to minimise, like technical debt, size effects of quick fixes, bad tool/framework/language choices, long feedback loops.

2 minute video:

Related:

Via:

–jeroen

Read the rest of this entry »

Posted in Conference Topics, Conferences, Development, Event, Software Development | Leave a Comment »

How to debug Delphi JSON export stack-overflows: watch the fields and their circular references

Posted by jpluimers on 2020/12/23

Unlike Delphi RTL XML support which is property based, the JSON support is field based.

By default, JSON uses all fields (no matter their protection level, so anything from strict private to published  is taken into account).

When there are cycles, they are not detected: it will just stack-overflow with a high set of entries like this:

REST.JsonReflect.{REST.JsonReflect}TTypeMarshaller.MarshalSimpleField($788BFB40,$78AB0150)
REST.JsonReflect.{REST.JsonReflect}TTypeMarshaller.MarshalData($78AB0150)
REST.JsonReflect.{REST.JsonReflect}TTypeMarshaller.MarshalValue((($A9B7E8, Pointer($AFE168) as IValueData, 80, 336, 2024472912, $78AB0150, TClass($78AB0150), 80, 336, 2024472912, 2,77471682335019e+34, 1,00022251675539e-314, 0,00000000737961e-4933, 2024472912, 202447,2912, 2024472912, 2024472912, ($78AB0150, nil), $78AB0150)),???)
REST.JsonReflect.{REST.JsonReflect}TTypeMarshaller.MarshalSimpleField($78A921D0,$78AA69C0)
REST.JsonReflect.{REST.JsonReflect}TTypeMarshaller.MarshalData($78AA69C0)
REST.JsonReflect.{REST.JsonReflect}TTypeMarshaller.Marshal(???)

The easiest way to debug this is to:

  1. Set breakpoints in procedure TTypeMarshaller<TSerial>.MarshalData(Data: TObject);
    1. First breakpoint on the for rttiField loop
      • Watch or log these values (the first two usually are the same, the last two too):
        1. ComposeTypeName(Data) which gives you the fully qualified name (including unit and class) of the type exposing the fields
        2. Data.ClassName as a sanity check
        3. rttiType.Name which should be the same as Data.ClassName
    2. Second breakpoint inside the for rttiField loop on the if not ShouldMarshalstatement
      • Watch or log these values:
        1. rttiType.Name inside the loop, it changes value to match rttiField.Name, because of a debugger bug not showing it as E2171 Variable 'rttiType' inaccessible here due to optimization.
        2. rttiField.Name the actual field name

Tricks to circumvent circular references:

  • remember that fields with a reference to function value are not marshaled, so they are an excellent way of shoehorning in a dependency in (the reference value will be a capture which includes the instance data of the function to be called)
  • applying a [JsonMarshalled(False)] attribute (be sure to use unit REST.Json.Types!) only works when used inside non-generic types:
    • a class like TMySoapHeaderValue<T: IInterface> = class will not expose these attributes
    • a class like TMySoapHeaderValue = class will expose these attributes

You can check the JsonMarshalled problem by setting a breakpoint inside function LazyLoadAttributes(var P: PByte): TFunc<TArray<TCustomAttribute>>; on the line Exit(nil); and watch the value for Handle^.

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development | Leave a Comment »

I really wish people reporting bugs provide more factual details, especially when asked for

Posted by jpluimers on 2020/12/15

Basically the below thread goes like this: [WayBack] GExperts / Bugs / #92 Grep cannot handle UTF-16 and UTF-32 pas files

  1. There is a bug in UTF-16 and UTF-32 handling in your tool when running under AAA, but  not when running your tool under BBB; these files fail: xxx.txt  and yyy.txt
  2. Which version of our tool did you run under AAA and which version of our tool did you run under BBB
  3. It fails with your tool when running under AAA , but succeeds under BBB
  4. Repeat at step 2 until you fall asleep.

Part of the [WayBack] Short, Self Contained, Correct Example are indeed in it, but without more details it is hard to reproduce.

So without the reporter providing those details, nobody, especially not on open source projects, is going to fix it just on that bug report.

Via: [WayBack] It’s time for a gift to all Delphi developers, a new Release of GExperts. Happy Holidays! (But do spend some time with your family rather than testing G… – Thomas Mueller (dummzeuch) – Google+

Which highlights another conceptual problem from the same bug reporter: expecting a new version to have a regression of all open bugs against the new version.

That’s not how the world works, if it has ever worked that way. If your issue is not mentioned in any release notes, then assume nothing happened. If you want to bump it up, then provide more details.

–jeroen

Posted in Conference Topics, Conferences, Development, Event, How to report bugs, Issue/Bug tracking, Software Development | Leave a Comment »

In Delphi, avoid having a TComponent descendant implement interfaces, unless you are prepared to handle your refcounting

Posted by jpluimers on 2020/12/15

Every now and then I see code, where a class descending from TComponent implements some interfaces, only interface references are used to the instances, and the expected behaviour is that the instances will free themselves when all the references went out of scope.

Bummer: TComponent by default is not reference counted.

It is when you assign VCLComObject an IVCLComObject which is hell to implement (Delphi provides two of them: TVCLAutoObject and TActiveFormControl. They sound heavey, and are).

Do not go that way. If you need some form of ownership in a class implementing an interface, then descend the class from TInterfacedObject, and add a field of TComponent that is the owner of things that need to be freed later on. In the destructor, free that field.

Something like this:

unit InterfacedObjectWithRootUnit;

interface

type
   TInterfacedObjectWithRoot = class(TInterfacedObject)
   strict private
      FRoot: TComponent;
      function GetRoot: TComponent;
   strict protected
      property Root: TComponent read GetRoot;
   public
      destructor Destroy; override;
   end;

implementation

destructor TInterfacedObjectWithRoot.Destroy;
begin
  if Assigned(FRoot) then
  begin
    FRoot.Free();
    FRoot := nil;
  end;
  inherited Destroy();
end;

function TInterfacedObjectWithRoot.GetRoot: TComponent;
begin
  if FRoot = nil then
    FRoot := TComponent.Create(nil);
  Result := FRoot;
end;

end.

–jeroen

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development | Leave a Comment »