Letters to the editor may be sent via email to cujed@mfi.com, or via the postal service to Letters to the Editor, C/C++ Users Journal, 1601 W. 23rd St., Ste 200, Lawrence, KS 66046-2700.
Dear CUJ,
David Gould's article on double dispatching in the May CUJ was interesting, but like many before him, David confuses the GOF Visitor Pattern with the more general topic of double dispatching. As the latter is a special interest of mine, I feel obliged to set the record straight.
My fundamental concern is this sentence:
"A celebrated solution to the problem of double dispatch is the Visitor pattern..."
Unfortunately, the Visitor pattern doesn't solve the problem of double dispatch, it solves the problem of needing to be able to add virtual-acting functions to a closed hierarchy. If you agree with the informal definition of a pattern used by many in the patterns community, a pattern is "a solution to a problem in a context." Technically speaking, I guess there's no reason why one pattern can't solve more than one problem, but people generally assume that each pattern solves a different problem. That being the case, it's important not to muddy the waters regarding which problem Visitor solves. If people come to believe that Visitor solves the double dispatching problem, they're less likely to remember that its original purpose was to solve a very different problem.
In his article summary, David states that "The Visitor pattern is an effective implementation of double dispatch." I believe this is precisely backwards. A particular manifestation of double dispatching (two virtual function calls) is used to implement the Visitor pattern. That is, Visitor is implemented via double dispatching, not vice versa. There are several other ways to implement double dispatching, and Visitor-like patterns could be implemented in terms of them, too, but Visitor itself could not. Visitor is, after all, "a solution to a problem in a context," so a different solution to the same problem would be, by definition, a different pattern. (Similarly, a set can be implemented via a hash table or via a linked list, but they are not the same design or data structure.)
Perhaps this all sounds like semantics gymnastics. I don't think it is. One of the most powerful aspects of patterns is that they raise the level of abstraction when talking about software designs. If somebody tells me they used pattern X, if I know what X is, I immediately know a lot about the problem that was being solved and the constraints affecting the potential solutions. So if somebody tells me they used Visitor, I should be able to assume they had a fixed hierarchy to which they needed to be able to add virtual functions. I'd probably also assume that they needed to be able to traverse an object structure while invoking these new virtual functions, because such traversals are how Visitor got its name in the first place.
But if some people say they use Visitor to solve the double dispatching problem, the pattern name becomes less precise, and I have to inquire about the specific problem being solved and the set of constraints in existence. I no longer know if there is a closed hierarchy or if traversal was part of the problem. My ability to communicate with the person describing their design is impeded. This is why terminological precision is important. (It is also why I nearly died when I learned that Win32 defines the term "critical section" in a way that's inconsistent with every standard historical use of the term. As a result, when a Windows programmer talks about a critical section, listeners familiar with the conventional definition must inquire about precisely what is meant. This is not progress.)
Readers interested in the general problem of double dispatching should know that the most extensive treatment of the topic for C++ can be found in David Chatterton's forthcoming doctoral thesis, "Dynamic Dispatch in Existing Strongly-Typed Languages." A more accessible reference is Chatterton's and Conway's "Multiple Dispatch in C++ and Java," available at http://www.cs.monash.edu.au/~davidc/tools21.ps.gz. What I hope is a reasonably thorough treatment of the matter can be found in my More Effective C++: 35 New Ways to Improve Your Programs and Designs (Addison-Wesley, 1996), pp. 228-251.
Readers interested in more detailed information on the Visitor Pattern and its variations may wish to consult the following references:
"Visiting Rights," John Vlissides, C++ Report, September 1995, pp. 12-16.
"The Trouble with Observer," John Vlissides, C++ Report September 1996, pp. 20-24.
"Acyclic Visitor," Robert Martin. Available at http://www.oma.com/PDF/acv.pdf.
"Visitors Revisited," Patrice Gautier, C++ Report, September 1996, pp.37-45.
"Default and Extrinsic Visitor," Martin Nordberg III, in Pattern Languages of Program Design 3 (PLoP 3) (Addison-Wesley), 1998, ISBN 0-201-31011-2, pp. 105-123.
"Yet Another Visitor Pattern," Jack Reeves, C++ Report, March 1998.
Yes, that's a lot of references, but Visitor is an interesting pattern. However, it shouldn't be thought of as the same as double dispatching.
Scott Meyers
After rereading the chapter on Visitor in Gamma et al's Design Patterns, I must concur. It is an error to think of the Visitor pattern as an architecture that can be used to implement double dispatch. That said, I think it is a pretty subtle error. It comes from confusing what is a very common implementation of Visitor with the Visitor pattern itself. This is actually very easy to do. For example, if you look at the chapter on Visitor in Design Patterns, you will find a big diagram of a class hierarchy (which happens to implement double dispatch), strategically labeled with the heading "Structure." Were I as naive as I was before reading your letter, I would have naturally assumed this diagram represented the "structure" of the Visitor pattern. It doesn't. It represents the structure of but one implementation of the Visitor pattern. (Sigh.) A picture may be worth 1000 words, but those 1000 words don't have to be right.
In further defense of David Gould, one of the things his article showed was how to add new GUI elements (buttons, boxes, and the like) to a fixed hierarchy of events, without modifying the event hierarchy. This is, in a sense, turning the Visitor pattern on its head: Visitor seeks to add new operations to a fixed hierarchy of objects. So Gould described his technique as an "inverted Visitor" pattern, in an attempt to convey what it did. The more correct "inverted double dispatch" would not have conveyed anything meaningful. We probably would have been in the clear if we had called it a "Visitor-like" pattern or an "Inverted Visitor-like" pattern. Thanks for enlightening us. mb
CUJ,
In the "We have mail" section of the February 1998 issue of CUJ, Andre Oughton and Denton Karle both wrote about pointers and references. Oughton asked which of these is better:
void foo1(int *myVal); void foo2(int &myVal);The first requires the client to write an explicit & on the argument to foo1, while foo2 doesn't.
Mr. Plauger responded by saying that he generally prefers to use an explicit pointer, and I agree. It's harder to mistake an explicit & for anything but pass-by-address, while it's not clear at all whether a function is being passed just a reference or a value since the syntax is the same for both.
On the other hand, many programmers feel that passing a const argument should look and feel like it's being passed by value. To wit, they prefer fooB over fooA:
void fooA(int myVal); void fooB(const int &myVal);The syntax for calling fooA and fooB are identical. The difference is that fooA receives a copy of the argument you pass it, while fooB receives a pointer (reference) to the argument. If myVal is a more complicated type, such as a class type, the difference can impact performance; the reference is faster. So sometimes using a const reference is okay.
Another thing I should point out is that references can be more dangerous than pointers. By its nature, once a reference has been established (seated) to an object, it can never be changed. Pointers, on the other hand, can be changed. This is extremely important if the object being referenced or pointed to is destructed. A pointer to a deleted object can be reset to NULL, but a reference to such an object can't be reset and becomes a dangling reference.
So programmers should choose carefully between pointers and references. I generally limit my use of reference variables to constructor and assignment operator arguments, and use pointers for everything else.
I stated that references can't be reseated; that's not entirely true. There is a loophole in the language that allows reference variables to be changed. The following code illustrates:
class Foo { public: Foo(int &i); void reseat_i(int &j); private: int & m_i; // Reference var }; Foo::Foo(int &i): // Constructor m_i(i) // Initializes m_i { } void Foo::reseat_i(int &j) { // In-place constructor, // reseats m_i new((void *)this) Foo(j); }The reseat_i function uses a placement new call to invoke the constructor for Foo on the object pointed to by this, with the net effect of re-initializing (reseating) the m_i reference variable. Such programming tricks are valid, but I certainly cannot recommend them because of their inherent danger. This sort of thing makes reference variables even more dangerous because it breaks the implicit guarantee that references can't be reseated.
David R. Tribble
Plano, TX
dtribble@technologist.com
http://www.flash.net/~dtribbleThanks for your insights. But I can't get too upset about a loophole in the language that requires so much conscious effort to exploit. I'm just about convinced that no language can be perfectly safe and consistent and still remain usable.
Well, the "pro-reference-argument" crowd has been strangely silent. I'd like to hear from someone who can argue (no pun intended) for using reference arguments instead of pointers. mb
Dear Mr. Plauger,
This is just a short note to ask about the recently approved C++ standard. I have seen a couple mentions in recent issues of CUJ that the standard is complete, but no mention of where it can be seen, etc. Is there a web site, or other place, where I could look at the standard?
Once upon a time there was a copy of one of the proposed Drafts posted on the Cygnus site. Has anyone done the same for the final version that everyone can look at?
Any information would be greatly appreciated.
Dale Spangler
derSpang@compuserve.comUnfortunately, the Final Draft International Standard (FDIS) has so far been explicitly kept from easy public access. I just got a machine-readable copy myself a few days ago, so Pete Becker and I can review it before casting the Dinkumware ballot. I hear talk that the FDIS might soon become more freely available, but right now that is not the case. pjp
Dear Sir,
I'm just a person who just wants to write simple programs. I have yet to find a book that gives me the kind of information I'm looking for. While the books I have looked at may have good information, it's not what I need:
Vb = Visual Basic d = Delphi 2.0 B3 = Borland Builder 3 vc = Visual C++ 1. Edit box, string to float ------------ vb x = val(text1.text) d x := StrToFloat(Edit1.Text); b3 x = StrToFloat(Edit1->Text); vc x = ? Edit box, float to string ------------ vb Text1.Text = Format$(x,"###") d Edit1.Text := FloatToStrF(x,ffFixed,7,2); b3 Edit1->Text = FloatToStrF(x,ffFixed,7,2); vc ? 2. Radio Buttons ------------ vb if option1.value = true then c = "am" d if checkbox1.state = cbchecked then c:='am'; b3 if(ChecBox1->State == cbChecked) c="am"; vc ?And so on and so forth, with all the other visual controls. What's the syntax for getting information out of controls, putting information into the controls, controlling the controls, enabled, visible, hide, show, and so on and so forth?
I need some good books.
Sincerely,
David L. Cousins
Sounds like the first thing you need is to pick one programming language and stick with it. Then the syntax for accessing visual controls won't seem so alien to you. Visual Basic will probably get you up and running the quickest, but unless you "just want to write simple programs" for the rest of your life, I'd avoid it like the plague. It will seriously warp your sense of aesthetics. You could do a lot worse than Delphi, and the C->C++ route is still viable if you're more serious about programming than you let on. One language you didn't mention is Java, which is arguably just as easy as Visual Basic and a helluva lot prettier. Pick a language and then maybe we can talk about some books. mbo