Re: Anyway to achieve the following

2021-08-17 Thread Rekel via Digitalmars-d-learn
On Saturday, 14 August 2021 at 20:50:47 UTC, Carl Sturtivant 
wrote:

```
struct S {
  int x = 1234;
}

void main() {
  import std.stdio;
   S s;
   //construction of a using &(s.x)
   auto a = Ref!(int)();
   writeln(a); //displays 1234
   s.x += 1;
   writeln(a); //displays 1235
   a += 1;
   writeln(s.x); //displays 1236
}

struct Ref(T) {
  T* ptr;
  this(T* p) { ptr = p; }
  string toString() { import std.conv; return to!string(*ptr); }
  ref T var() { return *ptr; }
  alias var this;
}
```


Wow you can alias this a function? TIL!


Re: Anyway to achieve the following

2021-08-17 Thread Johan via Digitalmars-d-learn

On Monday, 16 August 2021 at 19:30:19 UTC, JG wrote:
On Sunday, 15 August 2021 at 21:53:14 UTC, Carl Sturtivant 
wrote:

On Sunday, 15 August 2021 at 07:10:17 UTC, JG wrote:

[...]


What you are asking for are reference variables. C++ has them: 
the example here illustrates the behavior you want.

https://www.geeksforgeeks.org/references-in-c/

[...]


Thanks for the links and code. Looking at the assembly as 
suggested by others it seems that after optimization this not 
too bad.


The problem is not optimization. The semantics of the code are 
different when you use the `Ref!int` solution versus simply 
`int`. You'll see this in template instantiations, as in the 
`writeln` example.


`writeln` is a template and `writeln!int` is something different 
from `writeln!(Ref!int)`. When you force the template 
instantiation to `writeln!int` -- e.g. with an explicit cast, 
https://d.godbolt.org/z/6fKbMh731 -- the `Ref!int` output is the 
same as with `int`.


Regardless, I haven't seen a performance measurement, and it is 
most likely completely irrelevant for the performance of your 
program.


-Johan





Re: Anyway to achieve the following

2021-08-16 Thread JG via Digitalmars-d-learn

On Sunday, 15 August 2021 at 21:53:14 UTC, Carl Sturtivant wrote:

On Sunday, 15 August 2021 at 07:10:17 UTC, JG wrote:

[...]


What you are asking for are reference variables. C++ has them: 
the example here illustrates the behavior you want.

https://www.geeksforgeeks.org/references-in-c/

[...]


Thanks for the links and code. Looking at the assembly as 
suggested by others it seems that after optimization this not too 
bad.


Re: Anyway to achieve the following

2021-08-15 Thread Carl Sturtivant via Digitalmars-d-learn

On Sunday, 15 August 2021 at 07:10:17 UTC, JG wrote:

Hi,

This is exactly the behaviour I was trying to obtain.

It however comes with a fair amount of overhead, as can be seen 
in the following llvm ir:


[...]


What you are asking for are reference variables. C++ has them: 
the example here illustrates the behavior you want.

https://www.geeksforgeeks.org/references-in-c/

D does not have them, as mentioned above:
https://forum.dlang.org/post/mailman.2714.1628875187.3446.digitalmars-d-le...@puremagic.com

So to get the behavior you want, they have to be simulated, which 
is what this does:

https://forum.dlang.org/post/lcrrnszslpyazoziy...@forum.dlang.org

Next version: no `toString` and storage passed in by reference 
rather than by pointer.


```
struct S {
  int x = 1234;
}

void main() {
  import std.stdio;
   S s;
   auto p = 
   //construction of a using &(s.x)
   auto a = Ref!(int)(*p);
   //auto a = Ref!(int)(s.x);
   writeln(a); //displays 1234
   s.x += 1;
   writeln(a); //displays 1235
   a += 1;
   writeln(s.x); //displays 1236
}

struct Ref(T)
{
  T* ptr;
  this(ref T x) { ptr =  }
  @property ref T var() { return *ptr; }
  alias var this;
}
```

I see no way to avoid overhead, as I see no simpler simulation.



Re: Anyway to achieve the following

2021-08-15 Thread Johan via Digitalmars-d-learn

On Sunday, 15 August 2021 at 16:49:22 UTC, Paul Backus wrote:

On Sunday, 15 August 2021 at 07:10:17 UTC, JG wrote:


Hi,

This is exactly the behaviour I was trying to obtain.

It however comes with a fair amount of overhead, as can be 
seen in the following llvm ir:


[...]


I'm not really familiar with llvm ir, but looking at it on 
godbolt, it seems like the main difference is that taking the 
address of `s.x` forces the compiler to place `s` in memory, 
rather than keeping it entirely in registers:


https://d.godbolt.org/z/1afbsM6fv


The function `std.stdio.writeln!(example.Ref!(int))` is not 
trivial. I doubt there is a reasonable 
optimization/transformation path from a call to 
`std.stdio.writeln!(example.Ref!(int))` to a call to 
`std.stdio.writeln!(int).writeln(int)`.
Without being able to simplify it to that call, `s` has to be put 
in memory. It's the opaqueness of 
`std.stdio.writeln!(example.Ref!(int))` and that it (must) takes 
the address of `s.x` as parameter.


-Johan



Re: Anyway to achieve the following

2021-08-15 Thread Paul Backus via Digitalmars-d-learn

On Sunday, 15 August 2021 at 07:10:17 UTC, JG wrote:


Hi,

This is exactly the behaviour I was trying to obtain.

It however comes with a fair amount of overhead, as can be seen 
in the following llvm ir:


[...]


I'm not really familiar with llvm ir, but looking at it on 
godbolt, it seems like the main difference is that taking the 
address of `s.x` forces the compiler to place `s` in memory, 
rather than keeping it entirely in registers:


https://d.godbolt.org/z/1afbsM6fv


Re: Anyway to achieve the following

2021-08-15 Thread JG via Digitalmars-d-learn
On Saturday, 14 August 2021 at 20:50:47 UTC, Carl Sturtivant 
wrote:

```
struct S {
  int x = 1234;
}

void main() {
  import std.stdio;
   S s;
   //construction of a using &(s.x)
   auto a = Ref!(int)();
   writeln(a); //displays 1234
   s.x += 1;
   writeln(a); //displays 1235
   a += 1;
   writeln(s.x); //displays 1236
}

struct Ref(T) {
  T* ptr;
  this(T* p) { ptr = p; }
  string toString() { import std.conv; return to!string(*ptr); }
  ref T var() { return *ptr; }
  alias var this;
}
```


Hi,

This is exactly the behaviour I was trying to obtain.

It however comes with a fair amount of overhead, as can be seen 
in the following llvm ir:


define i32 @_Dmain({ i64, { i64, i8* }* } %unnamed) #0 {
  %s = alloca %onlineapp.S, align 4   ; [#uses = 
4, size/byte = 4]
  %a = alloca %"onlineapp.Ref!int.Ref", align 8   ; [#uses = 
5, size/byte = 8]
  %1 = bitcast %onlineapp.S* %s to i8*; [#uses = 
1]
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %1, i8* 
align 1 bitcast (%onlineapp.S* @onlineapp.S.__init to i8*), i64 
4, i1 false)
  %2 = bitcast %"onlineapp.Ref!int.Ref"* %a to i8* ; [#uses = 
1]
  call void @llvm.memset.p0i8.i64(i8* align 1 %2, i8 0, i64 
8, i1 false)
  %3 = getelementptr inbounds %onlineapp.S, %onlineapp.S* %s, 
