Contextual overloading

For large software projects, it is important that different modules can be developed as independently as possible one from each other. Furthermore, fundamental modules often implement default behaviour which is to be overwritten in a more specialized module. In order to facilitate these two requirements, TeXmacs implements an advanced system of contextual overloading.

In order to get the main idea behind this system, consider the implementation of a given functionality, like hitting the return key. Depending on the context, different actions have to be undertaken: by default, we start a new paragraph; inside a table, we start a new row; etc. A naive implementation would check all possible cases in a routine kbd-return and call the corresponding routine. However, this makes it impossible to add a new case in a new module without modifying the module which defines kbd-return. By contrast, the system of contextual overloading allows the user to conditionally redefine the routine kbd-return several times in distinct modules.

For instance, assume that we want to define a function hello which inserts “Hello” by default, but “hello()” in mode math, while positioning the cursor between the brackets. Using contextual overloading, this may be done as follows:

(tm-define (hello) (insert "Hello"))

(tm-define (hello) (:mode in-math?) (insert-go-to "hello()" '(6)))

Here we recall that the two definitions may be put inside different modules. Notice also that the contextual overloading system considers the implementation of hello inside math mode to be more particular than the default implementation. In case when several implementations match their respective conditions, the most particular implementation will be chosen.

Currently, TeXmacs supports three major types of conditions:

Conditions on the mode

A TeXmacs mode corresponds to a simple predicate without arguments, together with a finite number of other, less particular, modes which are implied by it. New modes can be defined using the instruction

(texmacs-modes mode% cond submode-1 ... submode-n)

For instance, we might define a new mode inside-theorem? as follows

(texmacs-modes inside-theorem% (inside? 'theorem) in-text%)

Some standard modes are always?, in-source?, in-text?, in-math?, in-prog?. There is also a special mode prevail? which is always satisfied, but nevertheless considered as more particular than all other modes.

Remark 1. Currently, modes necessarily terminate by the ? character. However, in the texmacs-modes instruction, the ? has to be replaced by a %. This may change in a future version of TeXmacs.

Conditions on the cursor context

Certain actions only make sense when the cursor is inside a special tag, or more generally inside some structure which matches a predicate. For instance, the action structured-insert-right inserts a new column at the right-hand side of the cursor when you are inside a table tag and a new branch when you are inside a tree. In the case, when you are both inside a table and a tree, the innermost match is considered to be the most particular one.

For instance, consider the implementation of a routine structured-swap for fractions, which permutes the numerator and denominator. This may be done as follows:

(tm-define (structured-swap)

(:inside frac)

(with-innermost t 'frac

(tree-set! t ‘(frac ,(tree-ref t 1) ,(tree-ref t 0)))))

Conditions on the arguments of the function

This type of contextual overloading is closest to the more classical concept of overloading used by languages like C++. Although one may overload on the types of the arguments, it is also possible to impose more general conditions on the arguments. For instance, one may sometimes wish to write the following kind of code:

(tm-define (my-replace what by)

default-implementation)

(tm-define (my-replace what by)

(:require (== what by))

(noop))

In cases of conflict, we notice that the contextual overloading system first dispatches on mode, next on the cursor context and finally on the arguments on the function. For instance, consider a routine foo defined by

(tm-define (foo) (:mode in-math?) implementation-1)

(tm-define (foo) (:inside 'frac) implementation-2)

Then the first implementation will be used when foo is called from within a fraction in math mode.

Besides tm-define, several other added language primitives support the contextual overloading mechanism. For instance, kbd-map, define-menu and extend-menu support overloading on mode and cursor context. The tm-define-macro and tm-property primitives are analoguous to tm-define.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".