www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - refInt = ref int: how to achieve this? or is this a bug?

reply mw <mingwu gmail.com> writes:
----------------
import std.stdio;

alias refInt = ref int;

void f(refInt i) {
   i = 456;
}

void main() {
   int i = 123;
   writeln(i);
   f(i);
   writeln(i);
}
----------------

$ $DMD/windows/bin64/rdmd.exe reft.d
123
123

$ $LDC/bin/rdmd  reft.d
123
123

How to achieve this typdef/alias that what I want?

Thanks.
Jun 17
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 6/17/20 4:38 PM, mw wrote:
 ----------------
 import std.stdio;
 
 alias refInt = ref int;
 
 void f(refInt i) {
    i = 456;
 }
 
 void main() {
    int i = 123;
    writeln(i);
    f(i);
    writeln(i);
 }
 ----------------
 
 $ $DMD/windows/bin64/rdmd.exe reft.d
 123
 123
 
 $ $LDC/bin/rdmd  reft.d
 123
 123
 
 How to achieve this typdef/alias that what I want?
It's not possible in this way. ref is a storage class and not part of the type. Essentially, your alias statement becomes: alias refInt = int; Which in itself is somewhat of a "feature", as storage classes that do not apply are ignored. Some may consider it a bug, but I haven't seen anyone attempt something like what you have, it sure seems like the compiler should complain. -Steve
Jun 17
next sibling parent mw <mingwu gmail.com> writes:
On Wednesday, 17 June 2020 at 20:47:59 UTC, Steven Schveighoffer 
wrote:
 On 6/17/20 4:38 PM, mw wrote:
 It's not possible in this way. ref is a storage class and not 
 part of the type.

 Essentially, your alias statement becomes:

 alias refInt = int;

 Which in itself is somewhat of a "feature", as storage classes 
 that do not apply are ignored. Some may consider it a bug, but 
 I haven't seen anyone attempt something like what you have, it 
 sure seems like the compiler should complain.
I'm trying to typedef a PushT here: https://github.com/mingwugmail/liblfdsd/blob/master/liblfds.dpp#L52 The C interface only accept void*, so I need different PushT type for different D type (basic type int|double, ..., struct, class, stirng|array). Without be able to `alias PushT = ref T`, it's hard to define this func: https://github.com/mingwugmail/liblfdsd/blob/master/liblfds.dpp#L72 bool push(PushT value) { ... } Any work-around? or suggestions how to structure the D code?
Jun 17
prev sibling parent reply mw <mingwu gmail.com> writes:
On Wednesday, 17 June 2020 at 20:47:59 UTC, Steven Schveighoffer 
wrote:
 Essentially, your alias statement becomes:

 alias refInt = int;

 Which in itself is somewhat of a "feature", as storage classes 
 that do not apply are ignored. Some may consider it a bug, but 
 I haven't seen anyone attempt something like what you have, it 
 sure seems like the compiler should complain.
I would consider it a bug, *even* C++ can handle this better :-) i.e. no surprise to the programmer. cat reft.cpp ---------------------- #include <stdio.h> typedef int& refInt; void f(refInt i) { i = 456; } int main() { int i = 123; printf("%d\n", i); f(i); printf("%d\n", i); } ---------------------- $ make reft g++ reft.cpp -o reft $ ./reft 123 456
Jun 17
parent reply Avrina <avrina12309412342 gmail.com> writes:
On Wednesday, 17 June 2020 at 21:27:01 UTC, mw wrote:
 On Wednesday, 17 June 2020 at 20:47:59 UTC, Steven 
 Schveighoffer wrote:
 Essentially, your alias statement becomes:

 alias refInt = int;

 Which in itself is somewhat of a "feature", as storage classes 
 that do not apply are ignored. Some may consider it a bug, but 
 I haven't seen anyone attempt something like what you have, it 
 sure seems like the compiler should complain.
