Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2021-12

Attn: Sven Can not use "specialize" to resolve forward declaration

3 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Martin Frb

https://gitlab.com/freepascal.org/fpc/source/-/issues/39459 You wrote

> No, this can not and this will never work. When a generic parameter

has a constraint that constraint /must/ be adhered to and a forward declaration is /not/ a valid type for such a constraint (except for *class* / |TObject| constraints).

Using TObject for just any class is nice here.

What to use for interface?
https://gitlab.com/freepascal.org/fpc/source/-/issues/39459#note_758496897

Sorry replied on the wrong issue.

How can I restrain a generic param, so it must be an interface, but leave open the exact type, so I can later use a forward declaration?

Reply by email

Sven Barth
to Martin Frb

Martin Frb via fpc-devel schrieb am Do.,
9. Dez. 2021, 00:15:

Show quoted text 18 lines
https://gitlab.com/freepascal.org/fpc/source/-/issues/39459 You wrote >> No, this can not and this will never work. When a generic parameter has a constraint that constraint *must* be adhered to and a forward declaration is *not* a valid type for such a constraint (except for *class* / TObject constraints). Using TObject for just any class is nice here. What to use for interface? https://gitlab.com/freepascal.org/fpc/source/-/issues/39459#note_758496897 Sorry replied on the wrong issue. How can I restrain a generic param, so it must be an interface, but leave open the exact type, so I can later use a forward declaration?

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.

Regards,
Sven

Reply by email

Martin Frb
to Sven Barth

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.

Sven Barth wrote 8 lines
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.

Reply by email