Article 20339 of comp.lang.c++:
Newsgroups: comp.lang.c++
Path: sessun!uunet!munnari.oz.au!metro!news
From: maxtal@physics.su.OZ.AU (John Max Skaller)
Subject: Mixin Article (repost)
Message-ID: <1993May19.100918.828@ucc.su.OZ.AU>
Sender: news@ucc.su.OZ.AU
Nntp-Posting-Host: physics.su.oz.au
Organization: School of Physics, University of Sydney, Australia
Date: Wed, 19 May 1993 10:09:18 GMT
Lines: 797

Due to many email requests for this article, I'm reposting
it. Included is the 'sort' example at the end. If you have
already read the article, no need to read on, I havent changed it.


	MIXIN SOFTWARE TECHNOLOGY
	=========================

Here is a long promised description of mixins. Sorry,
there are no real examples here. Its up to your imagination
until I get something real prepared. But this description
couldn't wait.

I hope it helps.

	John MAX Skaller, Maxtal P/L, Sydney, Australia.
	maxtal@extro.ucc.su.oz.au

QUESTION: What are mixins?

ANSWER:  "Mixin" in C++ is a high power technique for using
multiple inheritance (MI) with abstract virtual bases (AVB) to enable incremental development of both interfaces and implementations
of classes.

To understand mixins we first need to know the basic enabling
technology. I've often commented mixins were Bjarnes greatest
achievement in C++: the following two questions outline 
that achievement. Note Bjarne claims it wasn't intended
to enable mixin technology: so much the greater is a
scientific law that has unexpected and useful consequences.



QUESTION: How do mixins work?

ANSWER: Mixins rely on the "sibling call" mechanism described in
the ARM on p234:

	"A call to a virtual function through one path
	in an inheritance structure may result in the invocation 
	of a function redefined on another path. 
	This is an elegant way for a base class to 
	act as a means of communication between sibling classes."

                   B f()=0
                  /\
                 /  \
        f();    X    Y g(){ f(); }
                 \  /
                  \/
                  D

The virtual base B in this diagram contains a 'hook' or 'vector'
function 'f'. The definition of 'f' is supplied in X, while
'f' is used by 'g' in Y. The class D is derived from X and Y
to 'connect' the definition of 'f' in X with the usage of
'f' in Y via their shared virtual base B.

QUESTION: Why does Sibling Call work?

ANSWER: Sibling call works because of the Name Dominance Rule,
described in the ARM in 10.1.1 on pp204-205:

	"A name X::f dominates a name B::f if its class X has
	B as a base. If a name dominates another no ambiguity
	exists between the two; the dominant name is used
	when there is a choice ...

	"The dominance rule is necessary for virtual functions
	since it *is* the rule for which function should be 
	invoked for a virtual call ... for virtual functions
	the dominance rule is what guarrantees that the
	same function is called independently of the static
	type of the pointer, reference, or name of the object
	for which it is called"


	Axiom Classes
	-------------

The base classes in mixin technology are usually small, independent,
and abstract: ideal for placement in a library.  The member
functions of these classes are usually small in number,
independent, and pure virtual, and may be called axioms.

	class Ax1	class Ax2	class Ax3

A set of global functions operating on the base abstractions
can be written and also placed in the library:
they will work for all implementations of the abstractions
because of polymorphism. Note that these functions
are like 'theorems' in that they are defined in terms
of the undefined pure virtual axioms. 


	g(Ax1&);	g(Ax2&);	g(Ax3&);
	h(Ax1*);	h(Ax2*);	h(Ax3*);

	k(Ax1*,Ax2*);

Although global, these functions do NOT pollute the global namespace,
since they are qualified by the classes they operate on:
they are as attached to the class as its members, but have
no access to implementation details.

The axiom classes can be combined using public virtual inheritance
to form larger, convenient, sets of axioms.

	Theorem (Interface) Classes
	---------------------------

It is common practice to put a set of related 'theorem'
functions in a 'Theorem' class derived from the axiom classes
to which it refers. If more than one class is refered
to, MI must be used. The inheritance is usually public,
although sometimes it is protected or private if the
axioms are considered too primitive for end-user invokation.
The inheritance will almost always be virtual, so that
subsequent combination of theorem classes by MI will
always only ever have one instance of each axiom class.

These classes are sometimes called 'Interface' classes,
since they contain higher level functionality than the
primitive axiom classes, which is more suitable for
use by end-users.

In general, various schemes of building on the base abstractions
can be used, or no scheme at all. It is not incorrect to
introduce new axioms into theorem classes, for example.

Note that in advanced mixin use, interface classes may themselves
be introduced initially as abstract classes. Their pure
virtuals are then defined in terms of some set of axioms
by creating an implementation class which derives from both
the interface class and the axiom classes, and implements
the interface functions in terms of the axiom functions.
The resultant interface is still abstract: but the abstraction
has been shifted from the high level interface functions
to the low level axiom primitives. Subsequent definition
of the primitives 'concretises' the interface class.


	Model (Implementation) Classes
	------------------------------

