Re: Stop writeln from calling object destructor

2022-10-04 Thread data pulverizer via Digitalmars-d-learn
On Monday, 3 October 2022 at 11:08:00 UTC, Steven Schveighoffer 
wrote:

On 10/2/22 12:21 PM, data pulverizer wrote:
I've noticed that `writeln` calls the destructor of a struct 
multiple times and would like to know how to stop this from 
happening. It has become a very serious problem when working 
with objects that have memory management external to D.


I know you already solved the problem, but just for future 
reference, if you use something like `RefCounted`, you can 
avoid copying and destruction until everyone is done with the 
object. This is how my io library works, the IO objects are 
non-copyable, and you wrap them in `RefCounted` if you want to 
copy them.


-Steve


Just seen this. Nice one. The docs link: 
https://dlang.org/library/std/typecons/ref_counted.html


Re: Stop writeln from calling object destructor

2022-10-03 Thread Steven Schveighoffer via Digitalmars-d-learn

On 10/2/22 12:21 PM, data pulverizer wrote:
I've noticed that `writeln` calls the destructor of a struct multiple 
times and would like to know how to stop this from happening. It has 
become a very serious problem when working with objects that have memory 
management external to D.


I know you already solved the problem, but just for future reference, if 
you use something like `RefCounted`, you can avoid copying and 
destruction until everyone is done with the object. This is how my io 
library works, the IO objects are non-copyable, and you wrap them in 
`RefCounted` if you want to copy them.


-Steve


Re: Stop writeln from calling object destructor

2022-10-02 Thread Paul Backus via Digitalmars-d-learn

On Sunday, 2 October 2022 at 18:24:51 UTC, Ali Çehreli wrote:

On 10/2/22 10:55, data pulverizer wrote:
> ```
> this(T)(ref return scope T original)
> if(is(T == RVector!(Type)))
> {
>  //... code ...
> }
> ```

I've just tested. That is used only for explicit constructor 
syntax:


auto b = RVector!int(a);// templatized

>
>
> But this now works:
>
>
> ```
> this(ref return scope RVector!(Type) original)
> {
>  //... code ...
> }
> ```

That one works for both syntaxes:

auto b = RVector!int(a);// templatized
auto c = a; // non-templatized

Certainly confusing and potentially a bug... :/


It's a bug in the documentation.

https://issues.dlang.org/show_bug.cgi?id=23382
https://github.com/dlang/dlang.org/pull/3427


Re: Stop writeln from calling object destructor

2022-10-02 Thread data pulverizer via Digitalmars-d-learn

On Sunday, 2 October 2022 at 18:24:51 UTC, Ali Çehreli wrote:
I've just tested. That is used only for explicit constructor 
syntax ...


Many thanks. Knowledgeable as always!



Re: Stop writeln from calling object destructor

2022-10-02 Thread Ali Çehreli via Digitalmars-d-learn

