Loading ...
Sorry, an error occurred while loading the content.

duplicate objects problem

Expand Messages
  • code17
    Hi, there I recently got problems when I want to define a function which accepts an object and an integer n as parameter and gives out an array of n such
    Message 1 of 5 , Nov 2, 2006
    • 0 Attachment
      Hi, there

      I recently got problems when I want to define a function which accepts an
      object and an integer "n" as parameter and gives out an array of n such
      objects, i.e., int -> <obj> -> <obj> Array.t

      It sounds like Array.make can do it. But wait, here in my case, I actually
      want the n objects behavior totally independent from each other --- if the
      original object contain some mutable instant variable, they will be shared by
      all the instances, and the action of one object will likely to have effect on
      others.

      OK, Oo.copy is now the candidate. It is provided to "clone" an object. Instant
      variables won't be shared. However, as the manual says, Oo.copy is a
      superficial copy, "... a deeper assignment (for example if the instance
      variable is a reference cell) will of course affect both the original and the
      copy ..." :(

      Now comes the deep_copy function

      --------------------------------------------------------------------------
      let deep_copy (x:'a) =
      ((Marshal.from_string (Marshal.to_string x [Marshal.Closures]) 0): 'a);;
      --------------------------------------------------------------------------

      which seems to do the job quite well, all the values (even those being
      referenced from current object) are duplicated. But is that all?

      - when the original object was built, it opened some sockets and had them as
      inside values for further operations (i.e. reading/writing). Now the same
      value appear in all instances, i.e. all the instances will read from/write
      to the same sockets. In most cases, this is not what we want.

      - when the original object was built, it can register itself somewhere,
      however those duplications (by value copying) just won't.

      In one word, all the values of a created object can be copied, but the process
      of creating the object won't. So, it turns out that what I need is not object
      duplicator but object generator --- class that can produce new object
      instances. However class is NOT first-class value and can't be passed as
      parameters. Ideally, I'd like to be able to written

      -------------------------------------------------------------------
      let make_n_object n class_a = Array.init n (fun _ -> new class_a);;
      -------------------------------------------------------------------

      so it can build n independent objects, with all the initializations done for
      each of them. This is the most intuitive expressions one should come out with
      naturally. It states *exactly* what should be happen, however it's invalid.

      I though of two kinds of workaround, but neither is satisfactory.

      - Instead of using class as parameter, now we require a generator function of
      type (unit -> obj_a) as the parameter. and now

      ----------------------------------------------------------------------
      let make_n_object n generator = Array.init n (fun _ -> generator ());;
      ----------------------------------------------------------------------

      the programmer who use this function would write

      -------------------------------------
      let gen_a = fun () -> new class_a in
      make_n_object 10 gen_a;;
      -------------------------------------

      If this function is used by myself, then it's not a big deal, because I
      know what happens and why . However, it will be provided in a library to
      others. This unit thing looks common for experienced programmers (they know
      it is used to serve various purpose: generator, freeze/unfreeze, produce
      side-effect at appropriate time ...), but weird for a not-so-experienced
      programmer (why it is like that? why this is necessary? I just want to copy
      my objects ...) and if they don't understand well but simply follow the
      type signature, they can program

      --------------------------------------------------------
      let gen_a = let obj_a = new class_a in fun () -> obj_a;;
      --------------------------------------------------------

      which is definitely against our original intention.

      - Another solution would be force the programmer to have an #instance method
      of type (unit -> <obj>) in each object (this only works under certain
      restrictions, e.g. all the objects can only be produced through
      inheritance), which can reproduce the necessary side-effect together with a
      deep copy. By calling obj#instance (n-1) times, we now have n such
      objects. The original object serves as a template as well as an instance
      itself.

      Can anyone suggest some better solutions? Thanks

      -code17
    • Richard Jones
      ... I don t this function is such a good idea ... Part of the problem is that it doesn t change the object s id field. All objects are supposed to have a
      Message 2 of 5 , Nov 2, 2006
      • 0 Attachment
        On Thu, Nov 02, 2006 at 11:42:43AM +0100, code17 wrote:
        > let deep_copy (x:'a) =
        > ((Marshal.from_string (Marshal.to_string x [Marshal.Closures]) 0): 'a);;

        I don't this function is such a good idea ... Part of the problem is
        that it doesn't change the object's id field. All objects are
        supposed to have a unique id, but it's not clear what happens if you
        manage to create objects with the same id, as this does. Possibly
        operations which hash the object will fail -- eg. using objects as a
        key in a Hashtbl.

        # let deep_copy (x:'a) =
        ((Marshal.from_string (Marshal.to_string x [Marshal.Closures]) 0): 'a);;
        val deep_copy : 'a -> 'a = <fun>
        # let obj1 =
        object val mutable i = 0 method set_i i' = i <- i' method i = i end;;
        val obj1 : < i : int; set_i : int -> unit > = <obj>
        # obj1#set_i 42;;
        - : unit = ()
        # obj1#i;;
        - : int = 42
        # let obj2 = deep_copy obj1;;
        val obj2 : < i : int; set_i : int -> unit > = <obj>
        # obj2#i;;
        - : int = 42
        # Oo.id obj1;;
        - : int = 0
        # Oo.id obj2;;
        - : int = 0

        > - when the original object was built, it opened some sockets and had them as
        > inside values for further operations (i.e. reading/writing). Now the same
        > value appear in all instances, i.e. all the instances will read from/write
        > to the same sockets. In most cases, this is not what we want.
        >
        > - when the original object was built, it can register itself somewhere,
        > however those duplications (by value copying) just won't.

        So you don't want to blindly copy the object, but copy some fields but
        not others, and perhaps do a bit of other work too. This means you
        need to have a per-class #copy method, or #instance as you have called
        it below:

        [...]
        > - Another solution would be force the programmer to have an #instance method
        > of type (unit -> <obj>) in each object (this only works under certain
        > restrictions, e.g. all the objects can only be produced through
        > inheritance), which can reproduce the necessary side-effect together with a
        > deep copy. By calling obj#instance (n-1) times, we now have n such
        > objects. The original object serves as a template as well as an instance
        > itself.

        # let copy (x:'a) = (x#copy : 'a);;
        val copy : (< copy : 'a; .. > as 'a) -> 'a = <fun>

        Rich.

        --
        Richard Jones, CTO Merjis Ltd.
        Merjis - web marketing and technology - http://merjis.com
        Internet Marketing and AdWords courses - http://merjis.com/courses - NEW!
        Merjis blog - http://blog.merjis.com - NEW!
      • Richard Jones
        ... You might also want to read this: http://caml.inria.fr/pub/old_caml_site/caml-list/1685.html Rich. -- Richard Jones, CTO Merjis Ltd. Merjis - web marketing
        Message 3 of 5 , Nov 2, 2006
        • 0 Attachment
          On Thu, Nov 02, 2006 at 01:01:04PM +0000, Richard Jones wrote:
          > I don't this function is such a good idea ... Part of the problem is
          > that it doesn't change the object's id field. All objects are
          > supposed to have a unique id, but it's not clear what happens if you
          > manage to create objects with the same id, as this does. Possibly
          > operations which hash the object will fail -- eg. using objects as a
          > key in a Hashtbl.

          You might also want to read this:

          http://caml.inria.fr/pub/old_caml_site/caml-list/1685.html

          Rich.

          --
          Richard Jones, CTO Merjis Ltd.
          Merjis - web marketing and technology - http://merjis.com
          Internet Marketing and AdWords courses - http://merjis.com/courses - NEW!
          Merjis blog - http://blog.merjis.com - NEW!
        • code17
          ... Thanks for the hint. I will treat it more carefully. ... Actually, I need the ability of regenerate n new objects, including all the values as well as all
          Message 4 of 5 , Nov 2, 2006
          • 0 Attachment
            Richard Jones <rich@...> writes:
            > I don't this function is such a good idea ... Part of the problem is
            > that it doesn't change the object's id field. All objects are
            > supposed to have a unique id, but it's not clear what happens if you
            > manage to create objects with the same id, as this does. Possibly
            > operations which hash the object will fail -- eg. using objects as a
            > key in a Hashtbl.
            Thanks for the hint. I will treat it more carefully.

            > So you don't want to blindly copy the object, but copy some fields but
            > not others, and perhaps do a bit of other work too. This means you
            Actually, I need the ability of regenerate n new objects, including all the
            values as well as all the side-effect when building each of them. More
            preciously, I need object generator -- is the exact concept of *class*!
            However, as in my previous post, if you want to define a function a la
            Array.make, you can not pass the natural generator (class) as parameter,
            instead you can only produce and pass a (unit -> obj) wrapper for *each*
            class.

            I'm sorry maybe my previous post didn't distinguish "duplicate n" and
            "generate n" quite well. This is due to the fact that, in my case, all the n
            objects will be created before any actions being taken on them, so no inside
            state has been changed. To avoid the unit-wrapper generator, I thought a
            duplicator which takes one input object and gives n of them back is another
            possibility having a quite natural type sig. However, I just forgot that copy
            value won't reproduce the necessary side-effect (such as creating channels
            etc).

            Any other suggestions?

            ps, It's quite regretful that OCaml doesn't have module and class as first
            class value. Module has module type, class has class type, expression such as
            "snd (ModuleA, ModuleB)" should have a predictable type (though the meaning of
            pattern-match a Module/Class can be odd), why can't they be taken as values in
            certain cases?

            - code17
          • Martin Jambon
            ... Then you should do this: 1) Your classes take an additional () parameter, which makes new c a function of type unit - 2) Your library provides
            Message 5 of 5 , Nov 2, 2006
            • 0 Attachment
              On Thu, 2 Nov 2006, code17 wrote:

              > I though of two kinds of workaround, but neither is satisfactory.
              >
              > - Instead of using class as parameter, now we require a generator function of
              > type (unit -> obj_a) as the parameter. and now
              >
              > ----------------------------------------------------------------------
              > let make_n_object n generator = Array.init n (fun _ -> generator ());;
              > ----------------------------------------------------------------------
              >
              > the programmer who use this function would write
              >
              > -------------------------------------
              > let gen_a = fun () -> new class_a in
              > make_n_object 10 gen_a;;
              > -------------------------------------
              >
              > If this function is used by myself, then it's not a big deal, because I
              > know what happens and why . However, it will be provided in a library to
              > others.

              Then you should do this:
              1) Your classes take an additional () parameter, which makes "new c" a
              function of type unit -> <obj>
              2) Your library provides functions for each class and the doc recommends
              to use them instead of "new class". They share different namespaces, so
              they can (and should) have the same name.


              For example:

              class c () =
              object
              ...
              end

              let c () = new c ()


              > This unit thing looks common for experienced programmers (they know
              > it is used to serve various purpose: generator, freeze/unfreeze, produce
              > side-effect at appropriate time ...), but weird for a not-so-experienced
              > programmer (why it is like that? why this is necessary? I just want to copy
              > my objects ...) and if they don't understand well but simply follow the
              > type signature, they can program

              --
              Martin Jambon, PhD
              http://martin.jambon.free.fr
            Your message has been successfully submitted and would be delivered to recipients shortly.