Jump to page: 1 24  
Page
Thread overview
Newbie: copy, assignment of class instances
May 20, 2010
Larry Luther
May 20, 2010
Simen kjaeraas
May 27, 2010
Larry Luther
May 20, 2010
bearophile
May 20, 2010
bearophile
May 20, 2010
bearophile
May 20, 2010
Simen kjaeraas
May 27, 2010
Larry Luther
May 27, 2010
bearophile
May 20, 2010
Larry Luther
May 20, 2010
bearophile
May 20, 2010
Larry Luther
May 20, 2010
bearophile
May 20, 2010
bearophile
May 27, 2010
Larry Luther
May 27, 2010
bearophile
May 27, 2010
bearophile
May 27, 2010
Ali Çehreli
May 27, 2010
bearophile
May 20, 2010
bearophile
May 20, 2010
Ellery Newcomer
May 20, 2010
bearophile
May 21, 2010
Larry Luther
May 21, 2010
bearophile
May 27, 2010
Larry Luther
May 27, 2010
bearophile
May 27, 2010
bearophile
May 27, 2010
bearophile
Re: Newbie: Inheritance & slicing problem
Jun 02, 2010
Larry Luther
May 20, 2010
bearophile
May 20, 2010
Given:

  class A {
    int x, y;
  }

  class B : A {
    int z;
  }

  B
    foo = new B,
    bar = new B;

  scope B
    alpha = new B;

Q1:  How do I copy the member variables contributed by base class A
     from "foo" to "bar"?
     In C++:  (A &) bar = foo;

Q2:  How do I do a deepcopy of foo to bar?
     In C++:  bar = foo;

Q3:  Is the object "alpha" on the stack (per documentation)?

Q4:  What happens when I do "alpha = foo;"?
     "printf( "%p\n", alpha);" indicates that the address of "alpha" has changed.

Thanks, Larry

May 20, 2010
Larry Luther <larry.luther@dolby.com> wrote:

> Given:
>
>   class A {
>     int x, y;
>   }
>
>   class B : A {
>     int z;
>   }
>
>   B
>     foo = new B,
>     bar = new B;
>
>   scope B
>     alpha = new B;
>
> Q1:  How do I copy the member variables contributed by base class A
>      from "foo" to "bar"?
>      In C++:  (A &) bar = foo;

You can't. If you need this functionality, use a specialized function.

> Q2:  How do I do a deepcopy of foo to bar?
>      In C++:  bar = foo;

You don't. If you need this functionality, use a specialized function.
This should, to keep symmetry with other D features, probably be
called dup. Possibly deepdup, as the other dups don't do deep copy.

It is also worth noting that 'bar = foo;' does not perform deep copying
in C++, it only copies the immediate members, whereas deep copy would
follow pointers and deep copy those, too.

btw, if what you're referring to is not the deep copy explained above,
but merely a shallow copy (of the instance, not the reference), the
function should be called dup.

> Q3:  Is the object "alpha" on the stack (per documentation)?

Yes. Proof:

void main( ) {
    A a = new A( );
    scope A b = new A( );
    writefln( "%p, %p, %p", cast(void*)a, cast(void*)b, cast(void*)&a );
}

> Q4:  What happens when I do "alpha = foo;"?
>      "printf( "%p\n", alpha);" indicates that the address of "alpha" has changed.

'scope B alpha;' allocates stack space for a reference to a B, and
space for an instance of B. If the pointer changes, it is simply no longer
referencing the instance on the stack.

-- 
Simen
May 20, 2010
Larry Luther:

>   class A {
>     int x, y;
>   }
> 
>   class B : A {
>     int z;
>   }
> 
>   B
>     foo = new B,
>     bar = new B;
> 
>   scope B
>     alpha = new B;

Don't write code like this, it's not easy to write:

>   B
>     foo = new B,
>     bar = new B;

Write it this way:

B foo = new B,
B bar = new B;

Or this way:

auto foo = new B,
auto bar = new B;


> Q1:  How do I copy the member variables contributed by base class A
>      from "foo" to "bar"?
>      In C++:  (A &) bar = foo;

There is no standard way to do this. In general you don't need to copy classes or their contents, because they are on the heap and managed by the GC. If you want to copy their contents you have to add methods written by you that perform the copy you need.


> Q2:  How do I do a deepcopy of foo to bar?
>      In C++:  bar = foo;

In general you don't do it. There is no standard way to perform a deep copy. You can write your code to do it, but it's not easy to write. So far I have never had to perform a deep copy on D classes.

