The Need for Copy Constructors

Writing and using Classes in Dyalog APL

Re: The Need for Copy Constructors

Postby Erik.Friis on Fri May 13, 2011 5:31 pm

Hi Jane,

Objects of the same class should have access to each other's private fields (I always make my fields private). At least when I wrote my Copy method this seemed to work for me. This same concept holds true in C++. Maybe they've changed the behaviour in later version of the system.

Regards, Erik
Erik.Friis
 
Posts: 66
Joined: Mon Apr 04, 2011 3:16 pm

Re: The Need for Copy Constructors

Postby paulmansour on Sun May 15, 2011 4:50 pm

I am a little confused about the issue of copy constructors. This implies a user-written function to do the cloning, which avoids the issue of having the system determine how to copy something, correct? But when would this function get called? Currently assingment is by ref. Would this have to change? Would it require a new assignment primitive?
paulmansour
 
Posts: 418
Joined: Fri Oct 03, 2008 4:14 pm

Re: The Need for Copy Constructors

Postby Budgie on Sun May 15, 2011 5:55 pm

I don't think so. What I would do is say

copy←⎕NEW MyObject MyInstance

which would go into the normal constructor. After going through some user-written code to determine if the copy constructor should be called, the copy constructor would be called, and then the constructor would be exited. So we would end up with something like this:

∇constructor arg
:implements constructor
:if we should call the copy constructor
call the copy constructor
:else
carry on
:endif
Jane
User avatar
Budgie
 
Posts: 36
Joined: Thu Nov 26, 2009 9:22 am
Location: Beckenham

Re: The Need for Copy Constructors

Postby Erik.Friis on Sun May 15, 2011 10:10 pm

paulmansour wrote:I am a little confused about the issue of copy constructors. This implies a user-written function to do the cloning, which avoids the issue of having the system determine how to copy something, correct? But when would this function get called? Currently assingment is by ref. Would this have to change? Would it require a new assignment primitive?


I don't think so Paul. My thinking was that if a Copy Constructor is defined within the class then instead of a reference being assigned (e.g. MyObj1 <- MyObj2), the Copy Constructor would be invoked and a copy created as opposed to a simple reference assignment. It is possible that the current reference assignment was the wrong thing to do, as a copy constructor would solve the "deep copy" issue they were grappling with. After all, normal variables, when assigned are copied, why shouldn't objects be as well. Though there should be a way to assign a reference or alias as well - this is definitely required. Maybe something like MyObj1Ref <- []REFERENCE MyObj1 ... I have not thought it all the way through yet. But I do know that increasingly complex OO code is in need of the concept of a Copy Constructor as far as I can tell. Though I am getting by with code like this: MyObj2 <- MyObj1.Copy though particular attention must be paid to "where" the copy is created.
Erik.Friis
 
Posts: 66
Joined: Mon Apr 04, 2011 3:16 pm

Re: The Need for Copy Constructors

Postby paulmansour on Mon May 16, 2011 2:24 pm

Jane and Erik,

Thanks - now I understand.

It seems Jane's solution, which seems not much of a savings compared to writing a clone method, would not help Erik who is looking for a cleaner syntax.

The idea of having the assignment be by value based simply on the existance of a copy construcor is neat, as it allows backward compatability (I think!).

Erik.Friis wrote:It is possible that the current reference assignment was the wrong thing to do,


But even if Dyalog had implemented copy constructors from day one, the current behavior of assignment by reference would be the only thing to do in the case of no existing copy constructor for a class. No?

Erik.Friis wrote:After all, normal variables, when assigned are copied, why shouldn't objects be as well.


This requires a long conversation over a good beverage or two! Certainly because objects contain or refer to functions, they are somewhat different than normal variables, You can write any normal variable to disk, or send it over wire, and then read it back in again and get the same thing back. What do you get when you do the same with an object? A normal variable is simply not connected to the entire workspace tree the same way an object is. Even if a class is completely self-contained, with no :Include, all environmental variables localized, etc, and thus an instance of it was easily sent down the wire, what happens when you read it back in again? Do the function versions in the class or instance take precedence? What if the class did not exist on the other side? What if it did and the version was different?

Perhaps because I have just been using the Dyalog implemenationfor so long, and don't really have much experience whith anything else, it all seems perfectly natural to me that objects (and namespaces) are passed and assigned by ref. In fact, a long time ago, when refs where introduced, and as an APLer, I was trying to get my head around them, John Scholes said that in the future we wouldn't call them refs, implying that the terminology was somewhat of a crutch. Sure enough, my old code is littered with variable names like RefToThis and RefToThat, and now always just use This and That.
paulmansour
 
Posts: 418
Joined: Fri Oct 03, 2008 4:14 pm

Re: The Need for Copy Constructors

Postby Erik.Friis on Fri May 20, 2011 2:25 pm

Erik.Friis wrote:Objects of the same class should have access to each other's private fields (I always make my fields private). At least when I wrote my Copy method this seemed to work for me. This same concept holds true in C++. Maybe they've changed the behaviour in later version of the system.


I double check this yesterday and V13.0 does not allow objects of the same class to have access to each others' private fields. This makes it difficult (it would have to be done with a constructor that has arguments for every field) to write a copy/clone method for any class that has private fields unless a public get/set property is available for this field. My code appeared to be working, but it was writing the variables to that surrounding namespace :( -- yet another reason why this surrounding namespace should be done away with.

