Jump to page: 1 2
Thread overview
scoped classes
Apr 27, 2017
Alex
Apr 27, 2017
Stanislav Blinov
Apr 27, 2017
Alex
Apr 27, 2017
Stanislav Blinov
Apr 27, 2017
Alex
Apr 27, 2017
Ali Çehreli
Apr 27, 2017
Stanislav Blinov
Apr 27, 2017
ag0aep6g
Apr 27, 2017
Alex
Apr 27, 2017
Stanislav Blinov
Apr 27, 2017
Alex
April 27, 2017
Hi all,
a short question about an example.
having read this:
https://dlang.org/library/std/typecons/scoped.html

There is a struct B defined in the middle of the example, with a scoped class member.
How to define an array of such members (and to put some items to it)?
So, I want to have something like

// Use as member variable
struct B
{
    typeof(scoped!A())[] a; // note the trailing parentheses

    this(int i)
    {
        // construct member
        a.length = 5; // doesn't work, as the default constructor is disabled.
        a ~= scoped!A(i); // doesn't work, as the type is not copyable
        // ???
    }
}
April 27, 2017
On Thursday, 27 April 2017 at 06:40:49 UTC, Alex wrote:
> Hi all,
> a short question about an example.
> having read this:
> https://dlang.org/library/std/typecons/scoped.html
>
> There is a struct B defined in the middle of the example, with a scoped class member.
> How to define an array of such members (and to put some items to it)?
> So, I want to have something like
>
> // Use as member variable
> struct B
> {
>     typeof(scoped!A())[] a; // note the trailing parentheses
>
>     this(int i)
>     {
>         // construct member
>         a.length = 5; // doesn't work, as the default constructor is disabled.
>         a ~= scoped!A(i); // doesn't work, as the type is not copyable
>         // ???
>     }
> }

The only "possible" way would be like this:

typeof(scoped!A())[] a;
a = [ scoped!A(1), scoped!A(2), scoped!A(3) ];

But even so, you shouldn't do that. scoped isn't designed for it.
April 27, 2017
On Thursday, 27 April 2017 at 15:06:44 UTC, Stanislav Blinov wrote:
>
> The only "possible" way would be like this:
>
> typeof(scoped!A())[] a;
> a = [ scoped!A(1), scoped!A(2), scoped!A(3) ];
>
> But even so, you shouldn't do that. scoped isn't designed for it.

And then, the amount of elements is not known at compile time...

But I think, I can generalize the question little bit:
void main()
{
	S[] arr;
	S s = S(42);
	arr = [s]; // this doesn't work :(
}

struct S
{
	@disable this();
	@disable this(this);
	this(size_t dummy){}
}

Given a struct with an explicit constructor and a postblit. How to make an array of it?

Tried stuff with emplace, move and memmove already, nothing worked, at least in the form I had it...

It is good, that it is hidden so well, as I'm intend to do this action in a constructor only, but I didn't find not a single solution so far...
April 27, 2017
On Thursday, 27 April 2017 at 15:47:38 UTC, Alex wrote:

> struct S
> {
> 	@disable this();
> 	@disable this(this);
> 	this(size_t dummy){}
> }
>
> Given a struct with an explicit constructor and a postblit. How to make an array of it?

You mean with a disabled default ctor and postblit? You can't with built-in arrays. They expect that elements can be default-constructed and copied. Even std.container.Array in its current implementation won't help you there.
The only way to get around that is to devise your own array type that carefully deals with uninitialized storage and uses emplace/move/moveEmplace to store elements.

April 27, 2017
On Thursday, 27 April 2017 at 16:39:38 UTC, Stanislav Blinov wrote:
> On Thursday, 27 April 2017 at 15:47:38 UTC, Alex wrote:
>
>> struct S
>> {
>> 	@disable this();
>> 	@disable this(this);
>> 	this(size_t dummy){}
>> }
>>
>> Given a struct with an explicit constructor and a postblit. How to make an array of it?
>
> You mean with a disabled default ctor and postblit? You can't with built-in arrays. They expect that elements can be default-constructed and copied. Even std.container.Array in its current implementation won't help you there.
> The only way to get around that is to devise your own array type that carefully deals with uninitialized storage and uses emplace/move/moveEmplace to store elements.

Hm... ok. This is a acceptable answer. So, if such structs exist, it is forced to use pointers on their instances as an indirection... apart from using some reference type things surrounding them...
Thanks for helping with perception :)
April 27, 2017
I haven't used it yet but it's worth noting that there is EMSI's container library as well:

  http://code.dlang.org/packages/emsi_containers

Ali

April 27, 2017
On Thursday, 27 April 2017 at 17:07:05 UTC, Ali Çehreli wrote:
> I haven't used it yet but it's worth noting that there is EMSI's container library as well:
>
>   http://code.dlang.org/packages/emsi_containers

A brief glance at the source of dynamicarray there suggests that it won't help with non-copyables either.
April 27, 2017
On 04/27/2017 05:47 PM, Alex wrote:
> void main()
> {
>     S[] arr;
>     S s = S(42);
>     arr = [s]; // this doesn't work :(
> }
>
> struct S
> {
>     @disable this();
>     @disable this(this);
>     this(size_t dummy){}
> }

1) Construct the S instance directly in the array literal:

----
arr = [S(42]);
----

