June 17, 2020
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.


June 17, 2020
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.

June 18, 2020
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



June 18, 2020
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;
}
June 18, 2020
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.
June 18, 2020
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.


June 18, 2020
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.
June 18, 2020
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).
June 18, 2020
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.


June 18, 2020
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 :-)