3

I have several modules implementing the same interface. I want to load only one of this module depending on one argument given on the command line.

I was thinking to use first-class module but the problem is that I want to execute some functions before that the module is instanciated.

For the moment I have this :

module Arch = (val RetrolixAbstractArch.get_arch() : RetrolixAbstractArch.AbstractArch)


let get_arch () =
  let arch = Options.get_arch() in
  if arch = "" then
    Error.global_error "During analysis of compiler's architecture"
               "No architecture specified"
  else
    if arch = "mips" then
      ( module MipsArch : AbstractArch)
    else
    Error.global_error "During analysis of compiler's architecture"
               (Printf.sprintf "Architecture %s not supported or unknown" arch)      

But since the command line is not parsed yet, Options.get_arch give me the empty string.

I would like to realize the command line parsing before that this function is executed (without adding the parssing in the function). Is it possible ? Should I find an other way to achieve this ?

ivg
  • 34,431
  • 2
  • 35
  • 63
Saroupille
  • 609
  • 8
  • 14
  • What is `Options` and why don't you call the command line parser somewhere before you call this (the whole question's) module's `get_arch`? – antron May 25 '15 at 14:33
  • My problem is that the function get_arch is called before the main function. So the command line parser is not called at this time. But it would be weird to call it twice. Options is the module that store the option variables of the program, variables that depends on the command line. – Saroupille May 25 '15 at 14:39
  • Why is `get_arch` called before the main function? Is it part of module initialization for some module? Can you rearrange it so that you have some other main function, which allows you to control the order in which things are called, including the command line parser, `get_arch`, and your current main function? – antron May 25 '15 at 14:41

1 Answers1

9

It is possible, but you must use local modules. This is a minor issue, that basically requires only few refactoring.

let arch_of_name = function
  | "mips" -> (module MipsArch : AbstractArch)
  | "arm"  -> (module Arm)
  | _ -> invalid_arg "unknown arch"


let main () = 
  ...
  let arch_name = get_arch () in
  let module Arch = (val arch_of_name arch_name) in
  (* here you can use module Arch as usual *)

Another approach is to functorize your modules with arch structure and instantiate your functors as soon as you know the architecture. You can see a full fledged example here (see function target_of_arch that creates first-class module for particular architecture).

If your AbstractArch interface doesn't contain type definitions, then you can use other abstractions instead of modules: records of functions or objects. They may work more smoothly, and may even allow you to overload the arch instance dynamically (by making the arch instance to be a reference, although I wouldn't suggest this, as it is quite unclean, imo).

ivg
  • 34,431
  • 2
  • 35
  • 63