How to create an alias - overlaying two class hierarchies

M

Matt

Please help me. I really don't know a solution to this.

I am trying to re-merge two versions of a library after a badly accepted
code split. FLTK 1 is stable and has very few bugs. It has been
developed in parallel with FLTK 2. FLTK 2 has (by far) a better API, but
has become unstable due to the lack of TLC.

My plan is to map the FLTK 2 API onto the FLTK 1 guts, creating FLTK 3
which is source code compatible to 1 *and* 2.


This is part of the class hierarchy:

class Fl_Widget
class Fl_Group : public Fl_Widget
class Fl_Window : public Fl_Group

and

class fltk::Widget
class fltk::Group : public fltk::Widget
class fltk::Window : public fltk::Group

Now I need a true alias that maps Fl_Widget to fltk::Widget, etc. .

(1) A typedef does not do because a forward declaration of Fl_Widget
would fail:

class Fl_Widget *somePointer;
#include <Widget.h>
typedef fltk::Widget Fl_Widget; // error

(2) The I tried stub classes, generating this hierarchy

class fltk::Widget
class Fl_Widget : public fltk::Widget
class fltk::Group : public fltk::Widget
class Fl_Group : public fltk::Group
class fltk::Window : public fltk::Group
class Fl_Window : public fltk::Window

This fails because Fl_Group is no longer derived from Fl_Widet

(3) This may work, but it *u*gly!

class fltk::Widget
class Fl_Widget : public fltk::Widget
class fltk::Group : public Fl_Widget
class Fl_Group : public fltk::Group
class fltk::Window : public Fl_Group
class Fl_Window : public fltk::Window

(4) Using #define is out of the question... .


Any help is greatly appreciated!


Matthias
 
F

Francesco S. Carta

Please help me. I really don't know a solution to this.

I am trying to re-merge two versions of a library after a badly accepted
code split. FLTK 1 is stable and has very few bugs. It has been
developed in parallel with FLTK 2. FLTK 2 has (by far) a better API, but
has become unstable due to the lack of TLC.

My plan is to map the FLTK 2 API onto the FLTK 1 guts, creating FLTK 3
which is source code compatible to 1 *and* 2.

This is part of the class hierarchy:

class Fl_Widget
class Fl_Group : public Fl_Widget
class Fl_Window : public Fl_Group

and

class fltk::Widget
class fltk::Group : public fltk::Widget
class fltk::Window : public fltk::Group

Now I need a true alias that maps Fl_Widget to fltk::Widget, etc. .

(1) A typedef does not do because a forward declaration of Fl_Widget
would fail:

class Fl_Widget *somePointer;
#include <Widget.h>
   typedef fltk::Widget Fl_Widget; // error

(2) The I tried stub classes, generating this hierarchy

class fltk::Widget
class Fl_Widget : public fltk::Widget
class fltk::Group : public fltk::Widget
class Fl_Group : public fltk::Group
class fltk::Window : public fltk::Group
class Fl_Window : public fltk::Window

This fails because Fl_Group is no longer derived from Fl_Widet

(3) This may work, but it *u*gly!

class fltk::Widget
class Fl_Widget : public fltk::Widget
class fltk::Group : public Fl_Widget
class Fl_Group : public fltk::Group
class fltk::Window : public Fl_Group
class Fl_Window : public fltk::Window

(4) Using #define is out of the question... .

Any help is greatly appreciated!

Try posting more details - the interfaces of those classes, in
particular.

Also, I'm not so sure about what TLC stands for, here, top-level
classes perhaps?

A hierarchy could have nothing wrong in itself but its application can
be partially or totally wrong, depending on the cases.

Also, why did you write "this may work" for (3)? Didn't you test it?
Depending on the cases, that could be the only way to avoid rewriting
the interface.
 
M

Michael Doubez

Try posting more details - the interfaces of those classes, in
particular.

Also, I'm not so sure about what TLC stands for, here, top-level
classes perhaps?

I think he means TCL (Tool Command Language) like tcl/tk.

A hierarchy could have nothing wrong in itself but its application can
be partially or totally wrong, depending on the cases.

