Jump to content
Sign in to follow this  
FPiette

On the use of Interposers

Recommended Posts

44 minutes ago, Rollo62 said:

What is your opinion, about when to use interposer classes, and when better avoid it ?

In the context of this subject, an interposer class is a bad solution. An inherited class is the correct way.

 

In general, I avoid as much as possible interposer class. I think this make code more obscure. But not everyone share my opinion and that's OK.

Share this post


Link to post

Interposer classes are only good for components/controls that you already placed on forms because you can keep using them as is while you would need to replace a lets say TButton with TMyAwesomeButton.

Where I also like to use them is for extending DUnit as I can use my unit with the TTestCase class then instead of the DUnit one and add functionality - but I would stay away from using it on RTL classes.

 

Funny story: just yesterday we had a sudden compile error from a unit that was not touched in months. A class that was implementing an interface and the compiler complained about missing 2 method implementations.

Turned out it was caused by the fact that a junior had added a TAction interposer class into a form unit. That unit was used in the unit which now failed - because those interface methods had TAction in their signature and now they did not match anymore.

Edited by Stefan Glienke
  • Like 1

Share this post


Link to post
Guest
48 minutes ago, Rollo62 said:

What is your opinion, about when to use interposer classes, and when better avoid it ?

The ONLY (IMHO) reason to go "interposer" is when you want the benefits of OOP without the hazzle of having the IDE "follow" (e.i. install a package).

In other words, if you are writing a package, framework or some such you have no problem inheriting 'ala OOP.

The "interposer" thingy is just a way to use inheritance without the whole package-thingies.

So - why?

1. As mentioned, if you derive from 3rd party libs, putting that into a package can become cumbersome when the 3rd party lib has an update.

2. If you absolutely do not want to create a package to inherit. Like if you are publishing an OS project and want the "audince" to be able to compile "right away".

The problems with interposing are at least;

1. You MUST keep track of the order items in ALL your uses clauses. The IDE adds a unit and you have to re-arrange. In every unit.

2. As mentioned above - it's not very readable. At hand; we have begun to call it "interposer".

3. A lot of small "recurrent" programming error will be much harder to pin down when the project grows.

4. Let's just ... wait for it 🙂

 

Please, do not start thinking from "interposer"... start thinking OOP and inheritance.

Share this post


Link to post
2 hours ago, Rollo62 said:

But as always I ask myself, if its worth a separate class, or would it be better to have an interposer class for the new functionalty.

I doubt it. In this very case most of these features are specific for editor application. Others won't even notice troubles.

Share this post


Link to post
Guest
2 hours ago, Rollo62 said:

What is your opinion, about when to use interposer classes, and when better avoid it ?

I hate them but use them, they very helpful in building a house of cards, the quality and stability of your project become in question as they accumulate.

 

Mostly i use them when researching or testing an idea for results before wasting time on the original classes, for me using them then leaving them in production is like delaying what need to be done, the inevitable.

 

Edward Young : "Procrastination is the thief of time

Share this post


Link to post

I generally only use interposer classes to fix vcl/rtl issues where I'm using runtime packages.. and then only very carefully - generally in a file that is a folder like VclFixes and where the filename would be something like Vcl.Forms.RSP1234.pas - it's hard to miss that you are using a patch/hack and makes it easier to review when upgrading delphi versions (ie do I still need this file). 

 

The other time I have used them is when messing with the IDE and don't have the IDE source code 😉

  • Like 1

Share this post


Link to post
16 hours ago, Kas Ob. said:

I hate them but use them, they very helpful in building a house of cards, the quality and stability of your project become in question as they accumulate.

I don't see any stability issues, thats why I carefully added more and more interposers with such fixes.

 

But what would be the alternative, to have a separate layer of self-defined components, on top of the existing ones.

That would basically do the same job as the interposers, but would cause a LOT more trouble in designing the forms.

 

Maybe it depends much on how your current workflow is.
I mostly use component designer for fast (RAD) visual definitions, a few Events maybe for early testing sometimes,
but mostly I do the coding via interposers and their wrapping around events, by adding their own anonymous methods.

That way RAD is for design, and interposers serve for easy to use runtime coding the business logic.

 

I agree this gets maybe difficult when it comes to BPL, DLL, etc., or binding statis DCU from other sources.

Happily I don't have to do that, but if you work a lot with 3rd party components I would be more careful.