I would consider it a bug, *even* C++ can handle this better :-) i.e. no surprise to the programmer. cat reft.cpp ---------------------- #include <stdio.h> typedef int& refInt; void f(refInt i) { i = 456; } int main() { int i = 123; printf("%d\n", i); f(i); printf("%d\n", i); } ---------------------- $ make reft g++ reft.cpp -o reft $ ./reft 123 456
It's not a bug, it is purposefully designed to be that way. Just like you can't do ref variables. void main() { int a; int& b = a; // ok C++ ref int c = a; // not valid D } You can do something like this instead, not sure what you are trying to do tho. Could just be easier to put a separate function in the `static if` that you are trying to define the ref type in instead. import std.stdio; void foo(T)(auto ref T v) if (is(T : int) == __traits(isRef, v)) { writeln(__traits(isRef, v) ? "by ref" : "by value"); } void main() { int a; foo(a); // by ref // foo(10); // error by value float b; // foo(b); // error by ref foo(10.0f); // by value }
Jun 17
parent reply mw <mingwu gmail.com> writes:
On Wednesday, 17 June 2020 at 21:49:29 UTC, Avrina wrote:
 void foo(T)(auto ref T v) if (is(T : int) == __traits(isRef, > 
 v)) {
Thanks for the suggestion. Yes, that what I mean by: "guess I have to write more `static if`s." That is ugly. My thought is that: pointer and reference are all types of its own right: typedef `int*` is ptr in C++ typedef `int&` is ref in C++ and can you see the beauty of this symmetry? :-) In D, alias can correctly treat int* as pointer type, but treat `ref int` as `int`, this break the symmetry alias `int*` is ptr in D alias `ref int` becomes *int* in D can you see the visual ugliness of this? :-) not even to mention the semantic ugliness: compiler error on g(), not on f(): --------------------------- alias refInt = ref int; alias ptrInt = int*; void f(refInt i) { i = 456; } void g(ptrInt i) { } void main() { int i = 123; writeln(i); // 123 f(i); writeln(i); // 123! again g(i); // Error: function `reft.g(int* i)` is not callable using argument types `(int)` } ---------------------------
Jun 17
next sibling parent reply MoonlightSentinel <moonlightsentinel disroot.org> writes:
On Wednesday, 17 June 2020 at 22:09:35 UTC, mw wrote:
 and can you see the beauty of this symmetry?  :-)
Try int main() { typedef int* ptrInt; ptrInt arr; typedef int& refInt; refInt[] arr2; }
Jun 17
next sibling parent MoonlightSentinel <moonlightsentinel disroot.org> writes:
On Wednesday, 17 June 2020 at 22:15:08 UTC, MoonlightSentinel 
wrote:
 On Wednesday, 17 June 2020 at 22:09:35 UTC, mw wrote:
On Wednesday, 17 June 2020 at 22:15:08 UTC, MoonlightSentinel wrote: Wrong code, this was the intended code: int main() { typedef int* ptrInt; ptrInt arr[5]; typedef int& refInt; refInt arr2[5]; }
Jun 17
prev sibling parent reply mw <mingwu gmail.com> writes:
On Wednesday, 17 June 2020 at 22:15:08 UTC, MoonlightSentinel 
wrote:
 On Wednesday, 17 June 2020 at 22:09:35 UTC, mw wrote:
 and can you see the beauty of this symmetry?  :-)
Try int main() { typedef int* ptrInt; ptrInt arr; typedef int& refInt; refInt[] arr2; }
That's the semantics of reference: you cannot define a ref variable out of air. The equivalent D code cannot be compiled either. We are talking about pass either `ptr` or `ref` to other functions here.
Jun 17
parent reply MoonlightSentinel <moonlightsentinel disroot.org> writes:
On Wednesday, 17 June 2020 at 22:33:50 UTC, mw wrote:
 We are talking about pass either `ptr` or `ref` to other 
 functions here.
To quote some more of your previous post:
 My thought is that: pointer and reference are all types of its 
 own right:

 typedef `int*` is ptr in C++
 typedef `int&` is ref in C++
That's the inherent difference here, ref is a half-baked type constructor in C++ (and porting that behaviour to D would be a mistake as it would screw with highly templated code). But i would agree with you that there is a bug in your initial code, the `ref` should be rejected.
Jun 17
parent reply mw <mingwu gmail.com> writes:
On Wednesday, 17 June 2020 at 22:48:25 UTC, MoonlightSentinel 
wrote:
 But i would agree with you that there is a bug in your initial
It's not the bug in my code,
 code, the `ref` should be rejected.
