9 Replies Latest reply on Jul 23, 2006 2:48 PM by BKBK

    Cloning CFC instances In Memory

    friendofasquid Level 1
      We have a framework which can create hundreds of CFCs per page request. Most of the request time is used when a CreateObject("component", "....") is executed. This time is large because template caching must be disabled for other reasons. When the cache is enabled, the execution time is reduced significantly, sometimes by a factor of 5 or more.

      To compensate, I'd like to keep a prototype of each CFC I will be creating in memory, and then clone the one that currently resides in memory to avoid disk I/O. Note that I don't want a "deep copy" of a CFC because they should be empty prototypes anyways.

      This is possible in Java using the Object.clone() (deep copy) method or perhaps Object.getClass().newInstance() (empty copy), of which the latter approach is the one I'd like to take.

      I've tried writing a simple function in Java to do this:
      public static createFromInstance(Object obj) {
      ...
      return obj.getClass().newInstance();
      ...
      }

      but trying to use this method within ColdFusion gives undefined variables exceptions.

      We are using CF 6.1, but we may consider a move to 7. Perhaps using the CFCProxy class in 7.0.1 will work. Has anyone tried this method or has anyone written a Java or ColdFusion solution using 6.1? Can anyone explain the underlying mechanism of how CFCs map to Java objects, and how it might be possible to clone them?
        • 1. Re: Cloning CFC instances In Memory
          nimer
          CFC are ColdFusions version of Objects, however they are not instances of a java class so you can't clone them. Sorry.

          Can you reuse the same instance, and call a reset function between uses?
          • 2. Re: Cloning CFC instances In Memory
            friendofasquid Level 1
            I've considered keeping a pool of CFC to reuse, but I think it will quickly become too messy and complex to be a sustainable approach. We're talking an extremely high volume site.

            I thought CF compiles CFCs into Java classes, as it does for .cfm pages.

            This is really boils down to the lack of control of template caching, where it would be nice to do something like
            <cfsetting enabletrustedcache="true">...</cfsetting>

            I've written a similar custom tag, but because template cache is per server (not per request or even per application), that's not going to work in any meaningful way,
            • 3. Re: Cloning CFC instances In Memory
              Level 7
              This requirement has been around for a few years now: basically since 6.1
              and people starting to use CFCs with anger.

              For CFMX7, the best Macromedia could come up with was causing duplicate()
              to error if one tried to duplicate() a CFC instance (cf earlier versions
              which "duplicated" them into a struct). Are they actually thinking of
              fixing duplicate() so that it does actually duplicate the CFC instance?
              This "fix" to duplicate() in CFMX7 was a bit of a slack effort.

              --
              Adam
              • 4. Re: Cloning CFC instances In Memory
                BKBK Adobe Community Professional & MVP
                I wonder whether the pound (#) signs ensure that obj is a copy of comp.

                <cfobject component="mycomponent" name="comp" >
                <cfobject action="CREATE" type="JAVA" class="java.lang.Object" name="obj">
                <cfset obj = #comp#>
                <cfinvoke component="#obj#" method="myfunc" <!--- etc. ---> />

                • 5. Re: Cloning CFC instances In Memory
                  friendofasquid Level 1
                  a quick check:


                  <cfset obj = CreateObject("java", "java.lang.Object").init() />
                  <cfdump var="#obj.toString()#" /><br />

                  <cfset newInstance = #obj# />
                  <cfdump var="#newInstance.toString()#" />


                  reveals this is not the case.

                  • 6. Re: Cloning CFC instances In Memory
                    nimer Level 1
                    It does compile them into java, but not into a simple java class that could be cloned. It's more like a set of proxy objects.

                    There is a way to make setting changes like this on a per application basis. The trick is to use the j2ee version. If you install CF with the multi-version version you'll be able to deploy CF has a war for each portion of the application.

                    For instance right now you have your app broken up into subfolders. However what you can do is make each of those folders a new cf "war" deployment. Which makes each sub folder a standalone application complete with it's own cfadmin.

                    It's a trickier config then the simple standalone, and it does take a few more resources. But you'll get a lot more control. Of course read the CF docs on .war deployment before you do anything. But once you get used to breaking your apps up this way you'll always do it.
                    • 7. Re: Cloning CFC instances In Memory
                      BKBK Adobe Community Professional & MVP
                      > a quick check:

                      > <cfset obj = CreateObject("java", "java.lang.Object").init() />
                      > <cfdump var="#obj.toString()#" /><br />
                      > <cfset newInstance = #obj# />
                      > <cfdump var="#newInstance.toString()#" />

                      > reveals this is not the case.


                      Not quite. You're not comparing like with like. My suggestion involves two objects, not two instances of the same object.

                      Below, I have integrated your logic into my suggestion. The pounds (#) may not be necessary. However, I include them to further insist to Coldfusion to pass by value rather than by reference.

                      • 8. Re: Cloning CFC instances In Memory
                        Level 7
                        > The pounds (#) may not
                        > be necessary. However, I include them to further insist to Coldfusion to pass
                        > by value rather than by reference.

                        It does nothing of the sort. Pound-signs simply flag to CF that a char
                        sequence represents a variable name rather than a string, in situations
                        where there could be ambiguity:
                        - within a string, eg: "My name is #name#", as opposed to "My name is
                        name".
                        - outside of CF tags, eg: <cfoutput>My name is #name#</cfoutput>, as
                        opposed to <cfoutput>My name is name</cfoutput>

                        Within your example there is no ambiguity, so the pound signs are simply
                        redundant.

                        All your sample code is, likewise, redundant.

                        All you are demonstrating is that the copied-by-reference objects have
                        different REFERENCES. Well of course they do. Each of those references
                        (different memory locations in the stack) point to the same memory location
                        (in the heap) for the actual object instance data.

                        When you set obj to null, you are setting the REFERENCE to null, not the
                        object. Incidentally, no GC will be done on the object until ALL the
                        references to it are deleted (and even then, only when Java decides to do
                        it).

                        There is - currently - NO WAY to clone / duplicate an object in CF. If
                        you want to do so, you need to roll your own method which (recursively)
                        creates a new object instance and clones/duplicates its variables and this
                        scopes. That's as good as it gets.

                        --
                        Adam
                        • 9. Re: Cloning CFC instances In Memory
                          BKBK Adobe Community Professional & MVP
                          > The pounds (#) may not
                          > be necessary. However, I include them to further insist to Coldfusion to pass
                          > by value rather than by reference.

                          It does nothing of the sort. Pound-signs simply flag to CF that a char
                          sequence represents a variable name rather than a string, in situations
                          where there could be ambiguity:
                          - within a string, eg: "My name is #name#", as opposed to "My name is
                          name".
                          - outside of CF tags, eg: <cfoutput>My name is #name#</cfoutput>, as
                          opposed to <cfoutput>My name is name</cfoutput>

                          Within your example there is no ambiguity, so the pound signs are simply
                          redundant.

                          All your sample code is, likewise, redundant.


                          I'll simply repeat the Coldfusion fact. The statement <cfset var1 = #var2#> assigns the value of var 2 to the variable var1.

                          All you are demonstrating is that the copied-by-reference objects have
                          different REFERENCES. Well of course they do. Each of those references
                          (different memory locations in the stack) point to the same memory location
                          (in the heap) for the actual object instance data.


                          No disagreement there, as my code in fact demonstrates the point. It was simply to show Coffeeflower that my starting point was two objects rather than two instances of one object.

                          When you set obj to null, you are setting the REFERENCE to null, not the
                          object. Incidentally, no GC will be done on the object until ALL the
                          references to it are deleted (and even then, only when Java decides to do it).


                          Your argument is still good in Java. However, I think it needs some qualification in Coldfusion. My hypothesis is based on the pound (#) symbol, for which there is no equivalent in Java. I'll maintain the distinction you make between references on the stack and objects on the heap. Not only is it unimpeachable, it will now help me present my hypothesis more clearly.

                          An object reference points to the location of an object and its metadata on the heap. Object references, like the primitives,

                          <cfset myVar = 5>
                          <cfset x = #myVar#>

                          are stored on stack memory. I therefore wonder whether one can use the pound (#) symbol, or any other native Coldfusion technique, to create a primitive-like assignment. Could we, by replacing the reference to the heap with a primitive value assignment, create a copy of an object on the stack?