Even then, when you keep your units capsulated from external DCU, that should be still OK, only the mixing might crash.

I also try to divide my units into smallest possible fractions, to ensure that de-coupling (which not always works that easy).

 

 

Share this post


Link to post
7 minutes ago, Rollo62 said:

But what would be the alternative, to have a separate layer of self-defined components, on top of the existing ones.

Yes.

 

7 minutes ago, Rollo62 said:

That would basically do the same job as the interposers, but would cause a LOT more trouble in designing the forms.

No, it's no trouble at all.

  • Like 1

Share this post


Link to post

@David Heffernan

More trouble means I have to make all these components work in the designer now, I think there is no neat trick w/o registering them.

Also they are no more compatible classes, which could be used as "Xyz is TButton".

Edited by Rollo62

Share this post


Link to post

We use interposers or wrapper classes to populate third party components such as the grid, list and combo controls from TMS.

 

It started with us having hundreds of grids, and to get a normalized look, it was better to use a wrapper class to set them up, than to manually configure each class in each form. This class eventually evolved into several wrappers, most of them being data-aware so that we had unified ways of populating a grid, list or combo - straight from SQL, from object lists, or direct fill from "hard code", as well as handling selection events, etc.

 

Another benefit is that if TMS should happen to make changes or add features - we only need to deal with it in the wrappers.

 

 

Share this post


Link to post
11 minutes ago, Lars Fosdal said:

We use interposers or wrapper classes to populate third party components such as the grid, list and combo controls from TMS.

 

It started with us having hundreds of grids, and to get a normalized look, it was better to use a wrapper class to set them up, than to manually configure each class in each form. This class eventually evolved into several wrappers, most of them being data-aware so that we had unified ways of populating a grid, list or combo - straight from SQL, from object lists, or direct fill from "hard code", as well as handling selection events, etc.

 

Another benefit is that if TMS should happen to make changes or add features - we only need to deal with it in the wrappers.

I would never use interposer classes for that but simply run a one time search and replace for all occurences of the third party controls with my own.

Share this post


Link to post

@pyscripter  Thank you for that, it's extremely useful!  I'd like to add that Microsoft has changed their encoding standards in the new NotePad.  I mention this because our current Delphi TEncoding names are from the original standard.  The new standard is:

 

ANSI
UTF-16LE
UTF-16BE
UTF-8
UTF-8 with BOM

 

Which seems an improvement over just using "Unicode" for UTF-16LE.  Also saves default to UTF-8 (without BOM) instead of ANSI, for good or bad (I *think* good, but I bet there are other opinions!)

 

 


 

Share this post


Link to post
1 hour ago, Rollo62 said:

@David Heffernan

More trouble means I have to make all these components work in the designer now, I think there is no neat trick w/o registering them.

Also they are no more compatible classes, which could be used as "Xyz is TButton".

You just put them in a designtime package, install it, and then use them. That's what I do. I don't find it at all onerous.

  • Like 1

Share this post


Link to post
19 minutes ago, David Heffernan said:

You just put them in a designtime package, install it, and then use them.

Design time packages can be a PITA when you often switch source code versions affecting those components. 

  • Like 2

Share this post


Link to post
3 minutes ago, Uwe Raabe said:

Design time packages can be a PITA when you often switch source code versions affecting those components.

Please elaborate.

Share this post


Link to post
19 minutes ago, Uwe Raabe said:

Design time packages can be a PITA when you often switch source code versions affecting those components. 

That's true of course, but the problem arises the moment you use a single third party component.

Share this post


Link to post
32 minutes ago, Uwe Raabe said:

Design time packages can be a PITA when you often switch source code versions affecting those components. 

If you are referring to switching between different versions of them I can only suggest putting those (yes the binaries, so dcu, dcp, bpl) into vcs - git lfs for example does a fine job.

Share this post


Link to post
Guest
2 hours ago, Rollo62 said:

I don't see any stability issues, thats why I carefully added more and more interposers with such fixes.

We developer and we tend to forget over time, the problem raises from the update, so here two problems i faced and both in VCL, (both situations can be expanded to RTL too)