A hierarchy is a problem when you inherit an implementation, and
looking rapidely at fltk, it is the case here.

To the OP, your solution (2) may work if you virtually inherit:
class fltk::Widget
class Fl_Widget : public virtual fltk::Widget

class fltk::Group : public virtual fltk::Widget
class Fl_Group : public virual fltk::Group, public virtual Fl_Widget

class fltk::Window : public virtual fltk::Group
class Fl_Window : public fltk::Window, public virtual Fl_Group
 
F

Francesco S. Carta

I think he means TCL (Tool Command Language) like tcl/tk.

Looking up TLC led to several acronym expansions, but having failed to
find one that fit, I made one up ;-)
A hierarchy is a problem when you inherit an implementation,
Amen.

looking rapidely at fltk, it is the case here.

Oops, I thought the fltk thingie was something peculiar to the OP's
project, but since you were able to find those details somewhere else,
that had to be some third-party library.

I didn't even think about looking it up, first time I hear about,
thanks for pointing it out.

Damn, seems I'm a bit behind in the "IT acculturated" trail ;-)
 
M

Matt

Michael said:
I think he means TCL (Tool Command Language) like tcl/tk.

Oh, sorry, TLC stands for "tender love and care". I meant to say that we
did not take care of the fltk2 branch as we should have.
A hierarchy is a problem when you inherit an implementation, and
looking rapidely at fltk, it is the case here.

FLTK needed to be written to replace the Forms Library, a decades old
Graphical User Interface library. It needed to be source code
compatible. The class structure is - um - bearable, but really easy to
understand, which makes FLTK a great beginner GUI library. It has been
taught until recently at several universities.

FLTK2 was the attempt to clean up the major flaws, but never took of,
because user with existing code would not jump from V1 to V2, afraid of
the changes required in their source code.

Now we ended up with two libraries with 90% feature overlap, one stable
with an ancient API, the other instable, but as many users and a better API.

My goal is to move the stable version, FLTK 1, up and call it FLTK 3,
but implementing both APIs, so we don't lose any more users. Then the
additional features of FLTK 2 will be ported to FLTK 3. I am not sure if
this a sound strategy, but I would like to give it a try and see what
the acceptance will be.

The problem is the aliasing of the class hierarchy which must not be
even messier than what we have ;-)
To the OP, your solution (2) may work if you virtually inherit:
class fltk::Widget
class Fl_Widget : public virtual fltk::Widget

class fltk::Group : public virtual fltk::Widget
class Fl_Group : public virual fltk::Group, public virtual Fl_Widget

class fltk::Window : public virtual fltk::Group
class Fl_Window : public fltk::Window, public virtual Fl_Group

Thank you, I will try that out. Does that mean that the virtually
inherited classes must be pure virtual, too?

Francesco: (3) I see no reason why (3) wouldn't work, but I havn't
tested it yet. It feels a bit brute force to me and I was hoping for a
more elegant version.

Thanks for the hints,

Matthias
 
M

Michael Doubez

Oh, sorry, TLC stands for "tender love and care". I meant to say that we
did not take care of the fltk2 branch as we should have.

Not caring enough to spell it full then :)

[snip]
Thank you, I will try that out. Does that mean that the virtually
inherited classes must be pure virtual, too?

Not necessarily. That depends on own your class map to one another.

It solves the diamond shape inheritance. That way you will have the
following hierarchy:
Widget
| \
| FL_Widget
| |
Group |
| \ |
| FL_Group
| |
Window |
\ |
FL_Window


Group and FL_Group will share the same inherited Widget instance.
Francesco: (3) I see no reason why (3) wouldn't work, but I havn't
tested it yet. It feels a bit brute force to me and I was hoping for a
more elegant version.

If you don't need to bridge the two hierarchy (i.e. a FL_Widget* must
not be a fltk::Widget*), you could just use composition and keep the
types orthogonals:

