Skip to main content
Bounty Ended with 100 reputation awarded by Stefano Borini
deleted 16 characters in body
Source Link

is theSoundsSounds like Cursor represents a position in a Document. The Document class should ultimately be responsible for all primitive operations like inserting, deleting, gabbinggrabbing text and moving around. Most of these operations require a position as input and some may also return a position as output. A Cursor holds a Document and a position. Cursor could just be a concrete data class which just holds the position and the Document, basically a pair. The other approach is to make Cursor a first class abstraction. In that case its API will just mirror that of Document, and each method will be just a thin wrapper around the corresponding method on Document, but the methods on Cursor will omit the position parameter since they will fill that with the position from the Cursor. The basic pattern is something like

cursor.someMethod(arg1, ...) = cursor.doc.someMethod(cursor.pos, arg1, ...)

except if the Document method returns a position then the Cursor method should package that together with the document and to return a cursor like

cursor.cursorMethodotherMethod(arg1, ...) = new Cursor(cursor.doc,
                                            cursor.doc.cursorMethodotherMethod(cursor.pos, arg1, ...))

The drawback of this approach is the boiler plate on the implementation side, but it makes the library much nicer to use on the client side. Since the required boilerplate is simple and systematic you may be able to avoid writing it manually by either generating it, or doing the delegation through reflective calls if you are using a language with decent reflection capacities or a reasonably powerful preprocessor.

You still need to decide what a position is. It can be just a number representing the character position in the whole document (eg Emacs), a pair representing the line and position on the line, or a in C/C++ a pointer directly into the underlying container. I would recommend making position a member type on Document if your language supports that. That way each Document implementation can supply its own position type definition. Cursor treats positions as completely abstract, it just hold them and passes them to Document methods. only Document cares how they are implemented.

is theSounds like Cursor represents a position in a Document. The Document class should ultimately be responsible for all primitive operations like inserting, deleting, gabbing text and moving around. Most of these operations require a position as input and some may also return a position as output. A Cursor holds a Document and a position. Cursor could just be a concrete data class which just holds the position and the Document, basically a pair. The other approach is to make Cursor a first class abstraction. In that case its API will just mirror that of Document, and each method will be just a thin wrapper around the corresponding method on Document, but the methods on Cursor will omit the position parameter since they will fill that with the position from the Cursor. The basic pattern is something like

cursor.someMethod(arg1, ...) = cursor.doc.someMethod(cursor.pos, arg1, ...)

except if the Document method returns a position then the Cursor method should package that together with the document like

cursor.cursorMethod(arg1, ...) = new Cursor(cursor.doc,
                                            cursor.doc.cursorMethod(cursor.pos, arg1, ...))

The drawback of this approach is the boiler plate on the implementation side, but it makes the library much nicer to use on the client side. Since the required boilerplate is simple and systematic you may be able to avoid writing it manually by either generating it, or doing the delegation through reflective calls if you are using a language with decent reflection capacities or a reasonably powerful preprocessor.

Sounds like Cursor represents a position in a Document. The Document class should ultimately be responsible for all primitive operations like inserting, deleting, grabbing text and moving around. Most of these operations require a position as input and some also return a position as output. Cursor could just be a concrete data class which just holds the position and the Document, basically a pair. The other approach is to make Cursor a first class abstraction. In that case its API will just mirror that of Document, and each method will be just a thin wrapper around the corresponding method on Document, but the methods on Cursor will omit the position parameter since they will fill that with the position from the Cursor. The basic pattern is something like

cursor.someMethod(arg1, ...) = cursor.doc.someMethod(cursor.pos, arg1, ...)

except if the Document method returns a position then the Cursor method should package that together with the document and to return a cursor like

cursor.otherMethod(arg1, ...) = new Cursor(cursor.doc,
                                           cursor.doc.otherMethod(cursor.pos, arg1, ...))

The drawback of this approach is the boiler plate on the implementation side, but it makes the library much nicer to use on the client side. Since the required boilerplate is simple and systematic you may be able to avoid writing it manually by either generating it, or doing the delegation through reflective calls if you are using a language with decent reflection capacities or a reasonably powerful preprocessor.

You still need to decide what a position is. It can be just a number representing the character position in the whole document (eg Emacs), a pair representing the line and position on the line, or a in C/C++ a pointer directly into the underlying container. I would recommend making position a member type on Document if your language supports that. That way each Document implementation can supply its own position type definition. Cursor treats positions as completely abstract, it just hold them and passes them to Document methods. only Document cares how they are implemented.

deleted 16 characters in body
Source Link