1) An application was crashing on some clients PC's and EurekaLog pointing to specific code in 3rd-party library to be exact it in password input, the application is mine and i wrote it over years, spend hours trying to understand why some clients ( very few but not one and very rare like happens once in a week) that reported the log, after months i found it and it was an imposter class created compatibility issue after updating the password input ( from the 3rd-party) to allow using copy and paste (and few other tricks) , removed it and the AV was never seen again, i also in that time wasted the 3rd-party provider time by asking how and why this EurekaLog was reporting the AV in their code ! :classic_blush:

 

2) bad flickering in Listview and GridView after moving to newer Delphi version, i didn't see it but clients started to complain about flickering when certain types of data, couldn't reproduce, it was the imposter, this wasn't my code or my application, it did not take relatively long time as the first example as i was suspicious about everything there, yet it can be considered long time to be found and fixed, when browsing the code it easily can be missed in big and huge unit files, the root was with custom draw and when the original author was using non-virtual and later switched to virtual, leaving the imposter there.

 

1 hour ago, Lars Fosdal said:

It started with us having hundreds of grids,

Hundreds !, That is a reason to build and extend the original grid for your custom usage, a number on two finger is enough for me to build my own and add it as design-time package, in many cases i use imposter class to check and see the result, when satisfied then it is green light to waste time on.

 

I also have TListView extended into (TListViewEx ,TListViewEx2 ,TListViewEx3mini, TListViewExFineColor...) where i don't want to use the custom draw events for each and every one, also in that way no more copy and paste code in those events while supplying the custom colors 😎, i do this also for AlphaSkins controls and other non-vcl 3rd-party like SecureBlackBox as those settings as not optimal by default and instead of configuring each time and try not to miss or forget something, i have them configured and ready to be used, yes imposter can do it but extension is rock-solid, so even when i want to play with something i still can use very beautiful components, and correctly configured.

 

And not always you need extend and add to design time, just extend them so when bugs raises the report will be accurate and the code is isolated in specific places, or when you want to compare the default behaviour when your application is behaving differently.

 

(on side note try to add TMemo with empty lines and vertical scrolls enabled with anchors all true, after that you will never click on the default one)

Share this post


Link to post
49 minutes ago, Stefan Glienke said:

If you are referring to switching between different versions of them I can only suggest putting those (yes the binaries, so dcu, dcp, bpl) into vcs - git lfs for example does a fine job.

Yes, but that is not causing the PITA I was talking about. When you switch one of these bpl files (even with vcs) it requires to unload the design time package from the IDE and load the changed one afterwards.

 

In case these packages are part of the current project group it might as well be convenient to recompile those packages after the switch, which will do the unload-load internally.

  • Like 1

Share this post


Link to post
18 minutes ago, Uwe Raabe said:

it requires to unload the design time package from the IDE and load the changed one afterwards.

Correct, that's why you close the IDE before you switch the branch

Share this post


Link to post

If I did the my own component approach - I would need multiple versions of the design time components to deal with the different methods of feeding data to the controls, and every time I upgraded TMS, or made a change to the wrapper, I would have to rebuild them.  Since the wrapper code is continuously evolving - switching between Live, Pilot and Trunk would be very cumbersome if I had to swap the components used as well.

 

Since the data side of the wrapper is not linked to visual code and the events are connected to the wrapper and not the component, it is easy to write non-visual test code that can simulate UI events.

 

Custom components are an option, but. I personally prefer the wrapper approach.

Share this post


Link to post
15 minutes ago, Fr0sT.Brutal said:

And again the topic has turned to some other direction 😉 

Topic splitting can easily done by mods. Personally I would welcome if this was done more often so different things can continue being discussed in their own threads.

Edited by Stefan Glienke
  • Like 1

Share this post


Link to post

@Lars Fosdal

Well thanks for that.

 

One more argument for me, why I'm thinking of even TStringList as interposer:

I NEED a real good TStringList, doing all the basic jobs.

 

I really don't like to have  a  TStringListF for right file handling, a TStringListS for right stream handling, a TStringListKV for right Key/Value handling.

This is too much name cluttering for my taste, and usually not very necessary to me,

better to have one TStringList that fixes it all, and provide all basic, COMPLETE functionality.

Most issues I have that classes don't were designed completey, and important parts were missing.

 

I hope you get my point, just my 2 cents, why I think of interposers more than I should.

 

And yes, we can derive a TStringListEx from TStringList, as the new and only perfekt child (maybe).

 

 

Edited by Rollo62

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
Sign in to follow this  

×