Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

multiple "mains" in linked OCaml modules

Tags:

ocaml

I have a number of "library" modules in OCaml (mainly utility and helper functions) where I've added the following kind of code at the end for trivial unit-testing:

let main () = ...
main

or

let () = ...

This being code that mainly prints to the console (for simple testing purposes). The problem now is that when I link my "library" modules with my "main" module and execute the program I get all these distracting testing messages. Is there a way to include code in an OCaml module that gets executed when the module is linked alone (thus facilitating trivial testing) but not when used as a "library"? I 've read posts in SO to the effect that OCaml has no notion of a "main" module and that all modules are equal however it seems to me that the order of the object files given to the linker could be construed to indicate that the last module is the "main" one (since it's at the top of the "dependency food chain").

like image 928
Marcus Junius Brutus Avatar asked Apr 02 '12 18:04

Marcus Junius Brutus


2 Answers

OCaml supports static linking and dynamic loading of modules; what you normally do (and what is type safe) is static linking. I would only recommend dynamic loading if you need some kind of plugin architecture.

Anyway, a library is nothing else than a module (probably with sub-modules). If you statically link a module, all "main" routines will get executed in the order of the modules being linked in your executable.

So if you don't do anything about it, a module does not know into which executable it is getting linked in some "magic" fashion; what you imho should do is:

  • move the tests out of the modules, perhaps using ounit OR
  • at least rewrite your test-functions to be real functions, e.g. "let test () = ..."; then write a testing-frontend that will call all "test" functions from all of your modules.

addendum:

If you do that in other languages, there seems to be no free cake either:

In Java you if you have multiple mains in your code, you must explicitly select the one you want the executable to run.

In C you could use the C preprocessor to do something like

#ifdef TEST_1
int main() {
...
}
#endif

OCaml has its own preprocessorcamlp4 (camlp4 wikipedia article) with which you could do something similar. I personally do consider this kind of test embedding as bad software engineering. You should rather test your module/class/.. from the interface side and mark your internal invariants with assertions (which exist in Java, C & OCaml).

like image 153
lambdapower Avatar answered Sep 18 '22 16:09

lambdapower


The toolchain doesn't have any provision for this, it generates a file that runs the top-level code of all modules at startup, in order of linking.

I don't see how to make it work systematically. Modules almost always have some top-level code that needs to be executed. You'd need a way to separate the top-level code into two groups (one group always executed, the other only executed when the module is the last one to be linked). This seems unnecessarily messy.

A better solution (it seems to me) is just to use a slightly more sophisticated testing framework.

like image 23
Jeffrey Scofield Avatar answered Sep 18 '22 16:09

Jeffrey Scofield