sra@ecs.soton.ac.uk (Stephen Adams) (07/10/90)
This might be a naive question, but it has been puzzling me for a while. Consider the class integer. This class supports two methods: + which takes another integer and returns the sum image which returns a string denoting the integer as a decimal number so 2+4 -> 6 and (6).image -> "6" Suppose I create a subclass called roman. I provide a new method called image which returns roman numerals e.g. roman_6.image -> "VI". The + operation is inherited from integers. I declare the following variable and initialize it V:roman := make a roman with the value 5 I have two questions: (a) what should (V+V).image yield? "10" or "X"? (V+1).image "6" or "VI"? (1+V).image "6" or "VI" or error (in +)? (b) what do various object oriented systems actually do? If V+V is not a roman (but an integer, 10) then some information has been lost. This might be reasonable but it does seem surprising. -- Stephen Adams S.Adams@uk.ac.soton.ecs (JANET) Computer Science S.Adams@ecs.soton.ac.uk (Bitnet) Southampton S09 5NH, UK S.Adams@sot-ecs.uucp (uucp)
jacob@gore.com (Jacob Gore) (07/11/90)
/ comp.object / sra@ecs.soton.ac.uk (Stephen Adams) / Jul 10, 1990 / The key is that roman is a subclass of integer, and not vice versa. >(a) what should (V+V).image yield? "10" or "X"? "X", because a roman + a roman -> a roman > (V+1).image "6" or "VI"? "VI", because a roman + an integer -> a roman Why? A roman is an integer, so any place an integer can be used, a roman can be used just as well. Thus, "a roman + an integer" automatically gets the type of "a roman + a roman". > (1+V).image "6" or "VI" or error (in +)? "6", according to your definition of +. Not an error because V is a roman and hence an integer, and + is defined for two integers. Jacob -- Jacob Gore Jacob@Gore.Com boulder!gore!jacob
bmcphers@alias.UUCP (Brent McPherson) (07/11/90)
In article <1130012@gore.com> jacob@gore.com (Jacob Gore) writes: >/ comp.object / sra@ecs.soton.ac.uk (Stephen Adams) / Jul 10, 1990 / > >The key is that roman is a subclass of integer, and not vice versa. > > [stuff omitted...] > >> (V+1).image "6" or "VI"? > >"VI", because a roman + an integer -> a roman >Why? A roman is an integer, so any place an integer can be used, a roman >can be used just as well. Thus, "a roman + an integer" automatically gets >the type of "a roman + a roman". > I agree with you on the first and last case but not the second. The second case is incorrect since you cannot automatically convert from a base class to a derived class. Here is a simple example that illustrates the point. Dog is a subclass of mammal (therefore a dog is a mammal). A dog is a mammal, so any place a mammal can be used, a dog can be used just as well. The fundamental flaw in the logic is that every mammal is a dog when only the reverse is true. The solution will vary depending on the facilities offered by your favorite OOPS language. The first solution is to provide an overloaded '+' operator that takes an integer as a second argument (to explicity define what happens in that case). The second solution (allowed by C++) is to define a conversion method to allow the compiler to convert the roman to an integer before performing the addition. ie. C++ first looks for a method/routine where the types of the arguments exactly match the formal parameters. If an exact match is not found, then the compiler will look for conversions to apply to the argument in order to generate an exact match. Finally, if all else fails, an error message is generated. > > >Jacob >-- >Jacob Gore Jacob@Gore.Com boulder!gore!jacob -- Brent McPherson bmcphers%alias@csri.toronto.edu
jimad@microsoft.UUCP (Jim ADCOCK) (07/12/90)
In article <SRA.90Jul10155606@alonzo.ecs.soton.ac.uk> sra@ecs.soton.ac.uk (Stephen Adams) writes: >(a) what should (V+V).image yield? "10" or "X"? > (V+1).image "6" or "VI"? > (1+V).image "6" or "VI" or error (in +)? > >(b) what do various object oriented systems actually do? > C++ provides are variety of ways to allow a programmer to either return an int or a roman in the above example. Generalizing the problem to full polymorphic behavior is quite doable -- but ugly, requiring a double dispatch. Say in general, one wants: aDog = aDog + aDog; but in specific one wants: aPoodle = aPoodleF + aPoodleM; aCockerSpaniel = aCockerSpanielF + aCockerSpanielM; aCockapoo = aPoodleF + aCockerSpanielM; aCockapoo = aCockerSpanielF + aPoodleM; --So one can end up specifying a lot of flavors of "+" to get exactly the behavior one wants. [I'm using inter-breeding as a metaphor -- I'm not suggesting the above is a good overloading of "+"] --- void image(int i) { printf("%d\n", i); } class roman1 { protected: int i; public: roman1(int ii) : i(ii) {} operator int() { return i; } // a simplified version of roman numerals -- works for small positive ints :-) friend void image(roman1 r) { while (r.i--) printf("I"); printf("\n"); } }; class roman2 : public roman1 { public: roman2(int i) : roman1(i) {} friend roman2 operator+(int i, roman2 r2) { return i + r2.i; } }; main() { int anInt = 1; roman1 aRoman1 = 2; image(anInt + aRoman1); // prints "3" roman2 aRoman2 = 2; image(anInt + aRoman2); // prints "III" return 0; }
gilstrap@swbatl.sbc.com (Brian Gilstrap - UCI - 5-3929) (07/12/90)
Jacob Gore's comments have one '>' Stephen Adams' have two '>'s [1] >>(a) what should (V+V).image yield? "10" or "X"? >"X", because a roman + a roman -> a roman [2] >> (V+1).image "6" or "VI"? >"VI", because a roman + an integer -> a roman >Why? A roman is an integer, so any place an integer can be used, a roman >can be used just as well. Thus, "a roman + an integer" automatically gets >the type of "a roman + a roman". This statement doesn't make sense to me. (IMHO) What's really going on here is simply a precedence rule: "In a binary operator, if the second argument can be converted to the same type/class as that of the first, then use the type of the first argument as the default result type." [3] >> (1+V).image "6" or "VI" or error (in +)? >"6", according to your definition of +. Not an error because V is a roman >and hence an integer, and + is defined for two integers. Again, the same precedence rule. I could easily see a language where the default was convert the Roman to an Integer no matter if it's first or second (least common denominator) OR convert the Integer to an Roman no matter if it's first or second (I guess you could call this "specialization of results") Just because C++ approaches things the way described above doesn't mean it has to be that way. By the way, this isn't meant to be flammage. Please correct me if I've missed something. Brian R. Gilstrap gilstrap@swbatl.sbc.com gilstrap@swbatl.uucp ...!{texbell,uunet}!swbatl!gilstrap
pkr@media01.UUCP (Peter Kriens) (07/12/90)
Roman nummerals and integers, What is the result of 1 + V and V + 1? Isn't the fact that this problem is exactlt what Smalltalk does with coercion? In Smalltalk each class under Number gets a priority. When you are doing arithmetic with any number, it will compare the numbers and coerce the lower number into a new type of the higher number. This way the class itself can decide what the result is of V+1. So if V would return a higher priority than the integer 1, the 1 would be coerced into a roman nummeral and then the add message would be send again. It is some time ago that I looked into this matters, but as far as I remember this is the way it works in Smalltalk and CO2. Peter Kriens
jacob@gore.com (Jacob Gore) (07/12/90)
/ comp.object / sra@ecs.soton.ac.uk (Stephen Adams) / Jul 10, 1990 / Let me try this again, since what I said before makes no sense to me either... I'm only talking about the effect of inheritance on the problem, so I assume that the language does not use double dispatching, upward coersion, or overloading (i.e., there is only one "+" operation per class). > + which takes another integer and returns the sum > image which returns a string denoting the integer > as a decimal number > > so 2+4 -> 6 and (6).image -> "6" I also assume that "2+4" means "(2).add(4)". Now, since the compiler does no implicit type conversion, the type of the result and the operand of each operation depends on the programmer of that operation, rather than by the compiler. So, here's how I'd do it: > (a) what should (V+V).image yield? "10" or "X"? I would define "+" as: + : Like Self x Like Self --> Like Self so "V+V" returns a roman, hence (V+V).image returns "X". > (V+1).image "6" or "VI"? With my definition of "+", this would be an error. "Like Self" is Roman for V, and an Integer is not an acceptable replacement for a Roman. (Of course, if this was a common enough operation, "+" would be better defined as +: Like Self x Integer --> Like Self or +: Like Self x Integer --> Integer.) > (1+V).image "6" or "VI" or error (in +)? This would return "6". "Like Self" is Integer, so no conversions are needed: V is a Roman and hence an Integer. There are, of course, many other ways of doing it. I feel this one is most natural for the set of assumptions that I made. Jacob -- Jacob Gore Jacob@Gore.Com boulder!gore!jacob
matt@bacchus.esa.oz (Matthew Atterbury) (07/13/90)
In article <1990Jul11.184517.16505@swbatl.sbc.com> gilstrap@swbatl.UUCP (Brian Gilstrap - UCI - 5-3929) writes: > >I could easily see a language where the default was > > convert the Roman to an Integer no matter if it's first or second > (least common denominator) Why stop at Integer? Assuming the Smalltalk hierarchy, why not convert it to a Number, then to an Object? Applying this reasoning would lead to the result of all operations being of type Object ie. a TYPELESS language! Or are you suggesting full expression analysis to see what the most general class is? >OR > convert the Integer to an Roman no matter if it's first or second > (I guess you could call this "specialization of results") Similarly, why stop at Roman? What if there is a subclass of Roman - then all Integers and Romans would be converted to it, and if you subclassed that one later, all your earlier operations would be reconverted. What if Integer has a number of subclasses - which one? Or, again, are you suggesting full expression analysis to see what the most specific class is? >Just because C++ approaches things the way described above doesn't mean it >has to be that way. Smalltalk works like this also. If you are suggesting expression analysis, what if you get two classes that are NOT in very close subtrees of the class hierarchy? Do you then say that the most general form is (probably) Object so the result is converted to Object? And what is the most specific form? Basically, I can see how you could argue for your suggestion given the very simple example of Integer and Roman, but in the context of a class hierarchy, it seems unworkable. The expression: "1 + 2" says (sort of); expression evaluator: hello object of type integer of value 1. I have here an object of type integer with value 2. will you please perform the '+' operator with it, WHATEVER THAT MEANS TO YOU (coz *I* don't know), and tell me the result? integer class: OK. here's the result. (BTW, it's an object of type integer with value 3). In smalltalk (and all "real" OO languages IMHO), even integer operations like '+' are left to the "target" object to perform - they are NOT evaluated by some global omniscient 'expression evaluator'. If Integer decided that the result of adding a Roman to itself ought to be a Roman, it could do the conversion itself - NOTE that this decision is up to Integer, NOT anyone else. Well, this *was* going to be a short reply. Sorry for rambling on & on & on ... -- ------------------------------------------------------------------------------- Matt Atterbury [matt@bacchus.esa.oz.au] Expert Solutions Australia, Melbourne UUCP: ...!uunet!munnari!matt@bacchus.esa.oz.au "klaatu barada nikto" ARPA: matt%bacchus.esa.oz.AU@uunet.UU.NET "life? don't talk to me about life!"
barmar@think.com (Barry Margolin) (07/13/90)
In article <SRA.90Jul10155606@alonzo.ecs.soton.ac.uk> sra@ecs.soton.ac.uk (Stephen Adams) writes: >If V+V is not a roman (but an integer, 10) then some >information has been lost. I don't agree. + is a function that maps from <integer,integer> to integer. When roman inherits this operation, it can generally only deal with the "integerness" of roman numbers. The integer class doesn't know that the roman class exists, so how could integer.+ produce a roman? Virtual functions can allow base classes to operate at the descendents' levels in some ways, but it can get pretty difficult to delegate all the right things. In your example the + function isn't being overridden by the derived class, so what virtual functions might it call that would do the right thing? And in the V+1 and 1+V cases, how would this generic plus know whether to call the virtual function of the left or right argument (I think CLOS multimethods allow the priority of the arguments to be specified in the generic function definition), or how do you make the order irrelevant? Yes, information is lost. Consider what would happen if the subclass also has additional data, rather than just overriding a method. For instance, suppose there were a flag slot in the roman class that indicated whether it should be printed in the old style ("IIII" rather than "IV"). How could integer.+ know how to fill in this instance variable? I suppose it could let this default, but you're still losing information, since you'd expect that two romans with the same style should sum to another with that style. Actually, that wouldn't be a good way to implement the two styles, but the object-oriented way also has a similar problem. In this case, we'd make another subclass of integer called "old-roman", which also only overrides the image function and inherits integer.+. Now, what would you expect IIII+IV to return? In fact, it would be reasonable to make old-roman a subclass of roman, but it would be just as reasonable to go the other way. Therefore, even if we were to define a mechanism where the result of the addition were the most recent common ancestor of the two arguments, there's no inherent reason why IIII+IV should pick one or the other as the result type. And what if the most common ancestor were an abstract class; for instance, suppose there were an intermediate class, roman-without-4, which would be abstract because it doesn't know how to display 4 (it would have a pure virtual function image4). So, in general, using an inherited operation tends to be an information-losing mechanism. It's easy to move up the inheritance hirarchy, but hard to move back down. -- Barry Margolin, Thinking Machines Corp. barmar@think.com {uunet,harvard}!think!barmar
bertrand@eiffel.UUCP (Bertrand Meyer) (07/14/90)
Just a note on how this is understood in Eiffel, with no attempt to compare with other object-oriented languages. (Sorry, it is longer than originally anticipated, since it starts from the basic ideas.) As part of the paradigm, every operation has one or more arguments, and one of them, the ``target'' of the operation, plays a special role. This convention makes it possible to unify the concepts of module and type into a single one - the concept of class. A class is a module, packaging together a set of facilities; it is also a type, describing a set of potential run-time instances. By accepting that every operation ``applies to'' one distinguished target, we can merge the two notions by considering that the facilities packaged in the class (viewed as a module) are precisely the operations ``applying to'' individual instances of the class (viewed as a type). This is somewhat constraining, sometimes forcing us to choose ``the'' target of a multi-argument operation in apparently arbitrary ways, but serves as a powerful structuring facility and opens the road to many other properties, in particular inheritance. The convention is reflected in the standard syntax for application of operations (features): dot notation, as in /1/ document.print (my_macro_package, my_printer) where the target appears before the period, and any further arguments appear in parentheses after the operation name. Dynamic binding is also predicated on the ``single target'' assumption: if there is more than one version of an operation applicable to the target, the semantics of object-oriented computation prescribes that the choice be made on the basis of the run-time form of the object to which the target is attached. For example, if there are various types of documents, each described by a different class, and these classes provide different versions of the feature `print', then the execution of /1/ will select the appropriate version on the basis of the run-time type of `document'. Not surprisingly, the decision to base dynamic binding on the type of just one argument (the target) is subject to criticism. What if multi-criterion discrimination is desired? But this convention keeps things simple, and the few examples I have seen of mechanisms attempting to support dynamic binding on more than one argument were not convincing. Using dot notation for an arithmetic operation might give something like /2/ i.plus (j) with dynamic binding on the first argument only. The type of the result of /2/ is the type declared for the result of function `plus', as defined or redefined in the class corresponding to the dynamic type of `i'. The Eiffel notation for infix routines makes it possible to use standard syntax instead of /2/: /3/ i + j If i is declared of type C, this assumes that the declaration of the feature in C uses a name of the form `infix "+"' rather than `plus': /4/ infix "+" (other: C): C is -- Sum of current element and `other' do ... Implementation of addition ... end -- "+" This is indeed the kind of declaration found in Kernel Library classes such as INT, describing integers, FLOAT, describing floating-point reals, etc. (As readers familiar with Eiffel will know, we might in some cases prefer to declare `other' and the result as being of type `like Current' rather than C.) The ``infix'' mechanism (as the similar ``prefix'' mechanism) is, however, purely syntactical. /3/ is a mere equivalent for /2/, with the only difference that the feature was declared with name `infix "+"' rather than `plus'. In both /2/ and /3/, the choice of the version to be applied depends solely on the type of `i'. The type of `j' plays no role. As with /2/, the type of the result of /3/ is the type declared for the result of `infix "+"' in the class corresponding to the dynamic type of the object to which `i' is attached at the time of execution. If that class is a descendant of C, this result type must itself be a descendant of C. (A descendant of a class is the class itself, or a direct or indirect heir.) -- Bertrand Meyer bertrand@eiffel.com
bobatk@microsoft.UUCP (Bob ATKINSON) (07/17/90)
In article <1130013@gore.com> jacob@gore.com (Jacob Gore) writes: >/ comp.object / sra@ecs.soton.ac.uk (Stephen Adams) / Jul 10, 1990 / >(Of course, if this was a common enough operation, "+" would be better >defined as > +: Like Self x Integer --> Like Self >or > +: Like Self x Integer --> Integer.) I have run across a similar desire in C++ for a "same type as receiver" type expression in constructing collection classes. For example, I would like to express the fact that all collections can return a copy of themselves. Naturally, I would like to put this declaration in the same class in which I express the other fundamental collection operations, such as, for example, insertion of elements or enumeration. This is in class Collection. Thus, I am tempted to write: class Collection { public: virtual Collection* Copy(); }; but of course, this gives the incorrect return type, since expressions of the form class Set : public Collection { /* ... */ }; //... Set* pset = pSomeOtherSet->Copy(); give a type error. What I really want to say is something like class Collection { public: virtual typeof(*this)* Copy(); }; Though I have only thought about it in briefly, I believe this interacts cleanly with the automatic type conversions of Derived* to Base*. It strikes me that the typeof() operator might be generally useful in other situations as well. One might ask if parameterized types would allow us to express this construction. I don't see how the current parameterized type proposal would accomplish it. Bob Atkinson Microsoft
sakkinen@tukki.jyu.fi (Markku Sakkinen) (07/26/90)
In article <SRA.90Jul10155606@alonzo.ecs.soton.ac.uk> sra@ecs.soton.ac.uk (Stephen Adams) writes: >This might be a naive question, but it has been puzzling me >for a while. Consider the class integer. This class >supports two methods: > > + which takes another integer and returns the sum > image which returns a string denoting the integer > as a decimal number > >so 2+4 -> 6 and (6).image -> "6" > >Suppose I create a subclass called roman. I provide a new >method called image which returns roman numerals e.g. >roman_6.image -> "VI". The + operation is inherited from >integers. This is a very good question, in fact. The great majority of OO languages treats basic types such as integer differently from ordinary classes. There are two main approaches: 1. Simula and many others (including C++ and Eiffel) don't even pretend that 'integer' is a class; thus you cannot create any subclasses from it. 2. Smalltalk and some other languages pretend that 'integer' is a class just like any other. However, it is almost impossible to define subclasses that make any sense (I'll qualify this below). The problem at hand means that it is only desired to override one superclass method in the subclass, thus instances of the subclass should be completely similar to instances of the superclass. If OOP is as great for code reuse as advertised, then clearly one should not be required to write anything but the overriding method in the subclass definition. In Smalltalk-80, Integer happens to be an abstract class, so in Smalltalk we must take some concrete subclass (e.g. SmallInteger) to stand for 'integer' above. (The problem is different for an abstract superclass: '+' may not be implemented there at all, and indeed it isn't in Smalltalk's Integer class.) The instances of such Smalltalk classes as SmallInteger are immutable, and they are conceptually never created; all occurences of e.g. '5' can be regarded to refer to the same immutable object. It would seem to me that if one defines Roman as a subclass of SmallInteger, there is no way to create an instance of Roman with a given value. It appears that for the problem to be solvable, 'integer' must be a user-defined class both in Simula-like and Smalltalk-like languages. Let's call it 'MyInteger' to make this clear. It will obviously need exactly one instance variable, which is an ordinary integer. It will also need an initialisation method (constructor in C++). The '+' method must evidently create a new instance of MyInteger for its return value, just like 'image' must create a new string instance. >I declare the following variable and initialize it > > V:roman := make a roman with the value 5 > >I have two questions: > >(a) what should (V+V).image yield? "10" or "X"? > (V+1).image "6" or "VI"? > (1+V).image "6" or "VI" or error (in +)? > >(b) what do various object oriented systems actually do? > > >If V+V is not a roman (but an integer, 10) then some >information has been lost. This might be reasonable but it >does seem surprising. (b) Because we need the user-defined class MyInteger, _both_ 'V+1' and '1+V' will in most languages cause an error (at compile or run time depending on whether the language is statically typed or not). The integer '1' must therefore first be converted into a MyInteger. However, at least C++ will do automatic conversions if appropriate conversion operators have been defined. (a) Since you do not override '+' but inherit the superclass method, which returns a MyInteger, you will get the first alternative in all cases. If you do redefine '+' in Roman to yield a Roman result (with a MyInteger second operand) you will get the second alternative except in the last case. (In C++ however, if '+' is _virtual_ in MyInteger, you are not allowed to change the result class in the overriding method.) In C++ you can actually define distinct methods for each of the three above operand type pairs and give each of them exactly the result type that you like, independently. The appropriate method will then be selected at compile time; so if you use pointers to objects, the actual run-time class of the objects pointed to has no effect. - In CLOS, the "multi-method" principle means that you can also define different methods for different type pairs, but the selection will happen at run time based on the actual classes of the objects. By suitably defining several >Stephen Adams S.Adams@uk.ac.soton.ecs (JANET) >Computer Science S.Adams@ecs.soton.ac.uk (Bitnet) >Southampton S09 5NH, UK S.Adams@sot-ecs.uucp (uucp) It really wasn't too naive at all! Markku Sakkinen Department of Computer Science University of Jyvaskyla (a's with umlauts) Seminaarinkatu 15 SF-40100 Jyvaskyla (umlauts again) Finland SAKKINEN@FINJYU.bitnet (alternative network address)
bertrand@eiffel.UUCP (Bertrand Meyer) (07/26/90)
From <1990Jul26.120125.7955@tukki.jyu.fi> by sakkinen@tukki.jyu.fi (Markku Sakkinen): > Simula and many others (including C++ and Eiffel) don't even pretend > that 'integer' is a class. This is not quite correct with respect to Eiffel. INTEGER is an ``expanded type'' based on class INT, itself declared in the Kernel Library as class INT export infix "+", infix "-", ... prefix "+", prefix "-", infix "<", infix "<=", ... inherit COMPARABLE; FLOAT_CONV feature infix "+" (other: INT): INT is ... etc. end -- class INT Type INTEGER itself is an abbreviation for ``expanded INT'', meaning that instances of INTEGER do not need to be allocated dynamically, the way instances of a class type such as INT do. This was not described in the book ``Object-Oriented Software Construction'', which still treated integers and three other basic types in a special way, as implied by Mr. Sakkinen. However the full type system of Eiffel, with the above characteristics, is described in the current reference on the language, ``Eiffel: The Language'' (August 1989) and in an earlier document entitled ``Eiffel Types'' of which a quasi-final version was posted in comp.lang.eiffel on April 2, 1989 (message id <133@eiffel.UUCP>). The language definition treats class INT and its colleagues (CHAR, FLOAT, BOOL, DFLOAT) as normal classes, which may have descendants. In Interactive's current Eiffel implementation, there are still some limitations on writing classes that inherit from INT and the like; these are corrected, however, in the forthcoming release of our compiler. All this was done with the explicit aim of making the Eiffel type system completely consistent, and uniformly based on the notion of class. -- Bertrand Meyer bertrand@eiffel.com
jimad@microsoft.UUCP (Jim ADCOCK) (07/28/90)
In article <1990Jul26.120125.7955@tukki.jyu.fi> sakkinen@jytko.jyu.fi (Markku Sakkinen) writes: >In article <SRA.90Jul10155606@alonzo.ecs.soton.ac.uk> sra@ecs.soton.ac.uk (Stephen Adams) writes: >1. Simula and many others (including C++ and Eiffel) don't even pretend > that 'integer' is a class; thus you cannot create any subclasses > from it. Yes, except with about a page of code C++ allows you to turn the built-in primitive 'int' [or other primitive] into a a true class 'Int' than acts 'identical' to an int, but now is a full-class class, and can be subclassed. See Hanson "The C++ Answer Book" for the 'right' way to do this. >In C++ you can actually define distinct methods for each of the three >above operand type pairs and give each of them exactly the result type >that you like, independently. The appropriate method will then be selected >at compile time; so if you use pointers to objects, the actual run-time >class of the objects pointed to has no effect. Yes and no -- it depends on how you program it. Using the matrix/vector example, one might want to define something like: matrix& operator*(matrix& m, vector& v); matrix& operator*(matrix& m, matrix& v); .... where matrix and vector are really appropriate protocols. Then one could define various concrete classes answering these protocols: packed_matrix, sparse_matrix, packed_vector, packed_matrix.... and the overloaded operators make sure that the right protocols get selected when something like: a_sparse_matrix_ref * a_packed_vector_ref; is written. In general, then one has to explicitly program to get a virtual virtual function dispatch off both the left hand side and the right hand side in order to get to the actual do-the-work function, say: matrix& MpySparseMatByPackedVector(sparse_matrix& m, packed_vector& v). But, the nice thing is that the protocols are type-checked at compile time so that things like: a_sparse_matrix_ref * a_banana_ref; are caught at compile time [ assuming bananas aren't part of the math system you want to define :-] The real problem is that unless one is clever, one ends up implementing O(n^2) actual add or multiply routines that do the hard work. "Clever" in this particular example *might* mean making operator[] virtual, so that multiply and add routines can be written that don't care about the sparse-ness or packed-ness of a matrix or vector. This might reduce the problem such that there are only four flavors of each of add, sub, mpy, ....