For structs take a look at postblit too: http://www.digitalmars.com/d/2.0/struct.html#StructPostblit


> Q3:  Is the object "alpha" on the stack (per documentation)?

In this case with ldc and dmd alpha is on the stack, you can see also reading the produced asm. On the docs you can read the rules that must be satisfied for scoped classes to be really allocated on the stack.


> Q4:  What happens when I do "alpha = foo;"?
>      "printf( "%p\n", alpha);" indicates that the address of "alpha" has changed.

alpha is on the stack, but beside alpha on the stack there is also the reference to alpha. So such reference gets rewritten.
Generally in D it's not a good idea to reassign the reference to a scoped class (some months ago I have even suggested to turn this operation into a syntax error) because when the scope ends, the class referenced by the reference to alpha gets collected, so if you change such reference to something else, it is such something else that gets collected. I am not sure what happens here, but this can be a source of bad troubles. This is probably why Walter was thinking of removing the scope attribute for classes.

Bye,
bearophile
May 20, 2010
> Generally in D it's not a good idea to reassign the reference to a scoped class

You can see it with this little D2 program:


import std.stdio: printf;
class Foo {
    int x;
    this(int xx) { this.x = xx; }
    ~this() { printf("Foo(%d) destructor\n", this.x); }
}
void main() {
    scope Foo f1 = new Foo(1);
    Foo f2 = new Foo(2);
    f1 = f2;
}

It prints just:
Foo(2) destructor

In general this is not good.
Bye,
bearophile
May 20, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=4214
May 20, 2010
Thank you for the clarifications.
I'm trying to do a shallow copy.

After reading Simen & bearophile, I would add a "copy" member function:

  class A {
    int x, y;

    void copy (in A a) {
      x = a.x;
      y = a.y;
    }
  }

  class B : A {
    int z;

    void copy (in B b) {
      super.copy( b);
      z = b.z;
    }
  }

  B foo = new B,
  B bar = new B;

Q:  Do I copy the member variables contributed by class A
    from "foo" to "bar", this way:  "(cast(A) bar).copy( foo);"?
    Or maybe "bar.A.copy( foo);"?

Larry

May 20, 2010
Larry Luther:

>  B foo = new B,
>  B bar = new B;

This is not valid D code, you have to use something like:

B foo = new B;
B bar = new B;


I suggest you to actually try to compile and run your little test programs. If you compile this:


class A {
    int x, y;

    void copy(A a) {
        x = a.x;
        y = a.y;
    }
}

class B : A { // line 10
    int z;

    void copy(B b) {
        super.copy(b);
        z = b.z;
    }

}

void main() {
    B foo = new B;
    B bar = new B;
}


You get this (badly written) error:
test.d(10): Error: class test2.B test2.A.copy(A a) is hidden by B



This works:


import std.stdio: writeln;
import std.string: format;


template ExceptionTemplate() {
    this() {
        super(this.classinfo.name);
    }

    this(string msg) {
        super(this.classinfo.name ~ ": " ~ msg);
    }
}


class ArgumentException: Exception {
    mixin ExceptionTemplate;
}


class A {
    int x, y;

    this(int xx, int yy) {
        this.x = xx;
        this.y = yy;
    }

    void copyFrom(Object other) {
        auto o = cast(typeof(this))other;
        if (o is null)
            throw new ArgumentException("Some message here...");
        x = o.x;
        y = o.y;
    }

    override string toString() {
        return format("A(%d, %d)", this.x, this.y);
    }
}

class B : A {
    int z;

    this(int xx, int yy, int zz) {
        super(xx, yy);
        this.z = zz;
    }

    override void copyFrom(Object other) {
        auto o = cast(typeof(this))other;
        if (o is null)
            throw new Exception("..."); // use a more specific exception here
        super.copyFrom(other);
        z = o.z;
    }

    override string toString() {
        return format("B(%d, %d, %d)", this.x, this.y, this.z);
    }
}

void main() {
    B foo = new B(1, 2, 3);
    B bar = new B(4, 5, 6);

    writeln("foo = ", foo);
    writeln("bar = ", bar);

    foo.copyFrom(bar);

    writeln("foo = ", foo);
    writeln("bar = ", bar);
}


Output:
foo = B(1, 2, 3)
bar = B(4, 5, 6)
foo = B(4, 5, 6)
bar = B(4, 5, 6)




An alternative implementation:


import std.stdio: writeln;
import std.string: format;


template ExceptionTemplate() {
    this() {
        super(this.classinfo.name);
    }

    this(string msg) {
        super(this.classinfo.name ~ ": " ~ msg);
    }
}


