Implement a relative reference robust to source and reference moving

The new function is X(SRC,REF), which briefly for a cell in the neighborhood
   of REF returns the corresponding cell in the neighborhood in SRC. For
   further details, see the updated documention.

   In developing and documenting this function, I refined some of the
   existing error messages (e.g. showing the coordinates when there is an
   attempt to obtain a cell with a negative coordinate) and improved the
   error propagation to increase the chance that the innermost error will
   percolate to the top level.
This commit is contained in:
Glen Whitney 2019-07-30 15:07:54 -04:00
parent ab1a2fbb5a
commit 341b12ba04
12 changed files with 650 additions and 238 deletions

View file

@ -4625,7 +4625,7 @@ save-tbl
file
\series default
\emph default
\end_layout
\begin_layout Description
@ -4642,7 +4642,7 @@ save-csv
file
\series default
\emph default
\end_layout
\begin_layout Description
@ -4659,7 +4659,7 @@ save-latex
file
\series default
\emph default
\end_layout
\begin_layout Description
@ -4676,7 +4676,7 @@ save-context
file
\series default
\emph default
\end_layout
\begin_layout Description
@ -4855,6 +4855,11 @@ Location Cell labels and the
&()
\family default
function have this type, but there are no location constant literals.
However,
\family typewriter
&(3,2,1),
\family default
for example, acts very much like a location constant literal.
\end_layout
\begin_layout Description
@ -5041,7 +5046,7 @@ y
x
\family typewriter
\emph default
=
~=
\family default
\emph on
y
@ -5489,7 +5494,8 @@ y
z
\emph default
is omitted, the coordinate of the cell is used.
The second form is in fact a no-op, but it is allowed for convenience
The second form is in fact a no-op, but it is allowed for convenience and
consistency of expressions.
\end_layout
\begin_layout Description
@ -5515,8 +5521,21 @@ relative.
\begin_inset Quotes erd
\end_inset
Thus R(-1) returns the value of the cell immediately to the left of this
one.
Thus
\family sans
\series bold
R
\series default
(-1)
\family default
returns the value of the cell immediately to the left of this one, and
\family sans
\series bold
R
\series default
(,,1)
\family default
returns the same cell as this one but on the following layer.
\end_layout
\begin_layout Description
@ -5541,8 +5560,181 @@ displaced (by).
\begin_inset Quotes erd
\end_inset
Thus, D(-1) returns the location of the cell immediately to the left of
this one.
Thus,
\family sans
\series bold
D
\series default
(-1)
\family default
returns the location of the cell immediately to the left of this one, and
\family sans
\series bold
D
\series default
(,2,1)
\family default
returns the location of the cell two below this one on the following layer.
\end_layout
\begin_layout Description
X(
\series medium
label
\emph on
\begin_inset space ~
\end_inset
to,
\begin_inset space ~
\end_inset
\emph default
label
\emph on
\begin_inset space ~
\end_inset
from,
\begin_inset space ~
\end_inset
\emph default
[bool
\emph on
\begin_inset space ~
\end_inset
fix_x
\emph default
]
\emph on
,
\begin_inset space ~
\end_inset
\emph default
[bool
\emph on
\begin_inset space ~
\end_inset
fix_y
\emph default
]
\emph on
,
\begin_inset space ~
\end_inset
\emph default
[bool
\emph on
\begin_inset space ~
\end_inset
fix_z
\emph default
]
\series default
)
\begin_inset Quotes eld
\end_inset
Excel reference
\begin_inset Quotes erd
\end_inset
: returns the value of the cell at a computed target location.
This target location is the one reached from the current cell via the same
offset as the cell with label
\emph on
to
\emph default
has from label
\emph on
from.
\emph default
The idea is that if you label the source of data you want to reference,
say with
\family sans
SRC
\family default
, and the location of some place you want to start referring to it with
\family sans
REF
\family default
, then you can use
\family sans
\series bold
X
\series default
(SRC,REF)
\family default
to refer to the source data, and fill this formula to neighboring cells
to refer to the neighbors of the source, and it will all continue to work
if either the source or the reference is moved around in the sheet.
\begin_inset Newline newline
\end_inset
If the
\emph on
fix_DIM
\emph default
argument is present and positive, then the corresponding coordinate of
the target cell is set to match that of
\emph on
to
\emph default
.
This corresponds to fixing the row or column (or layer) of the reference,
as with a
\begin_inset Quotes eld
\end_inset
$
\begin_inset Quotes erd
\end_inset
character in Excel.
Thus
\family sans
\series bold
X
\series default
(SRC,REF,1,1,1)
\family default
is identical to
\family sans
@(SRC)
\family default
, but you should certainly prefer the latter for clarity of expression.
\begin_inset Newline newline
\end_inset
There is a corresponding location function
\family sans
X&()
\family default
as well, which takes exactly the same arguments with the same meanings,
but it is rarely needed.
It is provided for completeness.
\begin_inset Newline newline
\end_inset
See the FAQ below for further discussion of cell references.
\end_layout
\begin_layout Description
@ -5904,7 +6096,7 @@ clock
condition
\emph default
,[location[,location])
,[location[,location])
\series default
conditionally clocks the specified cell if the condition is not 0.
If two locations are given, all cells in that range will be clocked.
@ -7264,8 +7456,22 @@ z
position of the given location, of the currently updated cell if none is
given.
These functions are usually used in combination with the @ function for
relative relations to other cells.
relative relations to other cell, but see also the convenience functions
\family sans
\series bold
R
\series default
()
\family default
and
\family sans
\series bold
D
\series default
()
\family default
for relative references.
\end_layout
\begin_layout Subsection
@ -7763,11 +7969,13 @@ X
\end_layout
\begin_layout Quote
eval(&((@(X)>=0)+x(BAD),y(BAD),z(BAD)))
eval(BAD + &((@(X)>=0),0,0))
\end_layout
\begin_layout Standard
The cell labelled
Note this is making use of the fact that you can add locations in the natural
way.
The cell labelled
\family typewriter
BAD
\family default
@ -7786,5 +7994,190 @@ BAD
\end_layout
\begin_layout Subsection
But my references don't do the right thing when I move or copy them!
\end_layout
\begin_layout Standard
If you are used to other spreadsheets, you have probably noticed that references
like
\family sans
@(0,1,0)
\family default
(for the start of the second row) or
\family sans
@(MYDATA)
\family default
(for a location) are
\begin_inset Quotes eld
\end_inset
absolute
\begin_inset Quotes erd
\end_inset
they always refer to the same location no matter where in the spreadsheet
they occur.
And of course sometimes it is convenient, for example when making a column
of consecutive numbers, to refer to nearby cells in a relative manner,
either with say
\family sans
@(x(),y()-1,z())+1
\family default
or
\family sans
@(&()+&(0,-1,0))+1
\family default
or just
\family sans
R(,-1)+1
\family default
to add one to the value of the cell just above.
Then you can fill that expression down and get your column of consecutive
numbers.
\end_layout
\begin_layout Standard
But these sorts of relative expressions only keep working if the cells move
together with the cells they refer to.
If for example you have a row of cells that are all referring to the row
above with a relative reference (like
\family sans
R(,-1)
\family default
) and you insert another row in between them, your references will be all
messed up.
There is value to
\begin_inset Quotes eld
\end_inset
Excel-style
\begin_inset Quotes erd
\end_inset
references that can be used to fill and which also can move around while
still just
\begin_inset Quotes eld
\end_inset
referring to what you want.
\begin_inset Quotes erd
\end_inset
\end_layout
\begin_layout Standard
To provide for this need, teapot has a function
\family sans
X(SRC, REF)
\family default
to retrieve the value of the cell labeled
\family sans
SRC
\family default
\bar under
from
\bar default
the cell labeled
\family sans
REF
\family default
.
If the so-labeled cells move around (either the source or the reference)
it will still work.
This is not particularly useful in and of itself; what makes it useful
is that from a cell other than
\family sans
REF
\family default
, it gives you the value of the cell that stands in the same relation to
\family sans
SRC
\family default
as that cell stands to
\family sans
REF
\family default
.
So in the cell to the right of
\family sans
REF
\family default
, it will give you the value of the cell to the right of
\family sans
SRC
\family default
; in the cell below, it gives you the cell below
\family sans
SRC
\family default
, etc.
Now you can fill a block of cells around
\family sans
REF
\family default
with formulas contaning
\family sans
X(SRC,REF)
\family default
and they will refer to the analogous block of cells around
\family sans
SRC
\family default
.
\end_layout
\begin_layout Standard
Sometimes you want to make this kind of reference but fix one of the coordinates
but not the others;
\family sans
X()
\family default
has optional flags for this, as well, so that
\family sans
X(SRC,REF,,,1)
\family default
will always be on the same layer as
\family sans
SRC
\family default
regardless of what layer it is called from or what layer
\family sans
REF
\family default
is on.
Thus
\family sans
X(SRC,REF,1,1,1)
\family default
is just
\family sans
@(SRC)
\family default
, but the intent of the latter is much clearer.
\end_layout
\begin_layout Standard
You might ask as a follow-up question: Isnt
\family sans
X(SRC, REF)
\family default
much more cumbersome than just referring to cells by coordinate and then
letting Excel just do the right thing as you copy and move either that
formula or the referred-to data? The response to this is that in a typical
spreadsheet, there are only a small number of fundamental references, and
all other references derive from them in this way.
So you generally only need a few labels, and by taking just a little extra
time to apply those labels and refer to them in initial formulas, you are
making the semantics of your references much clearer and in essence documenting
them within your spreadsheet.
This extra effort will therefore be repaid in an easier-to-use, easier-to-under
stand, and easier-to-maintain and update spreadsheet.
\end_layout
\end_body
\end_document