using Undo with portable C++ data model
using Undo with portable C++ data model
- Subject: using Undo with portable C++ data model
- From: John Richetta <email@hidden>
- Date: Fri, 6 Jun 2008 19:16:18 -0700
I have some core engine code that is written in C++, with the intent
of keeping it portable. I only have a Cocoa implementation of my
outer application, at present, so it's been a slightly academic
exercise, but so far, most of the code in my data model remains
substantially portable.
Now, as I try to implement undo, I find it difficult and messy to
keep the C++ code portable. I have only come up with two similar
ways to do this, and I'm curious if others have been down this path
and can make any recommendations.
One approach is to use IMPs (Objective-C method implementation
pointers) to call back into Objective-C, from C++. That is, the C++
code uses function pointers, essentially, when registering undo
actions. These IMPs would presumably be wrapped by a C++ class
providing a uniform interface to platform specific undo.
A second part of this solution involves writing some sort of
ill-defined Objective-C intermediary that forwards invocations posted
by the undo architecture to the appropriate C++ core data model
objects. This seems pretty artificial, since the engine objects are
moderately lightweight to begin with. As if this solution weren't
tedious and ugly enough, note that the engine now projects a fairly
Cocoa-specific vision of an undo architecture (good though it may
be), as well as some unpleasant mechanics, onto the cross platform
engine code.
A second somewhat more refined approach is to write a shallow
hierarchy of undo actions ("commands," in GoF parlance), appropriate
instances of which are provided by engine objects when registering
specific actions to undo, and send these, again via the IMP
mechanism, to some intermediary Objective-C code, that repackages the
actions as invocations, and forwards those invocations, when invoked
by an NSUndoManager, to reapply the actions to their target objects,
and clean up.
The second approach seems cleaner to me, since to the extent it
forces a specific undo implementation on the engine, it is likely to
be more portable / adaptable, and because it localizes the messy
platform-specific adaption code almost entirely outside the engine.
The undo "action" hierarchy is less elegant than invocations, but
that is presumably the price of keeping the engine portable. But are
there better plans than this?
It seems to me as if some enhancement to NSUndoManager might
facilitate easier interaction with C/C++ code, and that this is
probably a common problem, given that data model code is often one of
the better candidates for C++ implementation. The Cocoa undo
architecture pretty much requires close interaction between a data
model and NSUndoManager.
A key part of any potential extensions would be one or more C/C++
accessible entry points. It might also include the ability to stack
client-defined undo "action" or invocation objects, as outlined
above, or perhaps a way to package C-style variable argument lists
and function pointers.
I'm mocking up the "second" approach outlined above in a small test
application, and will summarize my findings once I've learned
something useful.
[Two+ weeks later...]
I didn't bother to complete my test application. After thinking
about it a while, I decided that the inelegance and complexity of
this approach was just too great for the benefit, and I decided to
ditch cross-platform compatibility, and convert what I had to back to
Objective-C++. In practice, this is rippling painfully hard, and
necessitating a lot of rework. And it feels terrible to be trashing
the work I did to make a portable engine.
So, I'm appealing to anyone who's come up with a better answer than I
have to please share. Thanks in advance, -jar
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden