Thread overview
Passing struct to function
Jun 13, 2018
Michał
Jun 13, 2018
Michał
Jun 14, 2018
Michał
June 13, 2018
When I pass my struct to function something is going wrong. I don't know how to fix it.

Code:
import std.stdio;


void print(ref Vector v, string s){
		writefln("%s==%s    %s", &v.x, v.ptr, s);
}

struct Vector {
	int x;
	int* ptr;

	this(this) {
		ptr = &x;
		print(this, "postblit");
	}
}

void someFunc(Vector t) {
	print(t, "in someFunc");
}

void main() {
	auto tmpA = Vector();
	tmpA.ptr = &tmpA.x;
	print(tmpA, "start");

	someFunc(tmpA);
}


Result on my machine:
7FFF7D70BC00==7FFF7D70BC00    start
7FFF7D70BBF0==7FFF7D70BBF0    postblit
7FFF7D70BBD0==7FFF7D70BBF0    in someFunc

In the last line pointers are not matching. I thought that postblit will do the thing but it is not the case. How to make 'ptr' to be null or '&this.x' all the time?
June 13, 2018
On 6/13/18 10:43 AM, Michał wrote:
> When I pass my struct to function something is going wrong. I don't know how to fix it.
> 
> Code:
> import std.stdio;
> 
> 
> void print(ref Vector v, string s){
>          writefln("%s==%s    %s", &v.x, v.ptr, s);
> }
> 
> struct Vector {
>      int x;
>      int* ptr;
> 
>      this(this) {
>          ptr = &x;
>          print(this, "postblit");
>      }
> }
> 
> void someFunc(Vector t) {
>      print(t, "in someFunc");
> }
> 
> void main() {
>      auto tmpA = Vector();
>      tmpA.ptr = &tmpA.x;
>      print(tmpA, "start");
> 
>      someFunc(tmpA);
> }
> 
> 
> Result on my machine:
> 7FFF7D70BC00==7FFF7D70BC00    start
> 7FFF7D70BBF0==7FFF7D70BBF0    postblit
> 7FFF7D70BBD0==7FFF7D70BBF0    in someFunc
> 
> In the last line pointers are not matching. I thought that postblit will do the thing but it is not the case. How to make 'ptr' to be null or '&this.x' all the time?

D allows moving any struct instance without calling postblit, as long as the original is no longer used.

The optimizer is likely seeing here that the memory can be copied without calling postblit, because nobody is using tmpA after the call.

In general, you should NOT store an internal pointer in a struct, unless you allocate it on the heap.

-Steve
June 13, 2018
On Wednesday, 13 June 2018 at 16:40:51 UTC, Steven Schveighoffer wrote:
> On 6/13/18 10:43 AM, Michał wrote:
>> When I pass my struct to function something is going wrong. I don't know how to fix it.
>> 
>> Code:
>> import std.stdio;
>> 
>> 
>> void print(ref Vector v, string s){
>>          writefln("%s==%s    %s", &v.x, v.ptr, s);
>> }
>> 
>> struct Vector {
>>      int x;
>>      int* ptr;
>> 
>>      this(this) {
>>          ptr = &x;
>>          print(this, "postblit");
>>      }
>> }
>> 
>> void someFunc(Vector t) {
>>      print(t, "in someFunc");
>> }
>> 
>> void main() {
>>      auto tmpA = Vector();
>>      tmpA.ptr = &tmpA.x;
>>      print(tmpA, "start");
>> 
>>      someFunc(tmpA);
>> }
>> 
>> 
>> Result on my machine:
>> 7FFF7D70BC00==7FFF7D70BC00    start
>> 7FFF7D70BBF0==7FFF7D70BBF0    postblit
>> 7FFF7D70BBD0==7FFF7D70BBF0    in someFunc
>> 
>> In the last line pointers are not matching. I thought that postblit will do the thing but it is not the case. How to make 'ptr' to be null or '&this.x' all the time?
>
> D allows moving any struct instance without calling postblit, as long as the original is no longer used.
>
> The optimizer is likely seeing here that the memory can be copied without calling postblit, because nobody is using tmpA after the call.
>
> In general, you should NOT store an internal pointer in a struct, unless you allocate it on the heap.
>
> -Steve


