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
which is bad memory-wise and speed-wise.

 

The new behaviour

Modules help a lot since they do

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