i32 0, i32 0 ; [#uses = 1, type = i32*]
  %4 = call %"onlineapp.Ref!int.Ref"* @pure nothrow ref @nogc 
@safe onlineapp.Ref!(int).Ref 
onlineapp.Ref!(int).Ref.__ctor(int*)(%"onlineapp.Ref!int.Ref"* 
nonnull returned %a, i32* %3) #4 ; [#uses = 0]
  %5 = load %"onlineapp.Ref!int.Ref", 
%"onlineapp.Ref!int.Ref"* %a, align 8 ; [#uses = 1]
  call void @@safe void 
std.stdio.writeln!(onlineapp.Ref!(int).Ref).writeln(onlineapp.Ref!(int).Ref)(%"onlineapp.Ref!int.Ref" %5) #4
  %6 = getelementptr inbounds %onlineapp.S, %onlineapp.S* %s, 
i32 0, i32 0 ; [#uses = 2, type = i32*]
  %7 = load i32, i32* %6, align 4 ; [#uses = 
1]
  %8 = add i32 %7, 1  ; [#uses = 
1]

  store i32 %8, i32* %6, align 4
  %9 = load %"onlineapp.Ref!int.Ref", 
%"onlineapp.Ref!int.Ref"* %a, align 8 ; [#uses = 1]
  call void @@safe void 
std.stdio.writeln!(onlineapp.Ref!(int).Ref).writeln(onlineapp.Ref!(int).Ref)(%"onlineapp.Ref!int.Ref" %9) #4
  %10 = call i32* @pure nothrow ref @nogc @safe int 
onlineapp.Ref!(int).Ref.var()(%"onlineapp.Ref!int.Ref"* nonnull 
%a) #4 ; [#uses = 2]
  %11 = load i32, i32* %10, align 4   ; [#uses = 
1]
  %12 = add i32 %11, 1; [#uses = 
1]

  store i32 %12, i32* %10, align 4
  %13 = getelementptr inbounds %onlineapp.S, %onlineapp.S* 
%s, i32 0, i32 0 ; [#uses = 1, type = i32*]
  %14 = load i32, i32* %13, align 4   ; [#uses = 
1]
  call void @@safe void 
std.stdio.writeln!(int).writeln(int)(i32 %14) #4

  ret i32 0
}


Re: Anyway to achieve the following

2021-08-14 Thread Carl Sturtivant via Digitalmars-d-learn

```
struct S {
  int x = 1234;
}

void main() {
  import std.stdio;
   S s;
   //construction of a using &(s.x)
   auto a = Ref!(int)();
   writeln(a); //displays 1234
   s.x += 1;
   writeln(a); //displays 1235
   a += 1;
   writeln(s.x); //displays 1236
}

struct Ref(T) {
  T* ptr;
  this(T* p) { ptr = p; }
  string toString() { import std.conv; return to!string(*ptr); }
  ref T var() { return *ptr; }
  alias var this;
}
```


Re: Anyway to achieve the following

2021-08-13 Thread pilger via Digitalmars-d-learn

On Friday, 13 August 2021 at 19:06:17 UTC, JG wrote:
Anyway I hope it is clearer what I mean. Is it possible to do 
this in d?


union S
{
  int x;
  int a;
}

void main()
{
   S s= S(1234);

   writeln(s.a); //displays 1234
   s.x = s.x+1;
   writeln(s.a); //displays 1235
   s.a = s.a +1;
   writeln(s.a); //displays 1236
}



Re: Anyway to achieve the following

2021-08-13 Thread JG via Digitalmars-d-learn

On Friday, 13 August 2021 at 17:19:43 UTC, H. S. Teoh wrote:
On Fri, Aug 13, 2021 at 05:11:50PM +, Rekel via 
Digitalmars-d-learn wrote: [...]
For anyone more experienced with C, I'm not well known with 
references but are those semantically similar to the idea of 
using a type at a predefined location?


References are essentially pointers under the hood. The 
difference is that at the language level they are treated as 
aliases to the original variable, and are therefore guaranteed 
to be non-null.


Note that in D `ref` is not a type constructor but a storage 
qualifier, so you cannot declare a reference variable, you can 
only get one if you pass a variable to a function that takes it 
by ref.



T


Thanks for all the replies.

I had a look at emplace but it does not seem to do exactly what I 
have in mind.


What I had in mind would have the following behaviour. Suppose we 
optionally
allow "in  before the semi-colon at the end of a 
declaration. With the following semantics


T x;
T y in 

assert(x==y);
assert(==);

Note that I am not suggesting that the syntax I wrote is what 
exists or should exist. I think what I am suggesting is not the 
same as say implicitly dereferenced pointers. If you think of the 
underlying machine, variables are aliases for locations in memory 
where values are stored, and what I am asking is whether it is 
possible to alias an arbitrary location (provided it contains the 
correct type.) (I guess what I am saying is only conceptually 
true variables might end up in registers, but from the point of 
view of the language it is true since if v is a variable, then  
is defined to be its address.)


This would allow things like:

Given:

struct S
{
   int x;
   int y;
}

You can write:

S s = S(1,2) in new S;

ending up with s being defined on the heap.

Anyway I hope it is clearer what I mean. Is it possible to do 
this in d?








Re: Anyway to achieve the following

2021-08-13 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Aug 13, 2021 at 05:11:50PM +, Rekel via Digitalmars-d-learn wrote:
[...]
> For anyone more experienced with C, I'm not well known with references
> but are those semantically similar to the idea of using a type at a
> predefined location?

References are essentially pointers under the hood. The difference is
that at the language level they are treated as aliases to the original
variable, and are therefore guaranteed to be non-null.

Note that in D `ref` is not a type constructor but a storage qualifier,
so you cannot declare a reference variable, you can only get one if you
pass a variable to a function that takes it by ref.


T

-- 
Spaghetti code may be tangly, but lasagna code is just cheesy.


Re: Anyway to achieve the following

2021-08-13 Thread Rekel via Digitalmars-d-learn

On Friday, 13 August 2021 at 09:10:18 UTC, Tejas wrote:

On Friday, 13 August 2021 at 08:25:33 UTC, JG wrote:

Suppose one has a pointer p of type T*.
Can on declare variable a of type T which is stored in the 
location pointed to by p?

Umm is this what you want?
```d
import std.stdio;

struct S
{
  int x = 1234;
}


void main() {
S s;
/*(ref a){
 writeln(a);
 s.x = s.x + 1;
 writeln(a);
 a = a +1;
 writeln(s.x);
}(s.x);*/

auto a = &(s.x);
writeln(*a);
s.x += 1;
writeln(*a);
*a += 1;
writeln(s.x);


}
```


That's also what I thought, although at first I thought JG meant 
dereferencing a pointer to a type without reallocating the 
content.


In a way comparable to aliasing A* or having your original data 
be a union in the first place.
It seems however one can use `.` when using pointers, which is 
cool, though there seem to be some caveats: 
https://forum.dlang.org/post/hthxvxxsxdpkvwcwg...@forum.dlang.org 
(note this is 2014...))


For anyone more experienced with C, I'm not well known with 
references but are those semantically similar to the idea of 
using a type at a predefined location?


Small sidenote, this would be cool:
```d
int* ip = cast(int*)other_pointer;
int a = #a; // like a dereference but without allocating space 
for a elsewhere.

int b = #a; // Or something along those lines
a = 1;
b += 1;
assert(a==2);
```


Re: Anyway to achieve the following

2021-08-13 Thread Paul Backus via Digitalmars-d-learn

On Friday, 13 August 2021 at 09:30:25 UTC, Ali Çehreli wrote:
(core.lifetime is not on dlang.org at the moment for me but it 
is under /usr/include/dmd/druntime/import/core on my computer.)


It's also on dpldocs.info:

https://dpldocs.info/experimental-docs/core.lifetime.html


Re: Anyway to achieve the following

2021-08-13 Thread Ali Çehreli via Digitalmars-d-learn

On 8/13/21 1:25 AM, JG wrote:

> Suppose one has a pointer p of type T*.
> Can on declare variable a of type T which is stored in the location
> pointed to by p?

You may be looking for core.lifetime.emplace. (core.lifetime is not on 
dlang.org at the moment for me but it is under 
/usr/include/dmd/druntime/import/core on my computer.)


I have some content about 'emplace' but it is not in std.conv anymore:

  http://ddili.org/ders/d.en/memory.html#ix_memory.construction,%20emplace

Ali



Re: Anyway to achieve the following

2021-08-13 Thread Tejas via Digitalmars-d-learn

On Friday, 13 August 2021 at 08:25:33 UTC, JG wrote:

Suppose one has a pointer p of type T*.
Can on declare variable a of type T which is stored in the 
location pointed to by p?


As an example if we have:

struct S
{
  int x = 1234;
}

void main() {
   S s;
   //unknown construction of a using &(s.x)
   writeln(a); //displays 1234
   s.x = s.x+1;
   writeln(a); //displays 1235
   a = a +1;
   writeln(s.x); //displays 1236
}

Similar behavior can be achieved in the body of the lambda here

import std.stdio;

struct S
{
  int x = 1234;
}


void main() {
S s;
(ref a){
 writeln(a);
 s.x = s.x + 1;
 writeln(a);
 a = a +1;
 writeln(s.x);
}(s.x);
}


Umm is this what you want?
```d
import std.stdio;

struct S
{
  int x = 1234;
}


void main() {
S s;
/*(ref a){
 writeln(a);
 s.x = s.x + 1;
 writeln(a);
 a = a +1;
 writeln(s.x);
}(s.x);*/

auto a = &(s.x);
writeln(*a);
s.x += 1;
writeln(*a);
*a += 1;
writeln(s.x);


}
```


Anyway to achieve the following

2021-08-13 Thread JG via Digitalmars-d-learn

Suppose one has a pointer p of type T*.
Can on declare variable a of type T which is stored in the 
location pointed to by p?


As an example if we have:

struct S
{
  int x = 1234;
}

void main() {
   S s;
   //unknown construction of a using &(s.x)
   writeln(a); //displays 1234
   s.x = s.x+1;
   writeln(a); //displays 1235
   a = a +1;
   writeln(s.x); //displays 1236
}

Similar behavior can be achieved in the body of the lambda here

import std.stdio;

struct S
{
  int x = 1234;
}


void main() {
S s;
(ref a){
 writeln(a);
 s.x = s.x + 1;
 writeln(a);
 a = a +1;
 writeln(s.x);
}(s.x);
}