Soundsis theSounds like Cursor represents a position in a Document. The Document class should ultimately be responsible for all primitive operations like inserting, deleting, gabbing text and moving around. Most of these operations require a position as input and some may also return a position as output. A Cursor holds a Document and a position. Cursor could just be a concrete data class which just holds the position and the Document, basically a pair. The other approach is to make Cursor a first class abstraction. In that case the its API will just mirror that of Document, and each method will be just a thin wrapper around the corresponding method on Document, but the methods on Cursor will omit the position parameter since they will fill that in with the position offrom the Cursor. The basic pattern is something like

cursor.someMethod(arg1, ...) = cursor.doc.someMethod(cursor.pos, arg1, ...)

except if the Document method returns a position then the Cursor method should package that together with the document like

cursor.anotherMethodcursorMethod(arg1, ...) = new Cursor(cursor.doc,
                                             cursor.doc.someMethodcursorMethod(cursor.pos, arg1, ...))

The drawback of this approach is that it can require a lot ofthe boiler plate on the implementation side, but it makes the library much nicenicer to use on the client side. As you can see,Since the required boilerplate is simple and systematic. If you are using a language with decent reflection capacities or a reasonably powerful preprocessor, you may be able to avoid it writing it manually by either generating it, or doing the delegation through reflective calls if you are using a language with decent reflection capacities or a reasonably powerful preprocessor.

Sounds like Cursor represents a position in a Document. The Document class should ultimately be responsible for all primitive operations like inserting, deleting, gabbing text and moving around. Most of these operations require a position as input and some may also return a position as output. A Cursor holds a Document and a position. Cursor could just be a concrete data class which just holds the position and the Document, basically a pair. The other approach is to make Cursor a first class abstraction. In that case the its API will just mirror that of Document, and each method will be just a thin wrapper around the corresponding method on Document, but the methods on Cursor will omit the position parameter since they will fill that in with the position of the Cursor. The basic pattern is something like

cursor.someMethod(arg1, ...) = cursor.doc.someMethod(cursor.pos, arg1, ...)

except if the Document method returns a position then the Cursor method should package that together with the document like

cursor.anotherMethod(arg1, ...) = new Cursor(cursor.doc,
                                             cursor.doc.someMethod(cursor.pos, arg1, ...))

The drawback of this is that it can require a lot of boiler plate on the implementation side, but it makes the library much nice to use on the client side. As you can see, the required boilerplate is simple and systematic. If you are using a language with decent reflection capacities or a reasonably powerful preprocessor, you may be able to avoid it writing it manually by either generating it, or doing the delegation through reflective calls.

is theSounds like Cursor represents a position in a Document. The Document class should ultimately be responsible for all primitive operations like inserting, deleting, gabbing text and moving around. Most of these operations require a position as input and some may also return a position as output. A Cursor holds a Document and a position. Cursor could just be a concrete data class which just holds the position and the Document, basically a pair. The other approach is to make Cursor a first class abstraction. In that case its API will just mirror that of Document, and each method will be just a thin wrapper around the corresponding method on Document, but the methods on Cursor will omit the position parameter since they will fill that with the position from the Cursor. The basic pattern is something like

cursor.someMethod(arg1, ...) = cursor.doc.someMethod(cursor.pos, arg1, ...)

except if the Document method returns a position then the Cursor method should package that together with the document like

cursor.cursorMethod(arg1, ...) = new Cursor(cursor.doc,
                                            cursor.doc.cursorMethod(cursor.pos, arg1, ...))

The drawback of this approach is the boiler plate on the implementation side, but it makes the library much nicer to use on the client side. Since the required boilerplate is simple and systematic you may be able to avoid writing it manually by either generating it, or doing the delegation through reflective calls if you are using a language with decent reflection capacities or a reasonably powerful preprocessor.

Source Link

Sounds like Cursor represents a position in a Document. The Document class should ultimately be responsible for all primitive operations like inserting, deleting, gabbing text and moving around. Most of these operations require a position as input and some may also return a position as output. A Cursor holds a Document and a position. Cursor could just be a concrete data class which just holds the position and the Document, basically a pair. The other approach is to make Cursor a first class abstraction. In that case the its API will just mirror that of Document, and each method will be just a thin wrapper around the corresponding method on Document, but the methods on Cursor will omit the position parameter since they will fill that in with the position of the Cursor. The basic pattern is something like

cursor.someMethod(arg1, ...) = cursor.doc.someMethod(cursor.pos, arg1, ...)

except if the Document method returns a position then the Cursor method should package that together with the document like

cursor.anotherMethod(arg1, ...) = new Cursor(cursor.doc,
                                             cursor.doc.someMethod(cursor.pos, arg1, ...))

The drawback of this is that it can require a lot of boiler plate on the implementation side, but it makes the library much nice to use on the client side. As you can see, the required boilerplate is simple and systematic. If you are using a language with decent reflection capacities or a reasonably powerful preprocessor, you may be able to avoid it writing it manually by either generating it, or doing the delegation through reflective calls.