The software distribution for Sod contains two main parts:
\begin{itemize}
-\item a translator, or preprocessor, similar in spirit to \manpage{lex}{1} or
- \manpage{yacc}{1}, which reads input files containing class definitions,
- and writes C source code and header files; and
+\item a translator, or preprocessor, similar in spirit to \man{lex}{1} or
+ \man{yacc}{1}, which reads input files containing class definitions, and
+ writes C source code and header files; and
\item a very small runtime library, containing the built-in base classes and
some simple utility macros and functions for working with instances and
classes.
growing new `safety' features.
\end{itemize}
+\subsection{Comparison with other object systems}
+
+Sod's object system is significantly different in flavour\footnote{%
+ The pun was unintentional, but I'm happy with it.} %
+from most popular object-ish languages. Indeed, it bears far more similarity
+to Flavors, CLOS, and Dylan than to \Cplusplus, \Csharp, or Java (and still
+less to Go or Rust).
+
+Of the popular languages, \Cplusplus's object system is probably closest to
+Sod. Both are statically compiled, statically typed, implement single
+dispatch, and have relatively simple runtime metaprogramming facilities.
+\Cplusplus\ has a rich compile-time template metalanguage; Sod instead allows
+compile-time metaprogramming in Common Lisp, which is probably less
+convenient for simple cases but rather more pleasant for doing difficult
+things. Significantly, Sod has the @|SodObject| class, of which all other
+classes\footnote{%
+ Unless you construct a new root class of your own, which you can totally
+ do, but it's hard work.} %
+are subclasses; \Cplusplus\ has no such root class.
+
+Both systems provide multiple inheritance, but go about it very differently.
+The most important difference is that \Cplusplus\ provides only \emph{static
+ delegation}: if you have a class @|B| which defines some (virtual) member
+function @|f|, and a derived class @|D| which wants to \emph{extend} the
+behaviour of @|f| on instances of @|D|, then you must explicitly call @|B::f|
+at the appropriate point:
+\begin{prog}
+ \#include <iostream> \\+
+ %
+ class B \{ \\
+ public: \\ \ind
+ virtual void f() \{ std::cout <{}< "B@\\n"; \} \\
+ virtual @~B() \{ \} \-\\
+ \}; \\+
+ %
+ class D: public B \{ \\
+ public: \\ \ind
+ void f() \{ B::f(); std::cout <{}< "D too@\\n"; \} \-\\
+ \};
+\end{prog}
+
+This works adequately when only single inheritance is involved. But if we
+now introduce multiple inheritance, we see the problem.
+\begin{prog}
+ \#include <iostream> \\+
+ %
+ class B \{ \\
+ public: \\ \ind
+ virtual void f() \{ std::cout <{}< "B@\\n"; \} \\
+ virtual @~B() \{ \} \-\\
+ \}; \\+
+ %
+ class X: virtual public B \{ \\
+ public: \\ \ind
+ void f() \{ B::f(); std::cout <{}< "X after@\\n"; \} \-\\
+ \}; \\+
+ %
+ class Y: virtual public B \{ \\
+ public: \\ \ind
+ void f() \{ std::cout <{}< "Y before@\\n"; B::f(); \} \-\\
+ \}; \\+
+ %
+ class D: public X, public Y \{ \\
+ public: \\ \ind
+ void f() \{ X::f(); Y::f(); \} // \comment{oh, dear} \-\\
+ \};
+\end{prog}
+The above prints
+\begin{prog}
+ B \\
+ X after \\
+ Y before \\
+ B
+\end{prog}
+which is unlikely to be what was wanted: `B' prints twice, and the `before'
+and `after' actions are both in the middle.\footnote{%
+ Of course, one could have arranged to call @|Y::f| before @|X::f| -- but
+ the important point is that one would have needed to \emph{know} that this
+ was necessary. And you still end up with two copies of `B'.} %
+The problem is that correctly composing behaviour from a collection of
+superclasses requires knowledge of all of the superclasses involved and how
+they're supposed to work together. Messing with virtual base classes has
+eliminated the problem of duplicating @|B|'s state, but has done nothing to
+help avoid duplicating @|B|'s \emph{behaviour} -- which is a shame, because
+duplicating one without the other is going to end badly.
+
+The obvious workaround is to separate the functionality -- here, printing the
+messages -- from the plumbing, which arranges to do everything in the right
+order. You'd end up with a @|_f| member function in each class which wanted
+print something, and then every class would have a virtual @|f| which calls
+the various @|_f| functions in the right order, like this:
+\begin{prog}
+ \#include <iostream> \\+
+ %
+ class B \{ \\
+ protected: \\ \ind
+ void _f() \{ std::cout <{}< "B@\\n"; \} \-\\
+ public: \\ \ind
+ virtual void f() \{ _f(); \} \\
+ virtual @~B() \{ \} \-\\
+ \}; \\+
+ %
+ class X: virtual public B \{ \\
+ protected: \\ \ind
+ void _f() \{ std::cout <{}< "X after@\\n"; \} \-\\
+ public: \\ \ind
+ void f() \{ B::_f(); _f(); \} \-\\
+ \}; \\+
+ %
+ class Y: virtual public B \{ \\
+ protected: \\ \ind
+ void _f() \{ std::cout <{}< "Y before@\\n"; \} \-\\
+ public: \\ \ind
+ void f() \{ _f(); B::_f(); \} \-\\
+ \}; \\+
+ %
+ class D: public X, public Y \{ \\
+ public: \\ \ind
+ void f() \{ Y::_f(); B::_f(); X::_f(); \} \-\\
+ \};
+\end{prog}
+This is clearly much more cumbersome. Most disastrously, it spreads
+knowledge about how the various classes' contributions to the behaviour of
+@|f| fit together throughout the class graph. Also, even this approach is
+only suitable for especially simple cases. Suppose @|Y| needed to add
+behaviour before \emph{and} after @|B| -- maybe @|Y| is taking out a lock,
+and then releasing it. Then this approach won't work any more; indeed, it's
+hard to see any way to make this work without spreading knowledge about
+@|Y|'s lock everywhere.
+
+Compare Sod's approach.
+\begin{prog}
+ code c: includes \{ \\
+ \#include <stdio.h> \\-
+ \#include <sod.h> \\
+ \#include "foo.h" \\
+ \} \\+
+ %
+ class B: SodObject \{ \\ \ind
+ void f() \{ puts("B"); \} \-\\
+ \} \\+
+ %
+ class X: B \{ \\ \ind
+ void b.f() \{ CALL_NEXT_METHOD; puts("X after"); \} \-\\
+ \} \\
+ %
+ class Y: B \{ \\ \ind
+ void b.f() \{ puts("Y before"); CALL_NEXT_METHOD; \} \-\\
+ \} \\+
+ %
+ class D: X, Y \{ \}
+\end{prog}
+This prints
+\begin{prog}
+ Y before \\
+ B \\
+ X after
+\end{prog}
+as (I think) you'd hope. @|CALL_NEXT_METHOD| here does the job of figuring
+out what to do next, according to some rather complicated rules
+(described in full in \xref{sec:concepts.methods.combination}).
+
+Indeed, there's an even better way to write this particular case with Sod,
+because Sod has dedicated \emph{method rĂ´les}.
+\begin{prog}
+ code c: includes \{ \\
+ \#include <stdio.h> \\-
+ \#include <sod.h> \\
+ \#include "foo.h" \\
+ \} \\+
+ %
+ class B: SodObject \{ \\ \ind
+ void f() \{ puts("B"); \} \-\\
+ \} \\+
+ %
+ class X: B \{ \\ \ind
+ [role = after] void b.f() \{ puts("X after"); \} \-\\
+ \} \\
+ %
+ class Y: B \{ \\ \ind
+ [role = before] void b.f() \{ puts("Y before"); \} \-\\
+ \} \\+
+ %
+ class D: X, Y \{ \}
+\end{prog}
+
%%%--------------------------------------------------------------------------
\section{About this manual}