it's the compiler's bug not rejecting it, given it's current semantics; instead it *silently* treat alias `ref int` as `int`.
Jun 17
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Wednesday, 17 June 2020 at 23:05:59 UTC, mw wrote:
 On Wednesday, 17 June 2020 at 22:48:25 UTC, MoonlightSentinel 
 wrote:
 But i would agree with you that there is a bug in your initial
It's not the bug in my code,
 code, the `ref` should be rejected.
it's the compiler's bug not rejecting it, given it's current semantics; instead it *silently* treat alias `ref int` as `int`.
It is both. In your code, for trying to use `ref` as a type qualifier when it is not (see [1] for type qualifiers), and in the compiler, for not issuing an error. [1] https://dlang.org/spec/const3.html
Jun 17
next sibling parent reply mw <mingwu gmail.com> writes:
On Wednesday, 17 June 2020 at 23:09:55 UTC, Stanislav Blinov 
wrote:
 it's the compiler's bug not rejecting it, given it's current 
 semantics; instead it *silently* treat alias `ref int` as 
 `int`.
It is both. In your code, for trying to use `ref` as a type qualifier when it is not (see [1] for type qualifiers), and in
Given the current language semantics, right, it shouldn't be typedef/alias-ed, But it make the code so complex / ugly to write: either: void foo(T)(auto ref T v) if (is(T : int) == __traits(isRef, v)) {} or f( T) /*more static if here*/ { /*potential dup code here*/ } f(ref T) /*more static if here*/ { /*potential dup code here*/ } I would call for improvement.
 the compiler, for not issuing an error.

 [1] https://dlang.org/spec/const3.html
Jun 17
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Wednesday, 17 June 2020 at 23:24:32 UTC, mw wrote:
 On Wednesday, 17 June 2020 at 23:09:55 UTC, Stanislav Blinov 
 wrote:
 it's the compiler's bug not rejecting it, given it's current 
 semantics; instead it *silently* treat alias `ref int` as 
 `int`.
It is both. In your code, for trying to use `ref` as a type qualifier when it is not (see [1] for type qualifiers), and in
Given the current language semantics, right, it shouldn't be typedef/alias-ed, But it make the code so complex / ugly to write: either: void foo(T)(auto ref T v) if (is(T : int) == __traits(isRef, v)) {}
Which translates to "take everything that implicitly converts to int by reference, and everything else - by value". I would love to see that same intent expressed in C++ in one declaration.
 or

 f(    T) /*more static if here*/ { /*potential dup code here*/ }
 f(ref T) /*more static if here*/ { /*potential dup code here*/ }

 I would call for improvement.
Again, looking at your code, this all comes out of your trying to conflate references and pass by reference. References (i.e. classes) and values (i.e. primitive types and structs) are semantically different, so should be treated differently.
Jun 17
parent reply mw <mingwu gmail.com> writes:
On Wednesday, 17 June 2020 at 23:48:52 UTC, Stanislav Blinov 
wrote:
 f(    T) /*more static if here*/ { /*potential dup code here*/ 
 }
 f(ref T) /*more static if here*/ { /*potential dup code here*/ 
 }

 I would call for improvement.
Again, looking at your code, this all comes out of your trying to conflate references and pass by reference. References (i.e. classes) and values (i.e. primitive types and structs) are semantically different, so should be treated differently.
It has to be done: because the C lib only accept void* as value. So on the D side, need to pass to C: -- primitive types, class (essentially pointers) by value -- struct, union, array|string, by reference The discussion here is how to make this passing code simple to write.
Jun 17
next sibling parent mw <mingwu gmail.com> writes:
On Wednesday, 17 June 2020 at 23:58:37 UTC, mw wrote:
 On Wednesday, 17 June 2020 at 23:48:52 UTC, Stanislav Blinov 
 wrote:
 f(    T) /*more static if here*/ { /*potential dup code 
 here*/ }
 f(ref T) /*more static if here*/ { /*potential dup code 
 here*/ }

 I would call for improvement.