On 10/2/22 10:55, data pulverizer wrote:
> On Sunday, 2 October 2022 at 17:28:51 UTC, data pulverizer wrote:
>> Sorry I'll need to implement all the overloaded copy constructors and
>> see if that fixes it.
>
> I've got it, something weird happened to my copy constructor. This was
> my original attempt and was ignored (didn't run in the copy constructor):
>
> ```
> this(T)(ref return scope T original)
> if(is(T == RVector!(Type)))
> {
>  //... code ...
> }
> ```

I've just tested. That is used only for explicit constructor syntax:

auto b = RVector!int(a);// templatized

>
>
> But this now works:
>
>
> ```
> this(ref return scope RVector!(Type) original)
> {
>  //... code ...
> }
> ```

That one works for both syntaxes:

auto b = RVector!int(a);// templatized
auto c = a; // non-templatized

Certainly confusing and potentially a bug... :/

> No idea why. `Type` is a template parameter of the object.

Minor convenience: You can replace all RVector!(Type) with just RVector 
in the implementation of RVector because the name of the struct template 
*is* that specific instantiation of it:


struct RVector(Type) {
// RVector below means RVector!Type:
this(ref return scope RVector original)
{
// ...
}
}

Ali




Re: Stop writeln from calling object destructor

2022-10-02 Thread data pulverizer via Digitalmars-d-learn

On Sunday, 2 October 2022 at 17:51:59 UTC, Ali Çehreli wrote:
What I noticed first in your original code was that it would be 
considered buggy because it was not considering copying. Every 
struct that does something in its destructor should either have 
post-blit (or copy constructor) defined or simpler, disallow 
copying altogether.


Thanks for the advice, for a while now I didn't know what was 
creating the issue.


The code I'm running is my D connector to the R API and for ages 
I didn't know where the multiple destructor calls to allow an 
object to be garbage collected by the R API was coming from, and 
it was breaking the whole thing.


I think I'll have to play it by ear whether to disable the copy 
constructor altogether or to use it now it is working.


Thanks both of you.



Re: Stop writeln from calling object destructor

2022-10-02 Thread data pulverizer via Digitalmars-d-learn

On Sunday, 2 October 2022 at 17:28:51 UTC, data pulverizer wrote:
Sorry I'll need to implement all the overloaded copy 
constructors and see if that fixes it.


I've got it, something weird happened to my copy constructor. 
This was my original attempt and was ignored (didn't run in the 
copy constructor):


```
this(T)(ref return scope T original)
if(is(T == RVector!(Type)))
{
//... code ...
}
```


But this now works:


```
this(ref return scope RVector!(Type) original)
{
//... code ...
}
```

No idea why. `Type` is a template parameter of the object.


Re: Stop writeln from calling object destructor

2022-10-02 Thread Ali Çehreli via Digitalmars-d-learn

On 10/2/22 10:28, data pulverizer wrote:
> On Sunday, 2 October 2022 at 17:19:55 UTC, data pulverizer wrote:
>> Any reason why this could be?
>

What I noticed first in your original code was that it would be 
considered buggy because it was not considering copying. Every struct 
that does something in its destructor should either have post-blit (or 
copy constructor) defined or simpler, disallow copying altogether.


That's what I did here:

  https://github.com/acehreli/alid/blob/main/cached/alid/cached.d#L178

@disable this(this);

I think disabling copy constructor was unnecessary but I did that as well:

@disable this(ref const(typeof(this)));

The issue remains and bothers me as well. I think writeln copies objects 
because D disallows references to rvalue. We couldn't print rvalues if 
writeln insisted on 'ref'. Or, rvalues would be copied anyway if we used 
'auto ref'. Hence the status quo...


> Sorry I'll need to implement all the overloaded copy constructors and
> see if that fixes it.

The best solution I know is to disable copying and printing not the 
object but an explicit string representation of it:


Added:

@disable this(this);

Added (there are better ways of doing the same e.g. using a 'sink' 
parameter):


string toString() const {
import std.format : format;
return format!"id: %s"(id);
}

Called toString:

writeln("MyObject: ", obj.toString);

Ali




Re: Stop writeln from calling object destructor

2022-10-02 Thread data pulverizer via Digitalmars-d-learn

On Sunday, 2 October 2022 at 17:19:55 UTC, data pulverizer wrote:

Any reason why this could be?


Sorry I'll need to implement all the overloaded copy constructors 
and see if that fixes it.


Re: Stop writeln from calling object destructor

2022-10-02 Thread data pulverizer via Digitalmars-d-learn

On Sunday, 2 October 2022 at 16:44:25 UTC, Paul Backus wrote:
It's because `writeln` is copying the object, and each of the 
copies is being destroyed. If you add a copy constructor to 
your example, you can see it happening:

...


I thought something like this could be happening in my original 
implementation and tried implementing a copy constructor using 
this reference 
https://dlang.org/spec/struct.html#struct-copy-constructor but it 
did not work. Both your's and the manual's suggestion works for 
my baby example but not for my actual code.


Any reason why this could be?



Re: Stop writeln from calling object destructor

2022-10-02 Thread Paul Backus via Digitalmars-d-learn

On Sunday, 2 October 2022 at 16:21:47 UTC, data pulverizer wrote:
I've noticed that `writeln` calls the destructor of a struct 
multiple times and would like to know how to stop this from 
happening.


It's because `writeln` is copying the object, and each of the 
copies is being destroyed. If you add a copy constructor to your 
example, you can see it happening:


```d
import std.stdio: writeln;

struct MyObject
{
int id;
this(int id) @nogc
{
this.id = id;
}
this(inout ref MyObject) inout
{
writeln("Object copy constructor...");
}
~this()
{
writeln("Object destructor ...");
}
}



void main()
{
auto obj = MyObject(42);
writeln(obj);
writeln("Goodbye:\n");
}
```

Output:

```d
Object copy constructor...
Object copy constructor...
Object copy constructor...
Object copy constructor...
MyObject(0)Object destructor ...
Object destructor ...

Object destructor ...
Object destructor ...
Goodbye:

Object destructor ...
```


Stop writeln from calling object destructor

2022-10-02 Thread data pulverizer via Digitalmars-d-learn
I've noticed that `writeln` calls the destructor of a struct 
multiple times and would like to know how to stop this from 
happening. It has become a very serious problem when working with 
objects that have memory management external to D.


Here is a repeatable example, where the destructor appears to 
have been called 4 times with one call of `writeln` before the 
object actually goes out of scope:



Code:
```
import std.stdio: writeln;

struct MyObject
{
int id;
this(int id) @nogc
{
this.id = id;
}
~this()
{
writeln("Object destructor ...");
}
}



void main()
{
auto obj = MyObject(42);
writeln("MyObject: ", obj);
writeln("Goodbye:\n");
}

```

Output:
```
$ rdmd gc.d
MyObject: MyObject(42)Object destructor ...
Object destructor ...

Object destructor ...
Object destructor ...
Goodbye:

Object destructor ...
```

Thank you