For each base abstraction, a typical library will contain several
implementations with different properties. An implementation
of an abstract class is derived *virtually* from the abstraction,
and implements it by overriding the virtual functions.

Typically, one implementation will be optimised for speed, and another
to use the least memory. However, the implementations
may also differ in their semantics, for example the pure
virtual function 'Draw()' may be overriden in different
classes to draw different shapes.

The implementation of an axiom class is called a Model or
Implementation class. As above, in a non-strict scheme,
Model classes may implement only some of the pure virtual
functions, and subsequent derivations may be needed to
completely concretise the abstraction. Such derivations
may also inherit other abstractions in order to concretise
the first set, transfering the burden of definition
sideways.

	Constructor (Mixin) Classes
	---------------------------

Now when you want to create an object which has a certain
interface, you select, or build using MI, an appropriate
interface class for your application. This class must
be globally known, and is the class with which
you perform all work.

Luckily, you dont have to write many procedures that operate
on this class: they are already in the library, although
they are typically defined to work on the bases: you can
still call them because your interface class 'isA' base,
for each of its bases.

However, the interface class is abstract, you cant
make an object of the interface class directly.
Instead you must 'mixin' <finally!> an implementation
of each axiom base by multiple virtual inheritance.

Suppose you have an interface class IF which has axiom
classes Ax1, Ax2 and Ax3. You choose to use the
implementations Ax1Im3, Ax2Im7 and Ax3Im2, because these
are optimised for speed and support the semantics you desire.
Here's how you do the mixin:

  IF * makeIF()
  {
	class Dummy : public IF,
		public virtual Ax1Im3,
		public virtual Ax2Im7,
		public virtual Ax3Im2
	{};
	return new Dummy;
  }


QUESTION: Where's the CODE??

ANSWER: You already wrote it. Mixins embody the idea 
of reusability to the fullest possible extent. 
Mixins are for lazy programmers --- the best kind :-)
 
You may have to write a constructor, though, because
constructors are not inherited. :-(

Thats why using mixins is sometimes called 'Programming
by Constructor': the constructor is the only code
you often have to write.

QUESTION: Why is the mixin class declared in function local scope?

ANSWER: It would be even better to use an anonymous class: 
the name of this class is not important and should not be known
by the rest of the system. It is, after all, a class
created purely for the purposes of implementing the interface:
and it is good practice to hide implementation details.

It is often crucial that these details are hidden, and cannot
be retrieved *even* with nasty hacks like dynamic downcasting.
This is because the implementations that have been hooked
in are too primitive for client access, and their direct
use by the end user may destroy the integrity of the object.
Making the constructor class local or anonymous defeats
downcasting, an excellent idea: the object should only
be accessed through its declared interface.

Perhaps unfortunately it is sometimes necessary to use
public derivation of the implementations so that
their constructors and destructors are accessible.
It is also usually necessary to name the concrete class
since you cannot define a constructor for the class
otherwise.

If the constructor class cannot be hidden by making it
local, its a good idea to hide it by declaring it
in file scope only.

Such definitions of the constructor class are
called 'On-The-Fly', because you make up the class
on the spot, just before you create an instance of it,
purely for the purposes of creating that instance,
and then forget the class immediately after the object
has been constructed.

Usually, the only new functions you can sensibly add to a mixin
class are those of *the* constructor and destructor,
and any helpers need by those functions. Only one constructor
is needed, since you only construct one object immediately
after mixin defintion: you might as well use the default
constructor.

It is also possible that you have selected or built an interface
class that is still partially abstract. In this case
you must also override the remaining pure virtual functions
in the mixin class. It is also possible to override
other virtual functions 'At The Last Minute' to provide
more efficient access or modified functionality.

QUESTION: Is this scheme of Axiom (primitive), Theorem(Interface), 
Model(Implementation) and Constructor(Mixin) classes 
the only way to do mixins?

ANSWER: No. You can do anything you want :-) 
The scheme outlined above is intended to indicate the 'Spirit of Mixin',
and not any set of hard and fast rules.

The basic principle of mixin is simply that you should defer
binding of the implementation of an interface until
the last possible place, and that the basic functional
primitives be encapsulated in small, independent abstract
classes.

QUESTION: Is there an even more powerful technique than mixin?

ANSWER: Yes and No :-)

YES: Delegation is more powerful than mixin.
With delegation the 'base' classes are accessed via
a pointer (or reference) to another object, and the
construction and destruction of these 'base' objects
are under programmer control. 

NO: With mixin, there are also (in many implementations) 
hidden pointers to virtual base sub-objects in the classes: 
these pointers are needed to locate the virtual bases.
However these hidden pointers are initialised and accessed
correctly at all times because they are manipulated directly
only by the compiler, not the programmer.

Mixin is the most powerful statically secure method available
in C++. 

