Real modules in YCP
Towards classes and objects
Didn't you miss 'real' classes and object like functions in YCP ?
With a clear environment and parse-time binding ?
No you can have it !
The old behaviour
YCP, originally planned as a functional language, always did dynamic
(i.e. runtime) binding of variables. Although useful in some cases,
it's quite puzzling for everyone used to 'imperative' languages.
So you could well program the following block
{
integer x = 42;
define f() ``{ return x; }
... // lots of lines
x = 55;
return f(); // will return 55 !
}
and get an unexpected result.
Another mis-used feature is include for special, global definitions.
Without 'real' modules, there is no alternative to include, so it was widely
accepted but
include just does that, it executes a complete file every time the include
is evaluated
which is bad memory-wise and speed-wise.
The new behaviour
Modules help a lot since they do
- Have definition-time bindings.
- One-time inclusion.
- Have their own namespace.
- Have a local environment.
Modules are a lot like include files, but they start with a module
statement specifying their name.
Example:
{
// This is a module called "Sample"
// It is stored in /usr/lib/YaST2/modules/Sample.ycp
module "Sample";
// this is a local declaration.
// it can only be 'seen' inside the module.
integer local_var = 42;
// this is a global declaration.
// it can be accessed from outside.
global integer global_var = 27;
// this is a global function
// it has access to global_var *and* local_var
global define sample_f () ``{ return local_var + global_var; }
}
The above module can now be used with the import statement.
import has a similar syntax for file names like include.
The interpreter automatically appends ".ycp" to the filename
and searches below /usr/lib/YaST2/modules. If the filename
starts with "./", the file is loaded from the local directory.
Caution: The file must have the same name as the module !
Inside modules, only variable or function declaration statements are
allowed. You can't have blocks or any kind of evaluation statements.
The global declarations of the module are accessed with Sample::.
Example:
{
import "Sample";
integer i = Sample::sample_f(); // == 69
i = Sample::local_var; // ERROR, no access possible !
i = Sample::global_var; // == 27
Sample::global_var = 0; // this variable is writable !!
return Sample::sample_f(); // == 42, since global_var is 0
}
The statement import "Sample"; triggers the loading of
Sample.ycp when first encountered. Subsequent import
statements are ignored, since "Sample" is already defined.
So you can't replace a module during runtime !
Modules with constructors.
If a global function with the same name as the module is defined, it
is treated as a constructor. The constructor is called after the
module is loaded and evaluated. So the constructor might be at the
beginning of the module and use functions declared later in the file.
Example:
{
// This is a module called "Class" with a constructor
// It is stored in /usr/lib/YaST2/modules/Sample.ycp
module "Class";
global integer class_var = 42;
// this is the constructor
global define Class() ``{ class_var = 12345; }
}
{
import "Class";
return Class::class_var; // will be 12345 !
}
Constructors can't have any arguments. The result of calling the
constructor is ignored.
Klaus Kämpf
Last modified: Fri Aug 17 16:24:42 MEST 2001