Valerin Valerin - 11 months ago 33
Scala Question

preprocessors in C++ and their alternatives in Scala

Which is the alternative implementation in Scala of preprocessor directives, like in C++? Let say that I have something like this:

#ifdef ADD
class Add extends Expr {
Expr left , right ;
Add ( Expr l, Expr r)
{ left =l; right =r; }
#ifdef EVAL
double eval () {
return left.eval () +
right.eval ();
}
#endif
#ifdef PRINT
void print () {
left.print ();
System.out.print("+");
right.print();
}
#endif
}
#endif


How I can have an equivalent of this in Scala?

Answer Source

First, you have to ask yourself, "Why do I want to conditionally include pieces of code that impact many objects?" (Expanding my comment)

Traditionally, preprocessing-controlled code is used for

  1. Feature configuration control - What features get included in a build. This partly the interface that you define but mostly how you use and invoke the feature set.
  2. Architectural control - What environments the software runs in, such as operating system and processor architecture.
  3. Annotations and cross-cutting concerns - Debugging, assertions, logging, constraint checking, etc.

For the first item, feature configuration control, it is very important to note that using the preprocessor approach, while convenient in the small scale, really tends to obscure the software and can lead you down rabbit holes.

The Scala way is to define a set of interfaces, called traits, and then bring those interfaces together into a complete picture. If you really need to have a particular component not included in the code, then you create a set of classes with only the code you want and package them up into a module (package or jar). Then you include that module in your final packaging.

The second concern is addressed in a similar fashion. You create packages for common code, and packages for the platform specific items. Then, at run time, you dynamically select which packages you load. This can be done by explicit package paths, or if you want to be tricky about it, you might try creating a class loader to do the dirty work for you. However, being up front about things works much better in the long term.

The third concern is addressed by several approaches in Scala.

An approach used in Java and in Scala is annotations. These use a programmatic flagging method to indicate that particular classes, methods or fields have special treatment. See the Scala documentation. However, using it to flag methods as not being present is not a good use, even though it is possible. The @deprecated annotation, for instance, is used to tell programmers when API elements are going away, and allows the compiler or IDE to flag items that should be upgraded.

Another approach available in Scala is the use of macros. From this page, we have the blurb: Macros are good for code generation, static checks and domain-specific languages. In theory, you could use them for what you have been trying to do with pre-processing.

In general, the pre-processing approach leads to "kitchen sink" type programming. The other issue that is a huge pain to deal with is that your method requires that every single module in the application, whether library or main program, needs to be compiled with the same flags. This is a tremendous burden on your make system, especially once you pass the hundreds of source files mark.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download