...
The definition of constants and variables in a dynamically linked
GNU/Octave extension resembles the header of a dynamically linked function
(see, for example, Section 1.1.3).
However, the appropriate macro DEFCONST
is not available when creating a dynamically loadable extension for it is
defined in defun.h and not in
defun-dld.h. The latter is
necessary to set up an dynamically loadable extension. The easiest,
moderately clean way is to duplicate DEFCONST
's definition from defun.h into the respective extension.
// same definition as found in defun.h #ifndef DEFCONST #define DEFCONST(name, defn, doc) DEFCONST_INTERNAL(name, defn, doc) #endif
DEFCONST
introduces a constant named
constant_name
at the interpreter level, giving it the value
of defining_expression
and endowing it with the
documentation documentation_string
. The newly
created constant will be protected against deletion, but
not against change.
voidDEFCONST
(constant_name, defining_expression, const std::string&documentation_string
)
The name of the constant constant_name
must be a valid
C++ identifier, because it is not quoted. Octave
automatically casts the variable's definition,
defining_expression
, to
type octave_value.
A constant can be assigned to and then takes on the new value! Assigning to a constant does not even produce a warning. clearing a protected constant does not give raise to a warning either. Clearing a protected constants re-installs its original value.
Example 1-7. Constant Definition
#include <oct.h> // `DEFCONST' from "defun.h" #ifndef DEFCONST #define DEFCONST(name, defn, doc) \ DEFCONST_INTERNAL(name, defn, doc) #endif static const double h = 6.626176e-34; // Planck's constant in J*s DEFUN_DLD(defconst, args, , "Install some fundamental physical constants.") { if (args.length() == 0) { DEFCONST(c, 2.99792458e8, "Speed of light in m/s."); DEFCONST(hbar, h / (2.0 * M_PI), "Reduced Planck's constant hbar, that is, h/(2*pi) in J*s."); DEFCONST(G, 6.672e-11, "Graviation constant in N*m^2/kg^2."); DEFCONST(e, 1.6021892e-19, "(Absolute value of the) Charge of an electron in C."); } else { error("defconst: expecting no arguments."); } return octave_value_list(); }
Long documentation strings in a long series of definitions tend to obscure the code. Assigning the documentation string to a macro allows for a separation of the help text and the definition. #define DOCSTRING_HBAR \ "Reduced Planck's constant hbar, this is, h/(2*pi) in J*s." ... DEFCONST(hbar, h / (2.0 * M_PI), DOCSTRING_HBAR); This is also useful for describing the function's documentation string. |
Like DEFCONST
is defined in defun.h and not in defun-dld.h. So, the programmer must introduce the
macro himself.
// same definition as found in defun.h #ifndef DEFVAR #define DEFVAR(name, defn, chg_fcn, doc) \ DEFVAR_INTERNAL(#name, SBV_ ## name, defn, false, chg_fcn, doc) #endif
voidDEFVAR
(variable_name
,defining_expression
, symbol_record::change_function changing_function, const std::string& documentation_string)
The parameters variable_name
,
defining_expression, and
documentation_string are analogous to those of
DEFCONST
. Only
changing_function calls for further explanation.
changing_function is a pointer to a function that gets called whenever variable variable_name is given a new value. changing_function can be NULL if there is no function to call. change_function is defined in symtab.h
// symtab.h typedef int (*change_function) (void);
A changing_function never takes on any parameters! Therefore, it must have a built-in knowledge of which interpreter variable to take care of. Usually, changing_functions correspond one-to-one with variable_names. Note the changing_function is called to initialize variable_name with the value of defining_expression. This means that changing_function is called at least once even if variable_name never gets changed withing the interpreter. The return value 0 from changing_function signals success to the caller, any other value stands for failure.
DEFVAR
installs and initializes a
variable in the interpreter's workspace. To access a variable or constant,
variables.h declares three
functions:
#include <variables.h>
std::string builtin_string_variable
(
const std::string&
symbol_name
);
int builtin_real_scalar_variable
(
const std::string&
symbol_name
,
double&
value
);
octave_value builtin_any_variable
(
const std::string&
symbol_name
);
Example 1-8. Variable Definition
#include <oct.h> #include <variables.h> // for `builtin_*_variable' // `DEFVAR' from "defun.h" #ifndef DEFVAR #define DEFVAR(name, defn, chg_fcn, doc) \ DEFVAR_INTERNAL(#name, SBV_ ## name, defn, false, chg_fcn, doc) #endif static double counter_var; static unsigned count = 0; static int counter_set(); // // documentation strings // #define DOCSTRING_DEFVAR \ "Define two variables in the workspace: simple and counter.\n\ See the respective documentations, that is,\n\ `help simple' and `help counter'." #define DOCSTRING_SIMPLE \ "Variable `simple' is initialized to 0.5.\n\ It is not linked to any low-level variable." #define DOCSTRING_COUNTER \ "Variable `counter' is initialized to 1.0.\n\ It is linked to the C++ variable `counter_var' in file `defvar.cc'.\n\ Whenever `counter' is assigned to the number of assigments\n\ is printed." // // body // DEFUN_DLD(defvar, args, , DOCSTRING_DEFVAR) { if (args.length() == 0) { DEFVAR(simple, 0.5, 0, DOCSTRING_SIMPLE); DEFVAR(counter, 1.0, counter_set, DOCSTRING_COUNTER); } else { error("defvar: expecting no arguments."); } return octave_value_list(); } static int counter_set() { if (builtin_real_scalar_variable("counter", counter_var) == 0) { error("counter_set: internal error, non-existent variable"); return 1; } count++; cout << "==> `counter' has been assigned to " << count << " times;\n" << "==> its new value is " << counter_var << ".\n"; return 0; }
Having studied Section 1.1.4.2, only one new Texinfo function is waiting: defvr.
-*- texinfo -*- @defvr {Built-in Variable} my_own_variable ... @end defvr