March 27, 2018 Re: Optional type - how to correctly reset a wrapped immutable T | ||||
---|---|---|---|---|
| ||||
Posted in reply to Seb | 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 Re: Optional type - how to correctly reset a wrapped immutable T | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | 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 Re: Optional type - how to correctly reset a wrapped immutable T | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | 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 Re: Optional type - how to correctly reset a wrapped immutable T | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | 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 Re: Optional type - how to correctly reset a wrapped immutable T | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | 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 Re: Optional type - how to correctly reset a wrapped immutable T | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | 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 Re: Optional type - how to correctly reset a wrapped immutable T | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | 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 Re: Optional type - how to correctly reset a wrapped immutable T | ||||
---|---|---|---|---|
| ||||
Posted in reply to SimonN | 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 |
Copyright © 1999-2021 by the D Language Foundation