...
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