I need internal pointer because I want to implement vector(like in C++) with 'small vector optimization', when i have internal pointer it is very easy and functions like 'add' don't have additional checks.

If storing internal pointers is forbidden do you know some way to implement 'small vector optimization' without additional checks in 'add' function?
June 13, 2018
On 6/13/18 1:08 PM, Michał wrote:
> On Wednesday, 13 June 2018 at 16:40:51 UTC, Steven Schveighoffer wrote:
>> On 6/13/18 10:43 AM, Michał wrote:
>>> When I pass my struct to function something is going wrong. I don't know how to fix it.
>>>
>>> Code:
>>> import std.stdio;
>>>
>>>
>>> void print(ref Vector v, string s){
>>>          writefln("%s==%s    %s", &v.x, v.ptr, s);
>>> }
>>>
>>> struct Vector {
>>>      int x;
>>>      int* ptr;
>>>
>>>      this(this) {
>>>          ptr = &x;
>>>          print(this, "postblit");
>>>      }
>>> }
>>>
>>> void someFunc(Vector t) {
>>>      print(t, "in someFunc");
>>> }
>>>
>>> void main() {
>>>      auto tmpA = Vector();
>>>      tmpA.ptr = &tmpA.x;
>>>      print(tmpA, "start");
>>>
>>>      someFunc(tmpA);
>>> }
>>>
>>>
>>> Result on my machine:
>>> 7FFF7D70BC00==7FFF7D70BC00    start
>>> 7FFF7D70BBF0==7FFF7D70BBF0    postblit
>>> 7FFF7D70BBD0==7FFF7D70BBF0    in someFunc
>>>
>>> In the last line pointers are not matching. I thought that postblit will do the thing but it is not the case. How to make 'ptr' to be null or '&this.x' all the time?
>>
>> D allows moving any struct instance without calling postblit, as long as the original is no longer used.
>>
>> The optimizer is likely seeing here that the memory can be copied without calling postblit, because nobody is using tmpA after the call.
>>
>> In general, you should NOT store an internal pointer in a struct, unless you allocate it on the heap.
>>
>> -Steve
> 
> 
> I need internal pointer because I want to implement vector(like in C++) with 'small vector optimization', when i have internal pointer it is very easy and functions like 'add' don't have additional checks.
> 
> If storing internal pointers is forbidden do you know some way to implement 'small vector optimization' without additional checks in 'add' function?

Hm... the only way to do it in D is to provide a function that checks whether the small vector optimization is in play, and return a pointer/slice to itself.

With D it is possible to alias the getter function that provides the actual data to allow code to look nicer.

For example (crude example):

struct Vector(T)
{
   bool svo; // small vector optimization
   union
   {
      T[4] local;
      T[] heap;
   }
   inout(T)[] get() inout { return svo ? local[], heap; }
   alias get this;
   ... // implement specialized append, concat operators, etc.
}

Now, you can use Vector as if it were an array, and it just works.

-Steve
June 14, 2018
On Wednesday, 13 June 2018 at 17:37:44 UTC, Steven Schveighoffer wrote:

> Hm... the only way to do it in D is to provide a function that checks whether the small vector optimization is in play, and return a pointer/slice to itself.
>
> With D it is possible to alias the getter function that provides the actual data to allow code to look nicer.
>
> For example (crude example):
>
> struct Vector(T)
> {
>    bool svo; // small vector optimization
>    union
>    {
>       T[4] local;
>       T[] heap;
>    }
>    inout(T)[] get() inout { return svo ? local[], heap; }
>    alias get this;
>    ... // implement specialized append, concat operators, etc.
> }
>
> Now, you can use Vector as if it were an array, and it just works.
>
> -Steve

Thanks for an idea, I will try it.