Again, looking at your code, this all comes out of your trying to conflate references and pass by reference. References (i.e. classes) and values (i.e. primitive types and structs) are semantically different, so should be treated differently.
It has to be done: because the C lib only accept void* as value. So on the D side, need to pass to C: -- primitive types, class (essentially pointers) by value -- struct, union, array|string, by reference The discussion here is how to make this passing code simple to write.
OK, guess Auto Ref Parameters is specially designed for this: https://dlang.org/spec/template.html#auto-ref-parameters
Jun 17
prev sibling next sibling parent Paul Backus <snarwin gmail.com> writes:
On Wednesday, 17 June 2020 at 23:58:37 UTC, mw wrote:
 It has to be done: because the C lib only accept void* as value.

 So on the D side, need to pass to C:

 -- primitive types, class (essentially pointers) by value
 -- struct, union, array|string, by reference

 The discussion here is how to make this passing code simple to 
 write.
void* address(T)(ref T arg) { static if (is(T == class) || is(T == interface)) return cast(void*) arg; else return cast(void*) &arg; }
Jun 17
prev sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Wednesday, 17 June 2020 at 23:58:37 UTC, mw wrote:
 On Wednesday, 17 June 2020 at 23:48:52 UTC, Stanislav Blinov 
 wrote:
 f(    T) /*more static if here*/ { /*potential dup code 
 here*/ }
 f(ref T) /*more static if here*/ { /*potential dup code 
 here*/ }

 I would call for improvement.
Again, looking at your code, this all comes out of your trying to conflate references and pass by reference. References (i.e. classes) and values (i.e. primitive types and structs) are semantically different, so should be treated differently.
It has to be done: because the C lib only accept void* as value. So on the D side, need to pass to C: -- primitive types, class (essentially pointers) by value -- struct, union, array|string, by reference The discussion here is how to make this passing code simple to write.
That's completely backwards. Because the C lib only takes void*, it forfeits any type safety and memory safety, so it is *on you* to preserve that. Which would require quite some code indeed. I don't think you've fully considered the implications of your code. You allocate an opaque memory region, which the GC knows nothing about, and you want to put pointers and references into it. That's bug number 1. Whether the GC *should* know about that memory depends on types you're using - static ifs are a must. You want to escape unshared pointers into other threads. That's bug number 2. The language can't statically verify that a pointer you're passing is the only pointer. It can only help you verify that a pointer you're passing may not point to unshared data - static ifs are a must. You want to escape pointers to locals on the stack to other threads. That's, tentatively, bug number 3. And no static ifs for that one, here you're on your own. And you want it all doable with "simple to write" code? That code *should* be onerous to write, like any other side stepping of the type system.
Jun 17
parent reply mw <mingwu gmail.com> writes:
On Thursday, 18 June 2020 at 00:40:15 UTC, Stanislav Blinov wrote:
 That's completely backwards. Because the C lib only takes 
 void*, it forfeits any type safety and memory safety, so it is 
 *on you* to preserve that. Which would require quite some code 
 indeed. I don't think you've fully considered the implications 
 of your code.
