March 27, 2018
On Monday, 26 March 2018 at 11:19:31 UTC, Seb wrote:
> On Monday, 26 March 2018 at 10:13:08 UTC, Simen Kjærås wrote:
>> On Monday, 26 March 2018 at 09:46:57 UTC, Nicholas Wilson wrote:
>>> Have a look at Rebindable: https://dlang.org/phobos/std_typecons.html#rebindable
>>
>> Allow me to quote from aliak's post:
>>
>>> what I'm looking for is a Rebindable implementation that's for value types
>>
>> As can be surmised from the above line, aliak has looked at Rebindable, and it doesn't work with value types.
>>
>> --
>>   Simen
>
> Though Rebindable could be improved to work with value types:
>
> https://github.com/dlang/phobos/pull/6136

And of course Seb knows about a related PR :p Will take a look to see what kind of magic is in there. Thanks !
March 27, 2018
On Tuesday, 27 March 2018 at 06:26:57 UTC, aliak wrote:
> [snip]
>
> By the by,  how come inout has to be stack based and const/immutable/mutable doesn't? Isn't inout just one of those depending on context?

Example?
March 27, 2018
On Tuesday, 27 March 2018 at 11:57:28 UTC, jmh530 wrote:
> On Tuesday, 27 March 2018 at 06:26:57 UTC, aliak wrote:
>> [snip]
>>
>> By the by,  how come inout has to be stack based and const/immutable/mutable doesn't? Isn't inout just one of those depending on context?
>
> Example?

Hmm, now that I'm explicitly trying to produce it, I feel I maybe using inout incorrectly?

struct Optional(T) {
    T[] bag;
    this(T t) {
        bag = [t];
    }
}

struct S {
    Optional!(inout(int)) f() inout
    {
        return Optional!(inout(int))(3);
    }
}

void main()
{
    auto a = S().f;
}

Above gives: Error: variable `onlineapp.Optional!(inout(int)).Optional.bag` only parameters or stack based variables can be inout

Change inout to const e.g. and it's all good.
March 27, 2018
On Tuesday, 27 March 2018 at 13:02:50 UTC, aliak wrote:
>
> Hmm, now that I'm explicitly trying to produce it, I feel I maybe using inout incorrectly?
>
> struct Optional(T) {
>     T[] bag;
>     this(T t) {
>         bag = [t];
>     }
> }
>
> struct S {
>     Optional!(inout(int)) f() inout
>     {
>         return Optional!(inout(int))(3);
>     }
> }
>
> void main()
> {
>     auto a = S().f;
> }
>
> Above gives: Error: variable `onlineapp.Optional!(inout(int)).Optional.bag` only parameters or stack based variables can be inout
>
> Change inout to const e.g. and it's all good.

You may refer to the section on struct constructors. inout on a constructor serves as both a const and an immutable constructor. This would allow you to create mutable/const/immutable objects of whatever struct. The payload could have some different setting.

https://dlang.org/spec/struct.html#struct-constructor

How about:

struct Optional(T) {
    T[] bag;
    this(T t) {
        bag = [t];
    }
}

Optional!T optional(T)(T x)
{
    return Optional!T(x);
}

void main()
{
    int x = 3;
    const(int) xx = 3;
    immutable(int) xxx = 3;

    auto y = optional(x);
    auto yy = optional(xx);
    auto yyy = optional(xxx);
}
March 27, 2018
On Monday, 26 March 2018 at 14:17:03 UTC, Jonathan M Davis wrote:
> Rebindable does is pretty questionable as far as the type system goes, but it does what it does by forcing pointer semantics on a class reference, so the point is arguable.

Yeah, I've always assumed that Rebindable cannot be implemented without internally breaking the type system, then exposing a safe interface.

But this sparked my interest, I've dug out the Rebindable code:

    private mixin template RebindableCommon(T, U, alias This)
        if (is(T == class) || is(T == interface) || isAssociativeArray!T)
    {
        private union
        {
            T original; // e.g., immutable(A) for classs A
            U stripped; // the unqualified type, e.g., A
        }
        // ...
    }

Does Rebindable-using code, oblivious of the hacks inside Rebindable, remain 100 % safe even with aggressive compiler optimizations? For class A, inside Rebindable!(immutable A), there is a union of (immutable A) and A. I suspect that the D compiler is allowed to treat this reference to (immutable A) as immutable itself. Have there never been bugs here when, later, stripped = another.stripped;?

-- Simon
March 27, 2018
On Tuesday, 27 March 2018 at 13:51:20 UTC, jmh530 wrote:
> 
>
> How about:
> [snip]

I can kind of like this more, but after re-reading your original post I'm not sure it really resolves your issue:

struct Optional(T) {
    import std.traits : isMutable;
    T[] bag;

    this(T t) inout {
        bag = [t];
    }

    void opAssign(T rhs)
    {
        static if (isMutable!T)
            bag[0] = rhs;
        else
            bag = [rhs];
    }
}

Optional!T optional(T)(T x)
{
    return Optional!T(x);
}

void main()
{
    int x = 3;
    const(int) xx = 3;
    immutable(int) xxx = 3;
    immutable(int) xxxx = 4;

    auto y = optional(x);
    auto yy = optional(xx);
    auto yyy = optional(xxx);
    yyy = xxxx;
}
March 27, 2018
On Tuesday, 27 March 2018 at 15:28:40 UTC, jmh530 wrote:
>         static if (isMutable!T)
>             bag[0] = rhs;
>         else
>             bag = [rhs];

I like this idea. I'd even take it a step futher:

When T is a pointer or class reference, then we can put the reference on the stack (instead of into the array) and handle assignments like Rebindable handles assignments -- provided that Rebindable really is 100 % safe to the outside, see my concerns from 2 posts above. In this case (static if), we won't even declare the array T[] bag, and instead implement as T value, bool isPresent.

When T is a mutable value type, it goes on the stack, too. Again no array.

When T is a const/immutable/inout value type, we declare the array as before and rebind on assignment with bag = [rhs], as you proposed here.

-- Simon
March 29, 2018
On Tuesday, 27 March 2018 at 15:37:11 UTC, SimonN wrote:
> On Tuesday, 27 March 2018 at 15:28:40 UTC, jmh530 wrote:
>>         static if (isMutable!T)
>>             bag[0] = rhs;
>>         else
>>             bag = [rhs];
>
> I like this idea. I'd even take it a step futher:
>
> When T is a pointer or class reference, then we can put the reference on the stack (instead of into the array) and handle assignments like Rebindable handles assignments -- provided that Rebindable really is 100 % safe to the outside, see my concerns from 2 posts above. In this case (static if), we won't even declare the array T[] bag, and instead implement as T value, bool isPresent.
>
> When T is a mutable value type, it goes on the stack, too. Again no array.
>
> When T is a const/immutable/inout value type, we declare the array as before and rebind on assignment with bag = [rhs], as you proposed here.
>
> -- Simon

I think this all sounds good. I found the "magic" as well in Seb's Rebindable PR link for value types so might be able to have stack storage for const value types as well [1]. Not sure how safe it is.

Inout poses a problem in all cases though and I'm unsure how to solve it without stripping the qualifiers completely from the payload. Basically:

struct S(T) {
    T t;
}

auto make(T)(T t) {
    return S!(T)(t);
}

class C {
    int i;
    auto f() inout {
        make(i);
    }
}

Will not compile.

I can make T an Unqual!T, but then we are open to type breakage in cases where users should have access to member t.


[1] https://github.com/dlang/phobos/pull/6136/files#diff-4e008aedb3026d4a84f58323e53bf017R2223
1 2
Next ›   Last »