The below might read as if it belongs on the Lazarus list.
But this is not about Lazarus.

This is about a general design idea (pro and con), and the possibilities the language provides.
The example(s) just happen to be from Lazarus.

On 09/12/2021 07:59, Sven Barth via fpc-devel wrote:

For interfaces you can use IInterface/IUnknown though that will work only for COM interfaces. For raw interfaces there is no solution currently.

In my opinion you should rethink your code structure however. I don't know right now what would be better, but as it is now it feels bad.


Well, ok, lets go fishing for ideas.
No rush, this is a loooong time think, no idea when I will really get to it.

Lazarus has a debugger frontend (currently more or less hardcode in the IDE), and several backends (gdb/lldb/fpdebug/....)

The currently provided "interface" (for implementing a backend, that the IDE can talk to) is just code taken from when we had only one backend. However it is some elements, I like to keep. For different data elements (stack,watches,locals) a Monitor/Supplier relation exists.

The backend is the supplier. The frontend the monitor. One think they all have in common. They have a reference to each other. For reasons outside this quest, the design should support multiple Montiors, hence "Add/RemoveMonitor"

The WatchesSupplier takes one or more WatchesMonitor. The WatchesMonitor has one WatcheSupplier. On top of maintaining the relation, there will then be watches specific methods.

So far so good.
https://gitlab.com/freepascal.org/fpc/source/-/issues/39459#note_758496897
represents this idea.

Using interfaces also seems a good idea. It does put the least restrictions on both sides.
Especially each side can still choose it's own base classes.

-------
One more consideration. New methods could be added later. Then all classes implementing the interface must implement them. It would be nice, if a default could be automatically supplied. (if/where such a default exists, e.g. CanFeature = false)

Actually that is possible too. generics
type TWatchesSupplierDef<_Base> = generic class(_Base, IWatchesSupplier) ... end; // having virtual methods for any method of the interface.

That still fulfils the initial requirements. Any implementer of the interface can just mix it into their class structure

------
Now that still works. the problem starts when you want to split the Inteface into a general base, and specifics for the watches/stack/locals.

At that point, the generic type restrictions no longer work.

Why splitting it? I could just repeat the 2 methods in the base? Couldn't I? But, maintaining the list of monitors could be completely implemented in a generic (which later can be included in a monitor/supplier on a optional base).

So, if I do not want to duplicate that code, then I need such a baseclass.

Currently that means giving up on some of the param-type-restrictions.

---------------------
Anyway that is the current background of what I am looking into.
In my opinion you should rethink your code structure however. I don't know right now what would be better, but as it is now it feels bad.

Any better idea?


Btw, if that works, I have a feeling this could replace the LCL interfaces run-time created classes. Afaik it fulfils all the requirements that lead to the current situation.
- Being an interface
- having a default implementation
- allowing to mix default classes and specific classes into a new inheritance structure.



_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply via email to