Thank you for your comments. But I think you complicated the design: C is C, D is D. So let -- C manage C's memory (the container), and -- D manage C's memory (the objects) The only thing interfacing is simple the (void*) as *value*. -- all primitive types | class (pointers)'s *value* are stored as value of (void*) -- all (fat) objects' *address* are stored as value of (void*) The only extra requirement on the D side is to keep reference to those fat objects to avoid it being GC-ed before being pop-ed. (Just as don't push a stack var into any-type-of queue, and pop it after the stack is gone -- this are the responsibility of the programmer, not the container.) That's all. Anyway, this is a bit off-topic of this thread. Feel free to comment on github after I finish it, and welcome to be my code reviewers.
Jun 17
next sibling parent mw <mingwu gmail.com> writes:
On Thursday, 18 June 2020 at 01:21:52 UTC, mw wrote:
 -- C manage C's memory (the container), and
 -- D manage C's memory (the objects)
typo: -- D manage D's memory but you know I like symmetry, easy to detect errors.
Jun 17
prev sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Thursday, 18 June 2020 at 01:21:52 UTC, mw wrote:

 Thank you for your comments.

 But I think you complicated the design: C is C, D is D. So let

 -- C manage C's memory (the container), and
 -- D manage D's memory (the objects)

 The only thing interfacing is simple the (void*) as *value*.

 -- all primitive types | class (pointers)'s *value* are stored 
 as value of (void*)
 -- all (fat) objects' *address* are stored as value of (void*)

 The only extra requirement on the D side is to keep reference 
 to those fat objects to avoid it being GC-ed before being 
 pop-ed.

 (Just as don't push a stack var into any-type-of queue, and pop 
 it after the stack is gone -- this are the responsibility of 
 the programmer, not the container.)

 That's all.
So... not doing this: queue.push(new Object); // receiver may get garbage reference or this (when compiled with -preview=rvaluerefparam, in other words, when rvalues would be allowed to bind to refs): queue.push(FatStruct()); // temporary is gone after push() returns or, more to the point, since you want this to be very "generic": queue.push(createStuff!options()); // yeah, createStuff is somewhere inside 20kLOC in another module ...NOT doing any of those are all also programmer's responsibility? You're absolutely correct, C is C, and D is D, and type system exists for a reason, yet you're trying to circumvent it, and don't like it when the language fights back. Like I originally remarked, if you *want* to be escaping pointers, then escape pointers, and state as much in your interface. That will simplify it (the interface), and leave your users (i.e. "the programmers") with no illusions as to what's going on. ...or, realize that values and references have different semantics, and require different handling (in other words, different queue types).
Jun 17
parent mw <mingwu gmail.com> writes:
On Thursday, 18 June 2020 at 02:22:55 UTC, Stanislav Blinov wrote:
 On Thursday, 18 June 2020 at 01:21:52 UTC, mw wrote:
 queue.push(new Object); // receiver may get garbage reference
 queue.push(FatStruct()); // temporary is gone after push() 
 queue.push(createStuff!options()); // yeah, createStuff is
Can all of these be rewritten as: dSideRefHolderVar = dSideWhateverStuff(); queue.push(dSideRefHolderVar); ? To use that C lib, then have to live with its constraints. I have no intention to wrap that library to work universally in the D world. If dpp can provide a thin oo wrapper automatically, I don’t even want to write this one.
 You're absolutely correct, C is C, and D is D, and type system
I’m glad you recognize this:-)
 exists for a reason, yet you're trying to circumvent it, and 
 don't like it when the language fights back.
This is not true: the compiler silently throw away ref from the alias without issuing an error; if it did, I would be more sure it’s a feature rather than bug, given the current semantics. Then I will try to find other way to make it work.
 Like I originally remarked, if you *want* to be escaping 
 pointers, then escape pointers, and state as much in your 
 interface. That will simplify it (the interface), and leave 
 your users (i.e. "the programmers") with no illusions as to 
 what's going on.
That’s right: The library user have to know how the original library works in order to use the wrapper. Maybe I haven’t mentioned this: “To make those initial values valid (which is to say, visible) upon other logical cores, threads on those cores need to issue the define https://www.liblfds.org/mediawiki/index.php?title=r7.1.1:Define_LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE ” It’s ugly macro of that C lib need to be called, but need to live with it. And even laughable this: The LFDS711_QUEUE_BMM_QUERY_GET_POTENTIALLY_INACCURATE_COUNT query is not guaranteed to be accurate. Where enqueue and dequeue operations are not guaranteed to be visible by the time the function calls return, similarly, it may be that a count will during its operation not see an element which has been enqueued, or see that an element has been dequeued. In general however it should be bang on; it's just it's not guaranteed. https://www.liblfds.org/mediawiki/index.php?title=r7.1.1:Function_lfds711_queue_bmm_query#Notes Yet, this library is the best time tested open source library on the internet. I have no interest to re-invent the wheels, or make the wrapper universal. Because it’s much better than the ~4x times slower fewly-used D queues I have found.
Jun 17
prev sibling parent reply mw <mingwu gmail.com> writes:
On Wednesday, 17 June 2020 at 23:09:55 UTC, Stanislav Blinov 
wrote:
 On Wednesday, 17 June 2020 at 23:05:59 UTC, mw wrote:
 On Wednesday, 17 June 2020 at 22:48:25 UTC, MoonlightSentinel 
 wrote:
 But i would agree with you that there is a bug in your initial
It's not the bug in my code,
 code, the `ref` should be rejected.