class ArgumentException: Exception {
    mixin ExceptionTemplate;
}


class A {
    int x, y;

    this(int xx, int yy) {
        this.x = xx;
        this.y = yy;
    }

    void copyFrom(typeof(this) other) {
        x = other.x;
        y = other.y;
    }

    override string toString() {
        return format("A(%d, %d)", this.x, this.y);
    }
}


class B : A {
    int z;

    this(int xx, int yy, int zz) {
        super(xx, yy);
        this.z = zz;
    }

    override void copyFrom(typeof(super) other) {
        auto o = cast(typeof(this))other;
        if (o is null)
            throw new ArgumentException("Some message here...");
        super.copyFrom(other);
        z = o.z;
    }

    override string toString() {
        return format("B(%d, %d, %d)", this.x, this.y, this.z);
    }
}


void main() {
    B foo = new B(1, 2, 3);
    B bar = new B(4, 5, 6);

    writeln("foo = ", foo);
    writeln("bar = ", bar);

    foo.copyFrom(bar);

    writeln("foo = ", foo);
    writeln("bar = ", bar);
}


In other languages an operator as "isa" replaces the less nice looking dynamic cast followed by null test.

Bye,
bearophile
May 20, 2010
I did not get an error when building and running with DMD 2.042:

import std.stdio;


class A {
  int x, y;

  void copy (in A a) {
    x = a.x;
    y = a.y;
  }

  void dump (string s) {
    writefln( "%s.A = { %s, %s }", s, x, y);
  }
}

class B : A {
  int z;

  void copy (in B b) {
    super.copy( b);
    z = b.z;
  }

  void dump (string s) {
    super.dump( s);
    writefln( "%s.B = { %s }", s, z);
  }
}


void main () {
  B foo = new B;
  B bar = new B;

  foo.x = 3;
  foo.y = 5;
  foo.z = 17;

  bar.x = 7;
  bar.y = 11;
  bar.z = 13;

  foo.dump( "foo");
  bar.dump( "bar");

  bar.copy( foo);
  bar.dump( "bar#2");
}

Which prints:

foo.A = { 3, 5 }
foo.B = { 17 }
bar.A = { 7, 11 }
bar.B = { 13 }
bar#2.A = { 3, 5 }
bar#2.B = { 17 }


May 20, 2010
Larry Luther:
>     void copy (in A a) {

In D2 it's better to use "const" or "immutable" instead of "in".

Here's one version of the code const-aware:


import std.stdio: writeln;
import std.string: format;


template ExceptionTemplate() {
    this() {
        super(this.classinfo.name);
    }

    this(string msg) {
        super(this.classinfo.name ~ ": " ~ msg);
    }
}


class ArgumentException: Exception {
    mixin ExceptionTemplate;
}


class A {
    int x, y;

    this(int xx, int yy) {
        this.x = xx;
        this.y = yy;
    }

    void copyFrom(const Object other) {
        const o = cast(typeof(this))other;
        if (o is null)
            throw new ArgumentException("Some message here...");
        x = o.x;
        y = o.y;
    }

    override string toString() const {
        return format("A(%d, %d)", this.x, this.y);
    }
}


class B : A {
    int z;

    this(int xx, int yy, int zz) {
        super(xx, yy);
        this.z = zz;
    }

    override void copyFrom(const Object other) {
        const o = cast(typeof(this))other;
        if (o is null)
            throw new ArgumentException("Some message here...");
        super.copyFrom(other);
        z = o.z;
    }

    override string toString() const {
        return format("B(%d, %d, %d)", this.x, this.y, this.z);
    }
}


void main() {
    B foo = new B(1, 2, 3);
    B bar = new B(4, 5, 6);

    writeln("foo = ", foo);
    writeln("bar = ", bar);

    foo.copyFrom(bar);

    writeln("foo = ", foo);
    writeln("bar = ", bar);
}


Bye,
bearophile
May 20, 2010
Larry Luther:

> I did not get an error when building and running with DMD 2.042:

I am using dmd v2.046, and I have taken the good habit of compiling with -w (warnings on).
It seems this error I see is a blocking warning. It's a warning badly written, but do you agree it is saying something important? I presume your code can lead to bugs. I don't know why this is a warning instead of a true error...

On your code it also complains for a missed "override" that is a good thing that eventually will become obligatory even without -w.

When you post here I suggest you to avoid using HTML and use pure text.

Bye,
bearophile
« First   ‹ Prev
1 2 3 4