[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    Re: Proposing the removal of virtual_hooks (or how you can add a
From:       Frans Englich <frans.englich () telia ! com>
Date:       2006-03-05 22:18:16
Message-ID: 200603052218.17153.frans.englich () telia ! com
[Download RAW message or body]

On Sunday 05 March 2006 16:50, Thiago Macieira wrote:
> Frans Englich wrote:
> >On Saturday 04 March 2006 11:18, Thiago Macieira wrote:
> >> I'd like to propose a change of policy in the KDE libraries: remove
> >> all virtual_hook functions from QObject-derived classes.
> >>
> >> The reason for that is that we *already* have a virtual_hook function
> >> in those classes and it's called qt_metacall. It's automatically
> >> generated by moc, so we're safe that it'll always exist.
> >
> >Another way to preserve BC is to use the visitor/double dispatch
> > pattern. It can be argued to be a bit heavy code-wise, but achieves the
> > goal and can also be fast, depending on various factors. Major
> > pros/cons:
>
> Would you mind elaborate on what that is?

Ok, attached is a visitor pattern discussion. I'm told it is in GOF's Pattern 
Design book, you can read about it in wikipedia, google for it, etc. I might 
very well be "wrong" on this, show an incomplete picture, and so forth. I 
have never seen anyone use it for the purpose of preserving BC, but by my 
common sense(TM) it should be possible to use it that way.

I use the visitor pattern in kdenonbeta/kdom/xpath, but that's mainly for 
other reasons(not for preserving BC).


Cheers,

		Frans

["visitor_example.cpp" (text/x-c++src)]

class AStayBC;
class BStayBC;

class Visitor
{
public:
	virtual char *visit(AStayBC *operand) const = 0;
	virtual char *visit(BStayBC *operand) const = 0;
};

/**
 * This class and sub-classes must stay binary compatible.
 */
class StayBC
{
public:
	virtual char *accept(const Visitor &visitor) = 0;
};


class AStayBC : public StayBC
{
	virtual char *accept(const Visitor &visitor)
	{
		return visitor.visit(this);
	}
};

class BStayBC : public StayBC
{
	virtual char *accept(const Visitor &visitor)
	{
		return visitor.visit(this);
	}
};

/*
 * Now, let's say we want to extend one of the StayBC sub-classes
 * in a polymorphic way.
 * 
 * First a Visitor sub-class which provides the "implementation" of the
 * extension:
 */

class Extension : public Visitor
{
	virtual char *visit(AStayBC *This) const
	{
		/* @p This is the 'this' pointer of the class we are
		 * extending, so to speak. */
		return "AStayBC";
	}

	virtual char *visit(BStayBC *This) const
	{
		return "BStayBC";
	}
};

/* 
 * And now, use Extension:
 */

void doIt()
{
	StayBC *sbc = new BStayBC();
	Extension ext;

	char *result = sbc->accept(ext);
	/* We've now managed to perform a polymorphic function call
	 * without touching the classes which the function call's "this"
	 * pointer is using. */
}

/* 
 * There are various modifications one can do here:
 *
 * - Change the constness of accept() and visit()
 * - Make the return value(char *, in this case) a generic class such
 *   that different return values can be used. Basically: "class VisitorResult{};"(or
 *   sub-class a Shared class or sth like that), which is sub-classed.
 * - One can make the accept() function take additional arguments which it pass on to
 *   visit(). For example, an int such that one can pass an enum(it looses typing though).
 * - Provide default implementations of accept()/visit() which returns default constructed
 *   values. This avoids that sub-classes have to provide dummy implementations if they
 *   for some reason are not of interest.
 * - One can deploy some of the boiler plate code with templates, especially if one uses
 *   the visitor pattern for several class hierarchies. (I think boost has somekind of
 *   visitor support.)
 *
 * Drawbacks with the visitor pattern:
 *
 * - It isn't an "uncontrained adding of virtual functions", to be exact. The calling convention
 *   is different, and what arguments that are allowed to be passed cannot be alterered.
 * - It is rather heavy. For adding a virtual function, one needs to create a class.
 *
 * Advantages:
 *
 * - It do provide a rather nifty call dispatching mechanism, which, if sufficient, works fine.
 * - It allows someone to extend a class hierarchy without sub-classing it.
 *
 * In some cases a visitor pattern can as a side effect provide a mechanism for preserving
 * BC(even though its primary purpose is something else). It's not a perfect, all-in-one
 * solution, but if the scenario fits, it fits.
 */ 



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic