[lazarus] compile error on New Sources from cvs - FIXED

Mattias Gaertner nc-gaertnma at netcologne.de
Thu Nov 27 16:09:09 EST 2003


On Thu, 27 Nov 2003 21:38:25 +0100  Micha Nelissen
<M.Nelissen at student.tue.nl> wrote:

> Mattias Gaertner wrote:
> 
> > On Thu, 27 Nov 2003 19:22:37 +0100  Micha Nelissen
> > <M.Nelissen at student.tue.nl> wrote:
> > 
> > 
> >>Mattias Gaertner wrote:
> >>
> >>
> >>>By using the the uses section in the implementation section you created
> >>>some circles. This is allowed, but it makes the code harder to
> >structure>>and less readable. They are allowed, but IMO you should try to
> >avoid>>them.
> >>
> >>I find the current approach less readable: extra units (menutype in this
> >
> >>case), extra definitions (TBaseMenuItem), unnecessary casting from 
> >>TBaseMenuItem to TMenuItem, while we know it is a TMenuItem. 
> > 
> > 
> > see below
> > 
> > 
> > 
> >>IMHO, the 
> >>interface hierarchy is like this:
> >>
> >>high - lcl (delphi compatible) interface
> >>      - generic platform independant interface
> >>      - lcl itself: controls, stdctrls, etc.
> >>low  - lcl type definitions
> > 
> > 
> > I think we are talking about the same thing. Maybe a little bit more
> > clear:
> > 
> > interface
> >  .. uses ..
> > LCL
> >  .. uses ..
> > interface base
> >  .. uses ..
> > base types
> > 
> > IMPORTANT:
> > In the following context, the "LCL" is the lazarus component library.
> > That means the OO components and not the interface functions. 
> > 
> >>From the user point of view this is the top level part, while the
> >interface
> > functions are the add ons, that are only used, if there is no LCL
> > component to handle the task. In other words: The LCL wraps the
> > interface in an object pascal way. 
> > 
> > For example: The user should never use the LCLCheckMenuItem. For the
> > user this is a low lvl function. The LCL delegates and controls the
> > interface. So, the interface base is below the LCL.
> > 
> > Our trick is, that the actual implementations of the interface (gtk,
> > win32) overrides the interface base. And because the user does not use
> > the real interface, we have the choice to put it wherever we want in the
> > hierachy. And the easiest position for the implementation is above the
> > whole LCL and its base. That's why we can use TMenuItem in the win32
> > intf. This is only because of its hideous character. If we would use a
> > perfect OO design, the implemented interface would ly right on the
> > interface base and would not know the LCL. 
> 
> You've made a good point here. However it has problems:
> 1) It assumes that all interfaces need the same information for doing 
> the same thing, so we can pass exactly that information. This assumption 
> is false as proven by recent CheckMenuItem. If, and I hope when, the qt 
> interface is going to be implemented it may need other kinds of 
> information currently not passed through the parameters.

I never assumed, that we pass all needed information as direct params. Only
the needed information. The interface just need a menu component and can
retrieve the rest. For example: By passing a TMenuItem instead of a
TBaseMenuItem, the gtk interface does still not have all the information it
needs. But it can retrieve the rest. So, replacing this parameter type, will
only save a few lines of code in the win32 intf.


> 2) All these calls should be reported back. So CheckMenuItem not only 
> checks the menuitem in the interface, but it should also report back to 
> the lcl that it has checked the menuitem.

.. and the LCL will check and react and call the interface again.

This will distribute some platform independent logic over the LCL and the
interfaces. The interfaces should be what they are named: just interfaces
between the LCL and the widget set. 
If we say, that the interface is on the same lvl as the LCL, it implies
*all* interface functions are on the same lvl. According to your example of
the checking of a menu item: calling the interface function FillRect on a
shared bitmap handle should unshare the bitmap. Just as the LCL does when
you use the LCL FillRect.

 
> These two reasons combined, mainly reason 1 though, I'd still vote for 
> the 'hideous' way, putting the interfacebase above the LCL in the 
> hierarchy.

The LCL uses the interface base. It can be above or on the same lvl, but
never below.


> This could also have the advantage that potential users 
> aren't going to call the interface directly because it suddenly is a 
> 'higher' level. 

What do you mean ?


> Everything the interfacebase can do, the lcl should be 
> able to do. So by using the lcl, users have its full potential and power 
> available.
> 
> > The other side:
> > What would happen, if we put the LCL and the interface base on the same
> > level?
> > This would mean, a call of LCLCheckMenuItem and the use of
> > AMenuItem.Checked:=true is equivalent. This would mean the LCL logic
> > must be handled in the interface (unchecking if it is a radio item,
> > etc.). I strongly suggest, that we do not try this way.
> 
> This seems like my reason 2) above. In essence, what you are then trying 
> to do, as we are partly doing now, is make H... out of everything which 
> only the interface knows about: HDC, HWND, ... and then are synced to 
> their corresponding object in the lcl. It does have a clear advantage 
> also: my reason 1) is also solved, because that H... carries the 
> information the interface needs to know about. Disadavantage is that you 
> have all, or a lot of it, information twice.
> 
> >>If we adhere to this order, nothing can go wrong. Things on lower level 
> >>may use things on a higher level, but only when they need to implement 
> >>functionality.
> >>
> >>
> >>>If units are ordered hierachical, an user can start exploring the high
> >>>lvl units and then go down, as he needs. But with unit circles, he
> >needs>>to read the whole circle to understand what is going on.
> >>
> >>I think not many users read interface uses and 'know' what's meant when 
> >>he reads an interface call.
> > 
> > 
> > That's exactly my point. Although it seems, you can draw different
> > conclusions from it.
> > 
> > 
> > Back to the "unnecssary" casting:
> > - it is always a good idea to check the input of a function 
> 
> This is true, but doesn't apply in this case if you ask me. Pascal has 
> quite strong typing. So let's use that to our advantage to provide as 
> much information as possible.

An 'as' is even stronger and the compiler already checks for TBaseMenuItem.

 
> > - the interface functions can also be used by the user. Even if we say:
> > Plz don't do. People will do.
> 
> Yes, this is unavoidable indeed. But how does it relate to unnecessary 
> casting?

1. The LCL and its interfaces are full of examples of typecasting TControls
to descendents. 
2. Users are humans, humans make mistakes, users will typecast without check
and call the interface functions. => The interface should check the type.

 
> > - We can add function to TBaseMenuItem, so that te typecast is not
> > needed.
> 
> Can you suggest an example?

For example GetIndex and GetParent.


Mattias






More information about the Lazarus mailing list