My Copy method looked like this:
Code: Select all
:class MyClass

:field private MyField

.
.
.

{del}r<-Copy
     :access public

     r<-#.[]NEW #.MyClass
     r.MyField<-MyField
{del}


The code ran, but MyField was created in the surrounding namespace for r (yuck!)

I'm not sure exactly what the reasoning is in OO languages for objects of the same class to have access to each others' private fields and it does seem counter-intuitive that anyone should have access to a private field, but I'm sure this sort of thing was part of the reason. Hopefully someone will give us a fuller explaination, so I don't have to dig out my Stroustrup "Design of C++". If copy constructors are added to Dyalog APL and I suspect they will be, then it is possible that only a copy constructor would be granted access to another object's private fields (of the same class).
Erik.Friis
 
Posts: 66
Joined: Mon Apr 04, 2011 3:16 pm

Re: The Need for Copy Constructors

Postby Erik.Friis on Fri May 20, 2011 5:54 pm

So it seems that the following (though a bit ungainly) code will work to create a copy of an object IF the class is a non-derived class. I cannot, however, see a way to create a copy of an object which is an instance of a derived class where both classes contain private fields. At this point I don't think it can be done with the current implementation.

Code: Select all
x<-[]NEW #.MyClass (1 2 3)
y<-x.Copy


Code: Select all
:Class MyClass
    :field private MyField1
    :field private MyField2
    :field private MyField3

    ∇ MyClass(Field1_ Field2_ Field3_)
      :Implements constructor
      :Access public
     
      (MyField1 MyField2 MyField3)←Field1_ Field2_ Field3_
    ∇

    ∇ MyClass_
      :Implements constructor
      :Access public
    ∇

    :property Field1
    :access public

        ∇ r←get x
          r←MyField1
        ∇
    :endproperty

    :property Field2
    :access public

        ∇ r←get x
          r←MyField2
        ∇
    :endproperty

    :property Field3
    :access public

        ∇ r←get x
          r←MyField3
        ∇
    :endproperty

    ∇ r←Copy
      :Access public
     
      r←#.⎕NEW #.MyClass(MyField1 MyField2 MyField3)
    ∇
:EndClass
Erik.Friis
 
Posts: 66
Joined: Mon Apr 04, 2011 3:16 pm

Re: The Need for Copy Constructors

Postby paulmansour on Fri May 20, 2011 6:37 pm

Erik,

You should be able to use system functions to get the name list of the properties, construct a namespace to contain the name/value pairs (a parameter space, if you will), pass this single ns to the constructor, and then set all the properties of the new copy. You won't have to explicity refrence any field names anywhere. And it will work for any class.

Paul
paulmansour
 
Posts: 418
Joined: Fri Oct 03, 2008 4:14 pm

Re: The Need for Copy Constructors

Postby uwejanza on Mon May 23, 2011 4:40 pm

Just to give an example of what works for me to clone object instances as far as I need it in my application - not claiming to deliver a solution that deserves being called general or complete.

Seems to me quite close to what Paul proposed.

Still there is an annoying inconsistency in use of name classes between ∆CopyFrom and ∆CopyTo which I learned to accept because that was the only way the code worked when I started running out of time in my project.

Code: Select all
:class MyFunnyLittleBaseClass

  :property Simple ∆CopyFrom
  :Access Public Instance
        ∇ ⍙←get
        ⍝ This property is used on the instance that is to be cloned
          ⍙←{⍵(⍎⍕⍵)}(⊂[2]⎕NL 2.1 2.2)~¨' '
  :endproperty

  :property Simple ∆CopyTo
  :Access Public Instance
        ∇ set ⍙;⍙1
        ⍝ This method is applied on the instance that we want to change
        ⍝ All values passed in the argument have to exist in the target object       
          'DATA SOURCE IS NOT COMPATIBLE'⎕SIGNAL 11/⍨0≠↑⍴(⎕NC 1⊃⍙.NewValue)~2.1 2.2 2.6
          ⍎'(',(⍕1⊃⍙.NewValue),')←2⊃⍙.NewValue'
  :endproperty 

    ∇ MakeMeACloneOf SourceObject;Fields
      :Access Public Instance
    ⍝ Copies the data contained in SourceObject to the Instance we run on
      ∆CopyTo←QuellObjekt.∆CopyFrom
    ∇

:endclass


Method MakeMeACloneOf has to be invoked on the instance that is expected to be changed.
It copies instances of classes derived from MyFunnyLittleBaseClass as well as instances of the base class. You can even copy between instances of different classes, as long as the target instance accepts all the properties/fields the source instance offers.

Exampl of use:
Code: Select all
   FirstInstance←⎕NEW MyFunnyLittleBaseClass

   FirstInstance.FiddleAroundWithInstanceData

   SecondInstance←⎕NEW MyFunnyLittleBaseClass

   SecondInstance.MakeMeACloneOf FirstInstance


Uwe
uwejanza
 
Posts: 19
Joined: Tue Mar 09, 2010 2:01 pm
Location: Nürnberg, Germany

Re: The Need for Copy Constructors

Postby Erik.Friis on Mon May 23, 2011 5:13 pm

Thanks for posting this. Does it work for derived classes?
Erik.Friis
 
Posts: 66
Joined: Mon Apr 04, 2011 3:16 pm

PreviousNext

Return to Object Oriented Programming

Who is online

Users browsing this forum: No registered users and 1 guest