it's the compiler's bug not rejecting it, given it's current semantics; instead it *silently* treat alias `ref int` as `int`.
It is both. In your code, for trying to use `ref` as a type qualifier when it is not (see [1] for type qualifiers), and in the compiler, for not issuing an error. [1] https://dlang.org/spec/const3.html
https://github.com/dlang/phobos/blob/master/std/range/package.d#L921 ``` alias ElementType = ref RvalueElementType; ``` Even code in phobos try to write this way too :-)
Jun 17
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 6/18/20 2:01 AM, mw wrote:
 On Wednesday, 17 June 2020 at 23:09:55 UTC, Stanislav Blinov wrote:
 On Wednesday, 17 June 2020 at 23:05:59 UTC, mw wrote:
 On Wednesday, 17 June 2020 at 22:48:25 UTC, MoonlightSentinel wrote:
 But i would agree with you that there is a bug in your initial
It's not the bug in my code,
 code, the `ref` should be rejected.
it's the compiler's bug not rejecting it, given it's current semantics; instead it *silently* treat alias `ref int` as `int`.
It is both. In your code, for trying to use `ref` as a type qualifier when it is not (see [1] for type qualifiers), and in the compiler, for not issuing an error. [1] https://dlang.org/spec/const3.html
https://github.com/dlang/phobos/blob/master/std/range/package.d#L921 ```                 alias ElementType = ref RvalueElementType; ``` Even code in phobos try to write this way too :-)
Three lines up: https://github.com/dlang/phobos/blob/master/std/range/package.d#L918 // This doesn't work yet I don't think it will ever work. -Steve
Jun 18
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Thursday, 18 June 2020 at 14:16:51 UTC, Steven Schveighoffer 
wrote:

 Three lines up:
 https://github.com/dlang/phobos/blob/master/std/range/package.d#L918

 // This doesn't work yet

 I don't think it will ever work.

 -Steve
Yup, it's just a bug in the parser. You can even do a alias wow = ref override abstract final scope static __gshared int; Still gonna be an int tho.
Jun 18
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Jun 18, 2020 at 02:20:04PM +0000, Stanislav Blinov via Digitalmars-d
wrote:
[...]
 Yup, it's just a bug in the parser. You can even do a
 
 alias wow = ref override abstract final scope static __gshared int;
 
 Still gonna be an int tho.
Wow that's ridiculous. A bug should be filed for this! T -- Those who don't understand Unix are condemned to reinvent it, poorly.
Jun 18
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Thursday, 18 June 2020 at 14:45:01 UTC, H. S. Teoh wrote:

 alias wow = ref override abstract final scope static __gshared 
 int;
 
 Still gonna be an int tho.
Wow that's ridiculous. A bug should be filed for this! T
It has been, not to worry. Also, a sense of deja vu kept bugging me, I found why: https://forum.dlang.org/post/k2fq3b$1t33$1 digitalmars.com
Jun 19
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Jun 19, 2020 at 01:21:07PM +0000, Stanislav Blinov via Digitalmars-d
wrote:
[...]
 It has been, not to worry. Also, a sense of deja vu kept bugging me, I
 found why: https://forum.dlang.org/post/k2fq3b$1t33$1 digitalmars.com
LOL, wow. Now *that* is totally ridiculous. :-D (And yeah, I also vaguely remember seeing that back then.) T -- Life is too short to run proprietary software. -- Bdale Garbee
Jun 19
prev sibling parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Wednesday, 17 June 2020 at 22:09:35 UTC, mw wrote:

 My thought is that: pointer and reference are all types of its 
 own right:

 typedef `int*` is ptr in C++
 typedef `int&` is ref in C++

 and can you see the beauty of this symmetry?  :-)
No, I can't. typedef int* intPtr; const intPtr ip = new int; typedef int& intRef; const intRef i = 3; // oops, does not compile
 In D, alias can correctly treat int* as pointer type, but treat 
 `ref int` as `int`, this break the symmetry
ref int is not a type. What should break is the line alias intRef = ref int; should not compile. Looks like it does compile. That's a bug.
 alias `int*`    is       ptr  in D
 alias `ref int` becomes *int* in D

 can you see the visual ugliness of this? :-) not even to 
 mention the semantic ugliness:
You're conflating reference types and pass by reference. These are not the same thing in D, and never will be.
Jun 17
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/17/20 1:38 PM, mw wrote:

 alias refInt = ref int;