QUESTION: Can you combine mixins and delegation?

ANSWER: It is not at all uncommon to combine the two techniques.
Mixins are prefered where possible because they are statically
and dynamically secure, and because construction and destruction
are managed automatically.

QUESTION: Is the use of virtual bases necessary in mixins?

ANSWER: Absolutely. Both the interface and implementation
classes inherit from the axioms: one to build on the
primitives, and the other to define them. If you
didnt use virtual inheritance in both cases, the definitions
would not be called by the interface functions:


                          Ax f()=0  Axiom: MUST be shared
                         /\
virtual mandatory --->  /  \   <---- virtual mandatory
                       /    \
Implementation   f(); Im    If g(){ f(); } Interface
                        \  /
                         \/
                          Mx Mixin


QUESTION: Why does mixin enable incremental development?

ANSWER: Because you can provide, and use as you desire,
implementations and abstractions in small pieces,
independently. The binding of the implementation pieces
is defered to the last minute: on the fly construction
from the pieces.

This cannot be done with single inheritance (SI):
with SI you get 'layered development', in which
binding is done in layers.

Of course, delegation also provides incremental development,
and is more powerful than mixin, so arguing that
only SI and delegation is needed is pointless: mixin
is the technology that provides greatest power while
remaining statically secure.

QUESTION: Can I use mixins with templates?

ANSWER: Oh YES. Please do.

QUESTION: Whats the best way to build a class library?

ANSWER: With mixins of course. Delegation may also
be required for more advanced techniques. However,
delegation is not as well supported or secure as
mixin in C++: use mixins wherever possible.

QUESTION: Whats the worst way to build a library?

ANSWER: Thats a leading question :-) The worst way
is to use an 'Object Heirarchy' which has a single
class 'Object' from which everything is derived by SI
in increasing levels of complexity.

This inevitably leads to either a VERY fat interface for
the 'Object' class in order to preserve polymorphic access via
virtual functions, or use of downcasting to emulate dynamism. 

Both these methods are ugly in C++, and break all the known
principles of good modular design:

	o Small interfaces
	o Weak coupling
	o Explicit coupling
	o Hiding of implementation
	o Closure of modules to changes
	o Openness of modules to extension
	o Reusability

	
Those not believing this should try to combine the use
of several Object based class libraries. The original
Borland and NIH libraries are examples.

QUESTION: Why dont mixins have this problem?

ANSWER: Because a mixin library is based on a set of small,
independent abstractions. Using two mixin libraries together
is just a case of taking the union of the abstractions.


QUESTION: Does use of mixins lead to an exponential explosion
of classes?

ANSWER: Not necessarily, it should do precisely the opposite.
The sets of basic abstractions and their implementations
can be combined by a simple union: the numbers of
such classes is just a simple addition --- its linear not
exponential.

Certainly, the number of *possible* combinations you can
have with mixins is exponential --- its supposed to be!
This is the whole point: you can have a very wide choice
of interfaces, yet implement them by a simple mixin
of some set of implementation classes.

But these choices are made 'on the fly': the existant
combinations in any one program will always be small,
and the differing implementation choices are irrelevant
because the're hidden.

Again, the number of useful interface classes you can
form will be exponential on the axiom classes, and this
is desirable. You dont have to actually create every such
combination.

Mixin libraries should be considered a toolkit of reusable
components, together with a few common combinations of these,
supplied for convenience.

A mixin library is not a monolithic, integrated, tightly
coupled system like an 'Object Heirarchy'.

QUESTION: Are mixin libraries hard to design?

ANSWER: Yes, all reusable components are hard to design.
It is not easy to decide exactly how to divide up functionality
between classes.

QUESTION: Are mixin libraries hard to use.

ANSWER: No, they're quite easy to use: often you need only
derive an appropriate class, mixing in the desired implementation
components, and possibly writing a constructor.

However, you should note that a mixin library does not
present you with a total solution to your problem. It still
leaves the task of designing solutions and implementing
them up to you, the programmer. It presents a wide variety
of solutions: you have much more choice than with an Object
Library.

What the mixin library does is save you writing code: you will
spend more time deciding which classes to use, and how to
plug them together than coding: the code is already written.

When you do have to write code, its usually to supply a new
implementation of an axiom class. In that case, the constraints
are extremely tight: the interface to which you must
conform is well defined, and the coding job is usually trivial.

QUESTION: How will mixin libraries change my coding style?

ANSWER: You wont spend much time writing code. Your effort
will be directed towards design rather than hacking.

QUESTION: Are there any good mixin libraries available?