// FL_Widget uses internally a fltk::Widget.
class FL_Widget
{
fltk::Widget* widget;

public:
FL_Widget():widget(new fltk::Widget())
{}

// interface uses widget

protected:
FL_Widget(fltk::Widget* w):widget(w)
{}
void setWidget(fltk::Widget* w)
{
widget=w;
}
};

And in case of inheritance, you intialize according to decorated
object:
class FL_Group: public FL_Widget
{
fltk::Group* group;

public:
FL_Group():FL_Widget(NULL)
,group(new fltk::Group())
{ setWidget(group); }

// interface uses group

protected:
FL_Group(fltk::Group* g):FL_Widget(g),group(g)
{}
void setGroup(fltk::Group* g)
{
group=g;
setWidget(group);
}
};

// ...

You would also have to redefine copy constructor and operator to make
your classes canonical; beware of destructor which must set its
hierarchy to NULL to avoid multiple deletion.
 
F

Francesco S. Carta

Matt said:
Francesco: (3) I see no reason why (3) wouldn't work, but I havn't
tested it yet. It feels a bit brute force to me and I was hoping for a
more elegant version.

I hope that Michael's suggestion will help you find the optimal
solution for your issue.

I just realized that you're one of the library's implementers, so yes,
that's something peculiar to your project and no, from your POV that's
not a third-party library ;-)

I'm interested in checking it out, but I'm having hard time getting it
- my fault, I have a weird proxyed connection. I'm going to send you
an e-mail to the addresses I've found on your personal website, you'll
eventually hand me some non-ftp link.

Good luck for your projects,
cheers,
Francesco
 
M

Matt

Francesco said:
I just realized that you're one of the library's implementers, so yes,
that's something peculiar to your project and no, from your POV that's
not a third-party library ;-)

Well, with a few hundred users, it feels like a third party library in
that I can't change the API (much) or even the ABI between revisions. At
least I have full access to the internals ;-)
I'm interested in checking it out, but I'm having hard time getting it
- my fault, I have a weird proxyed connection. I'm going to send you
an e-mail to the addresses I've found on your personal website, you'll
eventually hand me some non-ftp link.

No problem. The http download is here:

http://ftp.easysw.com/pub/fltk/
Good luck for your projects,

Thanks a lot for your interest. After 12 years of being one of the core
developers, the brain plays funny tricks with code and structures. I
kind of feel like I personally know every line of code ;-)

Matthias
 
M

Matt

Michael said:
It solves the diamond shape inheritance. That way you will have the
following hierarchy:
Widget
| \
| FL_Widget
| |
Group |
| \ |
| FL_Group
| |
Window |
\ |
FL_Window


Group and FL_Group will share the same inherited Widget instance.

Phew, yes. I read myself into the diamond problem a little (and suddenly
remembered why I always avoided it ;-). I gave it a quick try, but
haven't wrapped my head around it yet. I will try with a smaller project
first.
If you don't need to bridge the two hierarchy (i.e. a FL_Widget* must
not be a fltk::Widget*)

Sorry, no, I'll have to provide that.

I did another quick try with - hold your breath - using a simple
"define". While this throws up different (solvable) issues, I was
successful in compiling an FLTK 1 and almost an FLTK 2 program without
changing a line of code. Quite unsatisfying though.
You would also have to redefine copy constructor and operator to make
your classes canonical; beware of destructor which must set its
hierarchy to NULL to avoid multiple deletion.

Thanks for all the help!

Matthias
 
F

Francesco S. Carta

Well, with a few hundred users, it feels like a third party library in
that I can't change the API (much) or even the ABI between revisions. At
least I have full access to the internals ;-)

It's better to have such limitations, due to the consistency of the
user-base.
At least, this will push all the team towards injecting some more TLC
into the next revisions - sorry, I couldn't resist making this
malicious statement ;-)
No problem. The http download is here:

http://ftp.easysw.com/pub/fltk/

Thanks, I was finally able to get it from the above link.
Thanks a lot for your interest. After 12 years of being one of the core
developers, the brain plays funny tricks with code and structures. I
kind of feel like I personally know every line of code ;-)

You're welcome, I'm about to compile and try it out, I'll get in touch
with your community.

Cheers,
Francesco
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top