We've recently added universal construction so that stuff like new int(5) works. However, one thing that still doesn't work is copying structs on the stack to structs on the heap when allocating them. I think that this code should compile
struct Foo
{
int i;
}
void main()
{
auto f = Foo(5);
auto g = new Foo(f);
}
The compiler knows how to copy Foo, so it should be trivial for it to copy an existing Foo onto the a newly allocated Foo on the heap, and it would avoid forcing you to write code like
struct Foo
{
int i;
this(int j)
{
i = j;
}
this(Foo rhs)
{
this = rhs;
}
}
in order to get
void main()
{
auto f = Foo(5);
auto g = new Foo(f);
}
to work or from forcing you to write code like
void main()
{
auto f = Foo(5);
auto g = new Foo;
*g = f;
}
Comment #1 by bearophile_hugs — 2014-06-14T09:34:25Z
(In reply to Jonathan M Davis from comment #0)
> I think that this code should compile
>
> struct Foo
> {
> int i;
> }
>
> void main()
> {
> auto f = Foo(5);
> auto g = new Foo(f);
> }
Implicit functionality cause problems, so you need something significant to justify its presence. What are some use cases of code like that?
Comment #2 by issues.dlang — 2014-06-14T09:47:16Z
> Implicit functionality cause problems, so you need something significant to justify its presence. What are some use cases of code like that?
It's inconsistent that it doesn't work. Copying on the stack works just fine already, why shouldn't it just work for you to be able to construct an object on the heap which is a copy of one on the stack? And this code works right now
void main()
{
int i = 5;
auto j = new int(i);
}
It just doesn't work with structs for some reason. As it stands, you're forced to either do something like
auto g = new Foo;
*g = f;
which is overly verbose and doesn't work with const or immutable, or you're forced to create an extra constructor that basically does what a postblit already does except that it's for the heap. So, this affects all code that wants to create a copy of a struct on the heap.
Also, I don't see how the requested behavior could cause any problems. The only code which would be affected is code that already defines a constructor which takes a variable of the same type, and that could continue to work as it does now. Code that doesn't do that could then start taking advantage of the new behavior it wanted to, but all this is doing is the exact same thing that a postlblit constructor does except on the heap, and postblit constructors are already implicitly defined if you don't defined them. And I would fully expect that this feature would use the postblit constructor. It's just that it would then be copying to the heap rather than the stack.
Comment #3 by mkline.on.d — 2014-06-15T21:25:14Z
(In reply to bearophile_hugs from comment #1)
> What are some use cases of code like that?
Say struct Foo has a member Bar* b, which can either contain some optional data or be null to indicate that no such data is currently present.
From some other data structure, you procure an instance of Bar (call it other) which you would like to assign to b. However, to make the lifetime of b independent of its source, you want to create a garbage-collected copy of other and assign it to b.
Comment #4 by astrothayne — 2016-07-23T18:47:04Z
A workaround for this is to allocate a Foo then assign it to the struct.
struct Foo
{
int i;
}
void main()
{
auto f = Foo(5);
auto g = new Foo;
*g = f;
}
However, if the Foo struct has the default constructor disabled (@disable this();) then this doesn't work, even if postblit isn't disabled. The only way I can think of to get this to work in general would be something like this:
auto f= Foo(5);
auto g = cast(Foo*) (new ubyte[Foo.sizeof]).ptr;
*g = f;
which is pretty awkward.
Comment #5 by robert.schadek — 2024-12-13T18:21:29Z