views:

425

answers:

2

I am attempting to conceptualize the Singleton design pattern (qua Java) in OCaml and have seen ever instance allude to functors or modules, neither of which I am using in a proof of concept of GoF's work. Basically, I would like to recreate the following functionality using OCaml:

public class Singleton
{
 private static Singleton UniqueInstance; 
 private Singleton(){}
 public static Singleton getInstance()
 {
  if(UniqueInstance==null)UniqueInstance=new Singleton();
  return UniqueInstance;
 }
}

Is this possible without modules or functors?

+3  A: 

Objects in Ocaml can not have static / global methods. You can try, Immediate objects. Caveat, I think you can still do obj.copy to get a copy of the object, and every time they are evaluated they return a new object (so you cannot pass parameters to the object, well you can, with some encapsulation and a global boolean, but now you're dealing with modules). Of course, if you only have something like there example,

let p = object 
   val mutable x = 0
   method get_x = x
   method move d = x <- x + d
end

p would be evaluated once, and you would access that each time. Of course, p#copy would fuck things up for you. Modules are the way to go here. Ocaml's OO features aren't as 'powerful' as other languages. It's of course not the goal of the project, it's module system is very powerful.

Modules are (global) singletons. There really isn't anything you have to write to build them. They are implicitly in the language. For example, how about logging to a file:

---logging.ml
(* default channel to log *)
let log_channel = ref stdout

(* set the log to a channel *)
let set_log_chan chan = log_channel := chan

(* timestamp of log -- kinda heavy weight, but just for kicks *)
let get_log_prequel () = 
    let time = Unix.localtime (Unix.time ()) in
    (* format the time data into "y/m/d - h:m:s" format *)
    Printf.sprintf  "%d/%02d/%02d - %02d:%02d:%02d"
                    (time.Unix.tm_year+1900) time.Unix.tm_mon time.Unix.tm_mday
                    time.Unix.tm_hour time.Unix.tm_min time.Unix.tm_sec

(* log a string to the channel *)
let log_string str =
    output_string (!log_channel) ((get_log_prequel ())^":\t"^str^"\n")

---logging.mli
set_log_chan : in_channel -> unit
log_string : string -> unit

I think you get the point here. The singleton is implicit, right? There really isn't an instantiation like in objects --but that's kinda what you want in a singleton. You just start using it in other files like, Logging.log_string "parsed file "^file_name^" successfully.", et cetera, anywhere and you always use the same channel.

With functors you can compose your modules to add variety. Like specifying a module/function to generate a prequel for output, et cetera.

nlucaroni
I've seen numerous references citing modules are the way to go. What is an example of an OCaml implementation of Singleton using modules? Does it enforce all of the characteristics of Singleton (e.g. private constructor, single instance enforcement, etc.)?Thanks!
Mat
Is there a way to override the copy method of the object and Oo.copy? Unfortunately, I need to use OCaml's object constructs, so immediate objects might be my only route. Do you have any other insight on how to do this? Thanks!
Mat
i don't believe you can override the copy functions --well, not without meta-ocaml (I believe), or possibly camlp4 (I believe). I guess the only recommendation here is, don't call the copy functions :)
nlucaroni
+1  A: 

Can you explain why the module solution doesn't work for you? Modules really are the natural way to do what you would do with a singleton in other languages.

As a general matter, GOF-style patterns are largely irrelevant in OCaml. Indeed, objects are largely irrelevant in OCaml. People from OO backgrounds often think they should start out by using the OO features in OCaml, but this is a mistake. Most problems that are solved with objects in other languages are solved with parametric polymorphism, algebraic datatypes and modules in OCaml. Functors are a slightly more advanced topic, and objects are way out there. You shouldn't touch the object system until you are an accomplished user of the rest of the language.

zrr