August 20, 2005
"Burton Radons" <burton-radons@smocky.com> wrote in message news:de838k$1ouu$1@digitaldaemon.com...
> Haha, why'd I put that in a template?  It just hides the cast.  That should be:
>
>     private extern (C) Object _d_newclass (ClassInfo info);
>
>     Object shallow_copy (Object value)
>     {
>         if (value is null)
>             return null;
>
>         void *copy = _d_newclass (value.classinfo);
>         size_t size = value.classinfo.init.length;
>
>         copy [8 .. size] = (cast (void *) value) [8 .. size];
>         return cast (Object) copy;
>     }
>
> Better to start at that offset to avoid copying the synchronisation handle over, plus it's pointless work.

It's too bad it depends on a compiler-specific function (_d_newclass) and doesn't allow classes to say they don't want to be shallow_copied because they have a custom allocator or constructor behavior. Something slightly less risky would be something like

/** Clobbers an object with the contents of another object of the same
 *  class. Clobbering an arbitrary object is very risky so only use the
 *  function inside of a dup() method in a class after creating the
 *  target duplicate. For example,
 *     class Foo {
 *       int test;
 *       int some_other_state;
 *       this(int t) { test = t; }
 *       Foo dup() {
 *         Foo res = new Foo(test);
 *         clobber(res, this);
 *         return res;
 *       }
 *     }
 *     ...
 *     Foo x = new Foo(10);
 *     ...
 *     Foo y = x.dup;
 */
void clobber(Object dest, Object source) {
  ClassInfo ci = source.classinfo;
  if (ci !is dest.classinfo)
    throw new Exception("Cannot clobber subclasses or superclasses");
  void* s = source;
  void* d = dest;
  size_t start = Object.classinfo.init.length;
  d[start .. ci.init.length] = s[start .. ci.init.length];
}


August 21, 2005
On Sat, 20 Aug 2005 19:21:17 -0400, "Ben Hinkle" <ben.hinkle@gmail.com> wrote:

>
>"Burton Radons" <burton-radons@smocky.com> wrote in message news:de838k$1ouu$1@digitaldaemon.com...
>> Haha, why'd I put that in a template?  It just hides the cast.  That should be:
>>
>>     private extern (C) Object _d_newclass (ClassInfo info);
>>
>>     Object shallow_copy (Object value)
>>     {
>>         if (value is null)
>>             return null;
>>
>>         void *copy = _d_newclass (value.classinfo);
>>         size_t size = value.classinfo.init.length;
>>
>>         copy [8 .. size] = (cast (void *) value) [8 .. size];
>>         return cast (Object) copy;
>>     }
>>
>> Better to start at that offset to avoid copying the synchronisation handle over, plus it's pointless work.
>
>It's too bad it depends on a compiler-specific function (_d_newclass) and doesn't allow classes to say they don't want to be shallow_copied because they have a custom allocator or constructor behavior. Something slightly less risky would be something like
>
>/** Clobbers an object with the contents of another object of the same
> *  class. Clobbering an arbitrary object is very risky so only use the
> *  function inside of a dup() method in a class after creating the
> *  target duplicate. For example,
> *     class Foo {
> *       int test;
> *       int some_other_state;
> *       this(int t) { test = t; }
> *       Foo dup() {
> *         Foo res = new Foo(test);
> *         clobber(res, this);
> *         return res;
> *       }
> *     }
> *     ...
> *     Foo x = new Foo(10);
> *     ...
> *     Foo y = x.dup;
> */
>void clobber(Object dest, Object source) {
>  ClassInfo ci = source.classinfo;
>  if (ci !is dest.classinfo)
>    throw new Exception("Cannot clobber subclasses or superclasses");
>  void* s = source;
>  void* d = dest;
>  size_t start = Object.classinfo.init.length;
>  d[start .. ci.init.length] = s[start .. ci.init.length];
>}


Doesn't bar.dup() fail for a subclass Bar of Foo? Unless I reimplement
it, of course.