But I guess that's besides the point. So ...

2) Use std.algorithm.mutation.move [1]:

----
import std.algorithm.mutation: move;
S s = S(42);
arr = [move(s)];
----

`move` makes a "destructive copy" here; i.e, it resets `s` to `S.init`.

You probably want to append to that array at some point. That's going to be more tricky, because appending potentially involves copying the whole array.

This might work:

----
import std.algorithm.mutation: moveEmplace;
import std.array: uninitializedArray;

/* Make a new, larger array: */
S[] new_arr = uninitializedArray!(S[])(arr.length + 1);

/* Copy existing elements; destroy old array: */
foreach (size_t i; 0 .. arr.length) moveEmplace(arr[i], new_arr[i]);

/* Copy new element; destroy s: */
moveEmplace(s, new_arr[$ - 1]);

/* Replace old array with new one: */
arr = new_arr;
----

Notes:

* `moveEmplace` and `uninitializedArray` are completely unsafe. You must ensure safety yourself.

* I'm not entirely sure that the code is completely correct. It might be invalid and break some language rule.

* I'm pretty sure that the code is going to be invalid when you're dealing with const/immutable data.

* The code destroys the old array. References to it (slices of it, pointers into it) will show .init values.

* Maybe one can make use of `.capacity` somehow. As it is, the code makes a copy of the whole array every time.

* If this "moveAppend" functionality can be done in a valid manner, it might be a worthwhile addition to the "move" function family.



[1] http://dlang.org/phobos/std_algorithm_mutation.html#.move
April 27, 2017
On Thursday, 27 April 2017 at 17:39:42 UTC, ag0aep6g wrote:
> On 04/27/2017 05:47 PM, Alex wrote:
>> void main()
>> {
>>     S[] arr;
>>     S s = S(42);
>>     arr = [s]; // this doesn't work :(
>> }
>>
>> struct S
>> {
>>     @disable this();
>>     @disable this(this);
>>     this(size_t dummy){}
>> }
>
> 1) Construct the S instance directly in the array literal:
>
> ----
> arr = [S(42]);
> ----
>
> But I guess that's besides the point. So ...
>
> 2) Use std.algorithm.mutation.move [1]:
>
> ----
> import std.algorithm.mutation: move;
> S s = S(42);
> arr = [move(s)];
> ----
>
> `move` makes a "destructive copy" here; i.e, it resets `s` to `S.init`.
>
> You probably want to append to that array at some point. That's going to be more tricky, because appending potentially involves copying the whole array.
>
> This might work:
>
> ----
> import std.algorithm.mutation: moveEmplace;
> import std.array: uninitializedArray;
>
> /* Make a new, larger array: */
> S[] new_arr = uninitializedArray!(S[])(arr.length + 1);
>
> /* Copy existing elements; destroy old array: */
> foreach (size_t i; 0 .. arr.length) moveEmplace(arr[i], new_arr[i]);
>
> /* Copy new element; destroy s: */
> moveEmplace(s, new_arr[$ - 1]);
>
> /* Replace old array with new one: */
> arr = new_arr;
> ----
>

Cool! Works like a charm :)

> Notes:
>
> * `moveEmplace` and `uninitializedArray` are completely unsafe. You must ensure safety yourself.
Yes, I'm aware of this...

>
> * I'm not entirely sure that the code is completely correct. It might be invalid and break some language rule.
:-) I'm not sure about what is worse: to be forced to use pointers or to use black magic practices at preparation step only. So... Now, I have at least a choice...

>
> * I'm pretty sure that the code is going to be invalid when you're dealing with const/immutable data.
Ok... this is important... I tried this out, and the value of the immutable data even remains the same. But for safety reasons, I would reconstruct the structs inside the array anyway, so I can live with this, I think...

>
> * The code destroys the old array. References to it (slices of it, pointers into it) will show .init values.
That's ok... at creation time, there won't be any references yet...

>
> * Maybe one can make use of `.capacity` somehow. As it is, the code makes a copy of the whole array every time.
Tried this out for some values, capacity of the new array is always 0.

>
> * If this "moveAppend" functionality can be done in a valid manner, it might be a worthwhile addition to the "move" function family.
:-)

Thanks a lot!
>
>
>
> [1] http://dlang.org/phobos/std_algorithm_mutation.html#.move

April 27, 2017
On Thursday, 27 April 2017 at 18:36:08 UTC, Alex wrote:

>> * I'm pretty sure that the code is going to be invalid when you're dealing with const/immutable data.
> Ok... this is important... I tried this out, and the value of the immutable data even remains the same. But for safety reasons, I would reconstruct the structs inside the array anyway, so I can live with this, I think...

move() is only destructive if the type has custom postblit or destructor, otherwise it's just a bitwise copy. But, as mentioned, there's an issue with it at the moment: it doesn't really care if the type being moved has const/immutable members.

uninitializedArray is scary. If you do use it, probably best to localize the usage as much as possible and be very very VERY careful with it ;)

Here's a sketch of something that's a little bit more convenient: https://dpaste.dzfl.pl/ee472fd872a5
But I'm not going to pretend it'd survive a review.

Also note that, going back to your original question, docs for scoped state that it's illegal to move it, so that particular type you can't really store in any of these arrays.
« First   ‹ Prev
1 2