ANSWER: Not that I'm aware of. There are several reasons:

	1) Early C++ didnt have mixins: there was no
	  MI, only SI. People still use class libraries
	  designed at this time.

	2) Many existing compilers have or had until recently,
	  bugs in the implementation of MI, 
	  abstract classes and virtual functions.

	  For example, Cfront version 3 incorrectly diagnosed
	  mixin classes as abstract, defeating the use of mixins.
	  Version 3.0.1 is fixed, I believe.

	3) Mixin technology is not well understood.
	   Thats why I've written this article.

	   Mixins use some of the newest concepts in C++:
	   Abstract classes, Multiple Inheritance, and
	   Virtual bases: in combination. And templates and
	   exceptions will add to this technology.
	
	4) Many programmers come from a Smalltalk background.
	   So they are still thinking of OOP in terms of
	   dynamics and Object Hierarchies, techniques not
	   suited to C++, which is an essentially a strongly typed,
	   static, and compiled language.

	   C++ OOP is so different from Smalltalk, that I have
	   trouble conceiving them as both OOPLs. In fact I
	   tend to think of C++ as a class based language,
	   not an object based one.

	5) There are few examples. Because of 1-4, there are few
	   examples for other to learn from and improve on.
	   I hope this will soon change :-)
	   Use of a technique is exponential, there is the well
	   known 'Snowball' or 'Band Wagon' effect.

	   The situation is improving: already Borland, for example,
	   has replaced its Object based classes with the much
	   better BIDS classes. Although these are not yet
	   quite mixin classes (BC 3.1 has the mixin disabling bug),
	   they do use templates and MI: the precursor to
	   mixins.

QUESTION: Can I get around the mixin disabling bug?

ANSWER: Yes, you can just define a dummy body for your
pure virtual functions: it will never get called, but
it does make the code look messy, and it does prevent
the linker detecting when you have failed to supply
an implementation for a pure virtual (since they're
not pure virtual if you give a dummy body).

QUESTION: Can you show me an example of mixins?

ANSWER: Yes I promise! But not yet, I'm still working on one that
is non-trivial and actually usable. This is not so easy,
as my compiler has the mixin disabling bug. The compromise
between a 'Micky-Mouse' example (not convincing) and
an industrial strength one (lots of work and may have
too much detail for educational purposes) is an example
of the sort of design problem that I'm grappling with.

I'm currently working on a text screen based database.
(No, not a persistent object store, just a device independent
record manager with windows, dialog boxes etc--usable but
not sophisticated).

However, I invite those few programmers that have used
mixins to post examples.

#include <iostream.h>
// Mixin example: sorting and searching
//
// This software will sort and search an indexed set for which
// some total ordering is defined.
//
// The indices are integers 0..n, for some definite n.
//
// It must be possible to compare the data at locations i and j
// and return -1, 0, or +1 depending on the whether the
// ith element is less than, equal to, or greater than the jth element.
// The comparison MUST yield a total ordering or results are not
// guarranteed.
//
// It must also be possible to exchange the ith and jth elements.
// Note this need not imply moving the elements, exchanging
// the integer associated with an element suffices.
//
// Finally, for the search, it is necessary to compare the ith element
// with the candidate element. (In that order!)
//
// The searches and sorts assume ascending order:
// reverse the sign of compare and test to use descending order

// First, a work around for mixin disabled compilers
#define KLUDGE
#ifdef KLUDGE
  #define pv {}
  #define pi {return 0;}
#else
  #define pv =0;
  #define pi =0;
#endif

// *********************************
// ***** The Pure Abstractions *****
// *********************************

struct Object {
  virtual ~Object()=0;
};

// Collection base.
struct Collection {
  virtual int nelements()const pi
  virtual int compare(int i, int j)const pi
  virtual ~Collection(){}
};

// Sortable is a Collection
struct Sortable : public virtual Collection
{
  virtual void exchange(int i, int j) pv
};

// Sort is a Sortable
struct Sort : public virtual Sortable
{
  virtual void sort() pv
};

// Searchable is a Collection
struct Searchable : public virtual Collection
{
  virtual int test(int i)const pi
};

// Search is a Searchable
struct Search : public virtual Searchable
{
  virtual int search()const pi
};

// *****************************
// *** Some Implementations ****
// *****************************

// LinearSearch is a Search
struct LinearSearch : public virtual Search
{
  int search()const;
};

int LinearSearch::search()const
{
  int n=nelements();
  cout<<"Binary Chopping "<<n<<" elements"<<endl;
  for(int i=0; i<n; ++i)
  {
    int cmp=test(i);
    if(cmp==0)return i;
    if(cmp>0)return -1;
  }
  return -1;
}

// BinaryChop is a Search
struct BinaryChop : public virtual Search
{
  int search()const;
};

int BinaryChop::search()const
{
  int n=nelements();
  cout<<"Binary Chopping "<<n<<" elements"<<endl;
  int lo=0;
  int hi=n-1;
  while(lo<=hi)
  {
    int mid=(lo+hi)/2;
    int cmp=test(mid);
    if(cmp==0)return mid;
    if(cmp<0)lo=mid+1;
    else hi=mid-1;
  }
  return -1;

}

// BubbleSort is a Sort
struct BubbleSort : public virtual Sort
{
  void sort();
};