-Chuck
August 21, 2005
On Sat, 20 Aug 2005 13:19:41 -0700, Burton Radons <burton-radons@smocky.com> wrote:

>Haha, why'd I put that in a template?  It just hides the cast.  That should be:
>
>     private extern (C) Object _d_newclass (ClassInfo info);
>
>     Object shallow_copy (Object value)
>     {
>         if (value is null)
>             return null;
>
>         void *copy = _d_newclass (value.classinfo);
>         size_t size = value.classinfo.init.length;
>
>         copy [8 .. size] = (cast (void *) value) [8 .. size];
>         return cast (Object) copy;
>     }
>
>Better to start at that offset to avoid copying the synchronisation handle over, plus it's pointless work.

Thanks, Burton. That's pretty neat. I had figured out the "value.classinfo.init.length", but not the _d_newclass.

As Ben points out, it won't work with custom allocators, but since I'm using any in my own classes, that's fine.

-Chuck
August 21, 2005
"Chuck Esterbrook" <Chuck.Esterbrook@gmail.antispam.com> wrote in message news:3eifg1h5rbi03ql7etpur7i8645kumptet@4ax.com...
> On Sat, 20 Aug 2005 19:21:17 -0400, "Ben Hinkle" <ben.hinkle@gmail.com> wrote:
>
>>
>>"Burton Radons" <burton-radons@smocky.com> wrote in message news:de838k$1ouu$1@digitaldaemon.com...
>>> Haha, why'd I put that in a template?  It just hides the cast.  That should be:
>>>
>>>     private extern (C) Object _d_newclass (ClassInfo info);
>>>
>>>     Object shallow_copy (Object value)
>>>     {
>>>         if (value is null)
>>>             return null;
>>>
>>>         void *copy = _d_newclass (value.classinfo);
>>>         size_t size = value.classinfo.init.length;
>>>
>>>         copy [8 .. size] = (cast (void *) value) [8 .. size];
>>>         return cast (Object) copy;
>>>     }
>>>
>>> Better to start at that offset to avoid copying the synchronisation
>>> handle
>>> over, plus it's pointless work.
>>
>>It's too bad it depends on a compiler-specific function (_d_newclass) and doesn't allow classes to say they don't want to be shallow_copied because they have a custom allocator or constructor behavior. Something slightly less risky would be something like
>>
>>/** Clobbers an object with the contents of another object of the same
>> *  class. Clobbering an arbitrary object is very risky so only use the
>> *  function inside of a dup() method in a class after creating the
>> *  target duplicate. For example,
>> *     class Foo {
>> *       int test;
>> *       int some_other_state;
>> *       this(int t) { test = t; }
>> *       Foo dup() {
>> *         Foo res = new Foo(test);
>> *         clobber(res, this);
>> *         return res;
>> *       }
>> *     }
>> *     ...
>> *     Foo x = new Foo(10);
>> *     ...
>> *     Foo y = x.dup;
>> */
>>void clobber(Object dest, Object source) {
>>  ClassInfo ci = source.classinfo;
>>  if (ci !is dest.classinfo)
>>    throw new Exception("Cannot clobber subclasses or superclasses");
>>  void* s = source;
>>  void* d = dest;
>>  size_t start = Object.classinfo.init.length;
>>  d[start .. ci.init.length] = s[start .. ci.init.length];
>>}
>
>
> Doesn't bar.dup() fail for a subclass Bar of Foo? Unless I reimplement
> it, of course.
>
> -Chuck

Yeah. That's on purpose - I'd like subclasses to always say how they dup
just like they say how they are constructed. One can call _d_newclass and
clobber that if you want to let subclasses inherit dup "silently". For
classes that can be subclassed I'd probably go with using clobber in a copy
constructor instead of inside dup, actually:
  class Foo {
    this(Foo obj) {
      clobber(this,obj);
    }
  ...
  }
Then there's no confusion about dup having to be overriden by the subclass.


1 2
Next ›   Last »