(Aside: I think this thread should be on the 'learn' forum.) I've just come up with the following struct just to compile the code. It works but as you see with need for refInt(i) inside main, constructors are not called automatically in D. (Hence your thread. :) ) import std.stdio; struct refInt { int * p; this(ref int i) { this.p = &i; } ref int reference() { return *p; } alias reference this; auto opAssign(int i) { reference() = i; return this; } } void f(refInt i) { i = 456; } void main() { int i = 123; writeln(i); f(refInt(i)); writeln(i); } Ali
Jun 17
parent reply mw <mingwu gmail.com> writes:
On Wednesday, 17 June 2020 at 21:01:53 UTC, Ali Çehreli wrote:
 On 6/17/20 1:38 PM, mw wrote:
 (Aside: I think this thread should be on the 'learn' forum.)
That's my initially thought, but then I realized this could be a D bug, or a feature request.
 struct refInt {...}
Yes, I know there are work-around, but for my usage: https://github.com/mingwugmail/liblfdsd/blob/master/liblfds.dpp#L52 all these work-around are too heavy, a verbatim typedef in my question is the most succinct way to be used. Sigh, looks like it's not supported at this time, guess I have to write more `static if`s.
Jun 17
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Wednesday, 17 June 2020 at 21:20:00 UTC, mw wrote:
 On Wednesday, 17 June 2020 at 21:01:53 UTC, Ali Çehreli wrote:
 On 6/17/20 1:38 PM, mw wrote:
 (Aside: I think this thread should be on the 'learn' forum.)
That's my initially thought, but then I realized this could be a D bug, or a feature request.
 struct refInt {...}
Yes, I know there are work-around, but for my usage: https://github.com/mingwugmail/liblfdsd/blob/master/liblfds.dpp#L52 all these work-around are too heavy, a verbatim typedef in my question is the most succinct way to be used. Sigh, looks like it's not supported at this time, guess I have to write more `static if`s.
This is not a bug, this is by design. Also, you're trying to escape a pointer to arbitrary non-`shared` data residing on the stack into some global, shared, storage. I.e. (a) to not cause UB, you will need to make sure the consumer gets the data before you go out of scope, which defeats the purpose of this lock-free queue. And (b) to not cause UB, you will need to make sure consumer does not access the data concurrently with the producer. With that taken into account, if you do want to be escaping pointers, just escape pointers.
Jun 17
parent reply mw <mingwu gmail.com> writes:
On Wednesday, 17 June 2020 at 22:19:28 UTC, Stanislav Blinov 
wrote:
 This is not a bug, this is by design.

 Also, you're trying to escape a pointer to arbitrary 
 non-`shared` data residing on the stack into some global, 
 shared, storage. I.e. (a) to not cause UB, you will need to 
 make sure the consumer gets the data before you go out of 
 scope, which defeats the purpose of this lock-free queue. And 
 (b) to not cause UB, you will need to make sure consumer does 
 not access the data concurrently with the producer.

 With that taken into account, if you do want to be escaping 
 pointers, just escape pointers.
This discussion is not about this particular usage in that particular queue (either shared/lock free or not). Even with a plain dummy queue, the user can do whatever s/he want with the queue, e.g. push a stack var, and pop it when that stack is gone :-). The queue object has no control of this, again regardless of what kind of the queue it is. It's the programmers' responsibility to make sure the push/pop usage is right. Here we are discussing how to write: -- f(pass by value) and -- f(pass by ref) in a simple and straight forward way.
Jun 17
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Wednesday, 17 June 2020 at 22:41:21 UTC, mw wrote:

 Here we are discussing how to write:

 -- f(pass by value) and
 -- f(pass by ref)

 in a simple and straight forward way.
f(T) {} f(ref T) {} ¯\_(ツ)_/¯
Jun 17
parent mw <mingwu gmail.com> writes:
On Wednesday, 17 June 2020 at 22:50:01 UTC, Stanislav Blinov 
wrote:
 On Wednesday, 17 June 2020 at 22:41:21 UTC, mw wrote:

 Here we are discussing how to write:

 -- f(pass by value) and
 -- f(pass by ref)

 in a simple and straight forward way.
f(T) {} f(ref T) {}
This alone will not work, have to add more static if's
Jun 17