void BubbleSort::sort()
{
  int n=nelements();
  cout<<"Bubble sorting "<<n<<" elements"<<endl;
  for (int i=0; i<n-1; ++i)
    for(int j=n-2; j>=i; --j)
      if(compare(j,j+1)>0)exchange(j,j+1);
}

// ********************************
// ***** Example Mixin ************
// ********************************

template<class T>
int cmp(const T& a, const T& b)
{
  if(a<b)return -1;
  if(a==b)return 0;
  return 1;
}

template<class T>
class Array {
  T * data;
  int n;
public:
  int size()const {return n;}
  T& operator[](int i){return data[i];}
  const T& operator[](int i)const{return data[i];}
  Array(int nn, T* dd) : n(nn), data(dd) {}
};

template<class T>
ostream& operator<<(ostream& out, const Array<T>& a)
{
  for(int i=0; i<a.size(); ++i)
    cout<<"Elem "<<i<<" is "<<a[i]<<endl;
  return out;
}

template<class T>
class SSArray :
  public virtual Sort,
  public virtual Search,
  public Array<T>
{
  const T* candidate;
  int test(int i)const;
  int compare(int i,int j)const;
  void exchange(int,int);
  int nelements()const{return size();}
public:
  int find(const T* t)const;
  SSArray(int n, T* t) : Array<T>(n,t){}
};

template<class T> int SSArray<T>::test(int i)const
{
  return cmp(operator[](i),*candidate);
}

template<class T> int SSArray<T>::compare(int i,int j)const
{
  return cmp(operator[](i), operator[](j));
}

template<class T> void SSArray<T>::exchange(int i,int j)
{
  T temp=operator[](i);
  operator[](i)=operator[](j);
  operator[](j)=temp;
}

template<class T> int SSArray<T>::find(const T* t)const
{
  ((SSArray<T>*)this)->candidate=t; // cast away const
  return search();
}

// ****************************
// **** Instantiate Floats ****
// ****************************

struct Floats :
  public virtual BubbleSort,
  public virtual BinaryChop,
  public SSArray<float>
{
  Floats(int n, float *f) : SSArray<float>(n,f){}
};

ostream& operator<<(ostream& out, const Array<float>& a);

SSArray<float>* MakeFloats()
{
 int n;
 float *f;

 cout<<"Making Array of Floats"<<endl<<"Please tell me how many : ";
 cin>>n;

 f=new float[n];
 for(int i=0; i<n; ++i)
 {
   cout<<"Give me float #"<<i<<" : ";
   cin>>f[i];
 }

 return new Floats(n,f);
}

// **********************
// **** Test Routine ****
// **********************


int main()
{
 SSArray<float>& G=*MakeFloats();

 cout<<"Unsorted elements are:"<<endl<<G<<endl;
 G.sort();
 cout<<"Sorted elements are:"<<endl<<G<<endl;

 float x;
 cout<<"Give me a float : ";
 cin>>x;
 while(x!=-1)
 {
   int i=G.find(&x);
   cout<<"Found "<<x<<" at position "<<i<<endl;
   cout<<"Give me another float (-1 terminates): ";
   cin>>x;
 }

 delete &G;
 return 0;
}

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
	Maxtal Pty Ltd,		    CSERVE:10236.1703 
        6 MacKay St ASHFIELD,	    Mem: SA IT/9/22,SC22/WG21 
        NSW 2131, AUSTRALIA	    


Article 20406 of comp.lang.c++:
Xref: sessun comp.std.c++:2371 comp.lang.c++:20406
Newsgroups: comp.std.c++,comp.lang.c++
Path: sessun!uunet!gatech!hubcap!ncrcae!ncrhub2!ncrgw2!psinntp!megatest!mithril!djones
From: djones@megatest.com (Dave Jones)
Subject: Mixins Considered Silly
Message-ID: <C7B5s6.5D6@megatest.com>
Organization: Megatest Corporation
Date: Thu, 20 May 1993 04:28:10 GMT
Lines: 208

The "mixin" concept defers until runtime bindings that can be made at
compile/link time. The cost at runtime is possibly increased execution time.
What is the gain? Well maybe in some situations I guess it might result
in smaller object code, so okay maybe it's not totally silly. But I don't
think it is a revolutionary concept either. FORTH programmers have been
calling everything indirectly for decades.

I've edited the "mixin" example code that Max Skaller posted, changing it
to use templates for abstraction rather than virtual functions.

The resulting source code is 1/3 smaller. That's because the virtual base
class declarations become unnecessary. I will admit that their omission is
not pure gain. They do serve as suplimental documentation as to what is
required of the concrete classes and functions. Indeed C++ could have
been defined to require similar redundancy for the use of templates.
However I don't think I would be in favor of that. Such a declaration for
the "types of classes" that a template could take as parameters would
never be sufficient documentation. A human language description such as the
one at the top of the example source file will always be necessary, whether
templates or virtual functions are used for abstraction.

