On Saturday, 23 June 2018 at 14:06:08 UTC, Basile B. wrote:
On Saturday, 23 June 2018 at 01:58:31 UTC, DigitalDesigns wrote:
Is there any idiomatic undo designs in D that give a more
natural implementation than the standard techniques?
- The "stuff to undo" can be a forward range ("save" primitive,
+ assignable from a stored state)
- The manager can be an output range of the "stuff to undo"
```
struct UndoManager(Undoable, Storage)
if (isForwardRange!Undoable && isOutputRange!(Storage,
Undoable))
{
Storage storage;
Undoable undoable;
size_t position;
this(Storage storage, Undoable undoable)
{}
void push(){ storage.put(undoable.save()); length++;}
/* etc */
}
```
So that the UndoMgr is reusable with any Undoable and Storage
that implement the right primitives.
But well, you can do that with any PL that have basic generics,
e.g C# or FreePascal. The key is to have a nice generic
interface. IRL it's probably more complicated than my example.
Storage must probably be a RandomAccessRange or have more
specific primitives.
Now, **and this is D specific / D idiomatic**, to this can be
applied the "design by introspection". UndoManager can allow
more or less advanced features, depending on the primitives
implemented by Storage and Undoable. Technically this is done
at compile-time using __traits(hasMember), typically.
Actually i did one once for an hex editor and i think this
couldn't be applied. Typically a position, a command and a data
are the member of a change, not the whole stuff. The generic
abstraction should be changed to handle such a thing:
struct UndoItem(Position, Command)
{
Position position; // e.g offset in doc or coordinate, etc
Command command; // e.g an enum
ubyte[] data;
}
About the Storage, i think that a linked list is better. No need
to templatize it then. From this there's no thing possible that's
very idiomatic in the design.
Somrething like this old shitty stuff :
https://github.com/BBasile/LLClasses/blob/master/LLClasses.d#L5701 but with a better absssstraction (linked code is more or less the translation of what i did in Delphi years before).
So finally we come back to a simple generic stuff:
struct UndoMgr(Position, Command)
{
List!(UndoItem!(Position, Command)) items;
/*
stupid method there
- insert
- undo
- redo
- compact
- clear
*/
}
nothing D specific, you can do that in C# or in FreePascal.
UndoRedo is a simple thing, too much abstraction could make the
thing abstruse. But maybe this is what you look for, something
utterly complex to fill your emptiness.