In the edited mixin example, I took the liberty of coding the
functions BinarySearch, BubbleSort, et cetera, as the functions that they
are, rather than as classes. I also removed the cast-away-const, which IMHO
is a big red flag. The "mixin" search-class needed to make a comparison,
but did not "know" what types of things it was comparing! So it made a
demand on client classes that they squirrel away one of the things to
be compared, and that they find the other. In "mixin" technology,
isn't there a way to mix in a function?

BTW, I have briefly used a commercial library that employs virtual mixins
extensively. When I had questions that the documentation did not
answer to my satisfaction, I found it very hard to figure from the
code what was actually going on. Perhaps when I got used to the convolutions,
the reading would have been easier.

Here is the template version...

#include <iostream.h>
// Mixin example using TEMPLATES: sorting and searching
//
// This software will sort and search an indexed set for which
// some total ordering is defined.
//
// The indices are integers 0..n, for some definite n.
//
// It must be possible to compare the data at locations i and j
// and return -1, 0, or +1 depending on the whether the
// ith element is less than, equal to, or greater than the jth element.
// The comparison MUST yield a total ordering or results are not
// guarranteed.
//
// It must also be possible to exchange the ith and jth elements.
// Note this need not imply moving the elements, exchanging
// the integer associated with an element suffices.
//
// Finally, for the search, it is necessary to compare the ith element
// with the candidate element. (In that order!)
//
// The searches and sorts assume ascending order:
// reverse the sign of compare and test to use descending order

// *****************************
// *** Some Implementations ****
// *****************************

template<class T, class A>
int LinearSearch(const A &a, const T &t)
{
  int n= a.nelements();
  cout<<"Linear Searching "<<n<<" elements"<<endl;
  for(int i=0; i<n; ++i)
  {
    int cmp= compare(t, a[i]);
    if(cmp==0)return i;
    if(cmp>0)return -1;
  }
  return -1;
}

template< class T, class A>
int BinarySearch(const A &a, const T &t)
{
  int n= a.nelements();
  cout<<"Binary Chopping "<<n<<" elements"<<endl;
  int lo=0;
  int hi=n-1;
  while(lo<=hi)
  {
    int mid=(lo+hi)/2;
    int cmp= compare(t, a[mid]);
    if(cmp==0)return mid;
    if(cmp<0)lo=mid+1;
    else hi=mid-1;
  }
  return -1;
}

template<class A>
void BubbleSort( A &a)
{
  int n= a.nelements();
  cout<<"Bubble sorting "<<n<<" elements"<<endl;
  for (int i=0; i<n-1; ++i)
    for(int j=n-2; j>=i; --j)
      if(compare(a[j],a[j+1])>0)
	a.exchange(j,j+1);
}

template<class T>
int compare(const T& a, const T& b)
{
  if(a<b)return -1;
  if(a==b)return 0;
  return 1;
}

template<class T>
class Array {
  T * data;
  int n;
public:
  void exchange(int i, int j);
  int nelements()const {return n;}
  T& operator[](int i){return data[i];}
  const T& operator[](int i)const{return data[i];}
  Array(int _n, T *f):data(f), n(_n) {;}
};

template<class T> void Array<T>::exchange(int i,int j)
{
  T temp=operator[](i);
  operator[](i)=operator[](j);
  operator[](j)=temp;
}

template<class T>
ostream& operator<<(ostream& out, const Array<T>& a)
{
  for(int i=0; i<a.nelements(); ++i)
    cout<<"Elem "<<i<<" is "<<a[i]<<endl;
  return out;
}

// ********************************
// ***** Example Mixin ************
// ********************************

template<class T>
class SSArray : public Array<T>
{
public:
  int find(const T &t)const { return BinarySearch(*this, t); }
  void sort() { BubbleSort(*this); }
  SSArray(int n, T *f) : Array<T>(n,f){}
};


// ****************************
// **** Instantiate Floats ****
// ****************************

ostream& operator<<(ostream& out, const Array<float>& a);

float* MakeFloats(int n)
{
 float *f;

 f=new float[n];
 for(int i=0; i<n; ++i)
 {
   cout<<"Give me float #"<<i<<" : ";
   cin>>f[i];
 }

 return f;
}

// **********************
// **** Test Routine ****
// **********************

typedef SSArray<float> Floats;

int main()
{
 int n;
 cout<<"Making Array of Floats"<<endl<<"Please tell me how many : ";
 cin>>n;

 Floats G(n, MakeFloats(n));

 cout<<"Unsorted elements are:"<<endl<<G<<endl;
 G.sort();
 cout<<"Sorted elements are:"<<endl<<G<<endl;

 float x;
 cout<<"Give me a float : ";
 cin>>x;
 while(x!=-1)
 {
   int i=G.find(x);
   cout<<"Found "<<x<<" at position "<<i<<endl;
   cout<<"Give me another float (-1 terminates): ";
   cin>>x;
 }
 return 0;
}


Article 16023 of comp.lang.c++:
Newsgroups: comp.lang.c++
Path: sessun!uunet!zaphod.mps.ohio-state.edu!rpi!utcsri!cdf.toronto.edu!cdf.toronto.edu!g2devi
From: g2devi@cdf.toronto.edu (Deviasse Robert N.)
Subject: Re: Mixins 
Message-ID: <g2devi.728376456@cdf.toronto.edu>
Keywords: Mixins
Sender: news@cdf.toronto.edu
Nntp-Posting-Host: indepset.cdf
Organization: University of Toronto Computing Disciplines Facility
References: <1993Jan28.192352.26804@ucc.su.OZ.AU> <C1MzEB.1AM@world.std.com>
Date: Sat, 30 Jan 1993 06:47:36 GMT
Lines: 296


John MAX Skaller previously showed how to implement mixins in C++. Well actually
he showed how symmetric mixins are implemented. CLOS mixins are inherently
assymmetric. The difference between symmetric and asymmetric mixins is subtle
but important. In symmetric mixins, mixin parents are equally important. For
example, a graphic_task class is both a graphic object and a tasked object
and neither attribute is important. In asymmetric mixins one parent is more
important than the other. In essence, one parent is the "real" class while 
the other is an adjective. So in a bordered_window class, the main class
is the window while the adjective class is the bordered class.

Fortunately both types of mixins can be simulated in C++. The assymetric mixins
of CLOS depend on sibling calls and the linearization of the method calling
sequence. This "sibling" call can easily be simulated in C++ by the use of
templates. Suprisingly, multiple inheritance is not needed for assymetric
mixins. Ada 9X uses this approach to create mixins since it does not have 
multiple inheritance (the last time I checked).

Both symmetric and asymmetic mixins are important and neither is superior
since the model different class relationships.

Unfortunately, I don't have enough time to describe asymmetric mixins more
fully, but I think the following two examples give the general gist of how
asymmetric mixins are implemented and used.


---------------------- CUT HERE -----------------------

// Example comparing C++ asymmetric mixins with CLOS mixins

#include<iostream.h>
#include<string.h>

/**************************************************************************/
/******************** SEE ECOOP/OOPSLA '90 Proceedings ********************/
/**************************************************************************/

// (defclass Person()
//    (name)
//   )
//
//   (defmethod display((self Person))
//     (display (slot-value self 'name))
//   )
//
class Person{
  private:
    char _name[20];
  public:
    Person() { _name[0]=0; }
    void name(char *name_) { strcpy(_name,name_); }
    void display() const { cout << _name; }
};



// (defclass Graduate_mixin()
//    (degree)
//   )
//   (defmethod display((self Graduate_Mixin))
//      (call-next-method)
//      (display (slot-value self 'degree))
//   )
//
template<class T>
  class Graduate_mixin: public virtual T {
    private:
      char _degree[20];
    public:
      Graduate_mixin() { _degree[0]=0; }
      void degree(char *degree_)  { strcpy(_degree,degree_); }
      void display() const { T::display(); cout << ' ' << _degree; }
  };



// (defclass Graduate(Graduate_mixin Person)
//    ()
//   )
//

class Graduate:public virtual Graduate_mixin<Person> {};




// (defclass Dog()
//    (name)
//   )
//
//   (defmethod display((self Dog))
//     (display (slot-value self 'name))
//   )
//
// (defclass Guard_Dog(Graduate_mixin Dog)
//    ()
//   )
//
class Dog{
  private:
    char _name[20];
  public:
    Dog() { _name[0]=0; }
    void name(char *name_) { strcpy(_name,name_); }
    void display() const { cout << _name; }
};

class Guard_Dog:public virtual Graduate_mixin<Dog> {};



// (defclass Doctor_mixin()
//    (degree)
//   )
//   (defmethod display((self Doctor))
//      (display "Dr. ")
//      (call-next-method)
//   )
//
template<class T>
  class Doctor_mixin: public virtual T {
    public:
      Doctor_mixin() {}
      void display() const { cout << "Dr. "; T::display(); }
  };


// (defclass ResearchDoctor(Doctor_mixin Graduate_mixin Person)
//    ()
//   )

class ResearchDoctor: public virtual Doctor_mixin< Graduate_mixin<Person> > {};


void main(){
  ResearchDoctor fred;
  fred.name("Fred Smith"); fred.degree("Ph. D.");
  fred.display();  cout << endl;

  Guard_Dog fido;
  fido.name("Fido"); fido.degree("Guard Dog 1st Class");
  fido.display();  cout << endl;
}


---------------------- CUT HERE -----------------------

The following example shows a quick example of how asymmetric mixins might
be useful. Note how easily the mixins are combined and how "repeated
inheritance" makes sense.

---------------------- CUT HERE -----------------------

#include<stdio.h>

class Screen{
  private:
    char screen[20][40];
  public:
    Screen() { clear(); }
    void drawDot(int x,int y,char dot) { screen[y][x]=dot; }

    void clear() {
      for(int y=0;y<20;y++)
        for(int x=0;x<40;x++)
           screen[y][x]='.';
    }

    void refresh() {
      for(int y=0;y<20;y++){
        for(int x=0;x<40;x++)
           putchar(screen[y][x]);
        putchar('\n');
      }
    }
};

class Rectangle {
 private:
   int _x0,_y0,_x1,_y1;
 public:
   Rectangle() {}
   Rectangle(Rectangle &r) { *this=r; }
   Rectangle(int x0,int y0,int x1,int y1) : _x0(x0),_y0(y0),_x1(x1),_y1(y1) {}
   void expand() { _x0--,_y0--,_x1++,_y1++; }
   void getEdges(int &x0,int &y0,int &x1,int &y1) const { x0=_x0,y0=_y0,x1=_x1,y1=_y1; }

   virtual void drawOn(Screen &s) {
     for(int x=_x0;x<_x1;x++)
       for(int y=_y0;y<_y1;y++)
         s.drawDot(x,y,'*');
   }
};

class Picture{
 private:
   const char** _bitmap;
   Rectangle _extent;
 public:
   void initialize(Rectangle &r,const char** bitmap) { _bitmap=bitmap, _extent=r; }
   virtual const Rectangle &extent() const { return _extent; }

   virtual void drawOn(Screen &s) {
       int x0,y0,x1,y1;
       _extent.getEdges(x0,y0,x1,y1);
       for(int x=x0;x<x1;x++)
         for(int y=y0;y<y1;y++)
           s.drawDot(x,y,_bitmap[y-y0][x-x0]);
   }

};

template<class T>
 class Bordered_mixin:virtual public T{
   private:
     Rectangle _border;
   public:
     void initialize(Rectangle &r,const char** bitmap) {
        T::initialize(r,bitmap);  _border=T::extent(); _border.expand();
     }

     virtual void drawOn(Screen &s) {
       _border.drawOn(s);                  // "before" method    in CLOS
       T::drawOn(s);                       // "call-next-method" in CLOS
     }

     virtual const Rectangle &extent() const { return _border; }
 };

template<class T>
 class Grayed_mixin:virtual public T{
   public:
     virtual void drawOn(Screen &s) {
       T::drawOn(s);                       // "call-next-method" in CLOS

       int x0,y0,x1,y1;                    // "after" method in CLOS
       T::extent().getEdges(x0,y0,x1,y1);
       for(int x=x0;x<x1;x++)
         for(int y=y0;y<y1;y++)
           if ((x+y)%2)
              s.drawDot(x,y,' ');
     }
 };

const char *bitmap[]={
  " CCCCCC           ",
  " CCCCCC  ++   ++  ",
  " CC      ++   ++  ",
  " CC     ++++ ++++ ",
  " CC     ++++ ++++ ",
  " CCCCCC  ++   ++  ",
  " CCCCCC  ++   ++  "
};

Screen screen;

int main(){
  Picture picture;
  Grayed_mixin<Picture>  gm_picture;
  Bordered_mixin<Picture> bm_picture;
  Grayed_mixin<Bordered_mixin<Picture> > gm_bm_picture;
  Bordered_mixin<Grayed_mixin<Picture> > bm_gm_picture;
  Bordered_mixin<Bordered_mixin<Picture> > bm_bm_picture;

  picture.initialize(Rectangle(2,2,20,9),bitmap);
  gm_picture.initialize(Rectangle(2,2,20,9),bitmap);
  bm_picture.initialize(Rectangle(2,2,20,9),bitmap);
  gm_bm_picture.initialize(Rectangle(2,2,20,9),bitmap);
  bm_gm_picture.initialize(Rectangle(2,2,20,9),bitmap);
  bm_bm_picture.initialize(Rectangle(2,2,20,9),bitmap);

  printf("\n\npicture\n");
  picture.drawOn(screen);       screen.refresh();     screen.clear();

  printf("\n\ngrayed picture\n");
  gm_picture.drawOn(screen);    screen.refresh();     screen.clear();

  printf("\n\nbordered picture\n");
  bm_picture.drawOn(screen);    screen.refresh();     screen.clear();

  printf("\n\ngrayed bordered picture\n");
  gm_bm_picture.drawOn(screen); screen.refresh();     screen.clear();

  printf("\n\nbordered grayed picture\n");
  bm_gm_picture.drawOn(screen); screen.refresh();     screen.clear();

  printf("\n\ndoubly bordered picture\n");
  bm_bm_picture.drawOn(screen); screen.refresh();     screen.clear();

  return 0;
}
-- 
/----------------------------------+------------------------------------------\
| Robert N. Deviasse               |"If we have to re-invent the wheel,       |
| EMAIL: g2devi@cdf.utoronto.ca    |  can we at least make it round this time"|
+----------------------------------+------------------------------------------/

