Struct that destroys its original handle on copy-by-value
John Colvin via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sat Aug 1 10:50:26 PDT 2015
On Saturday, 1 August 2015 at 12:10:43 UTC, Joseph Rushton
Wakeling wrote:
> On 31/07/15 19:21, Ali Çehreli via Digitalmars-d-learn wrote:
>> On 07/26/2015 04:29 AM, Joseph Rushton Wakeling via
>> Digitalmars-d-learn wrote:
>>
>> > is this design idea even feasible in principle, or just a
>> bad
>> > idea from the get-go?
>>
>> As I understand it, it is against one of fundamental D
>> principles: structs are
>> value types where any copy can be used in place of any other.
>>
>> I expect there are examples where even Phobos violates it but
>> the struct
>> documentation still says so: "A struct is defined to not have
>> an identity; that
>> is, the implementation is free to make bit copies of the
>> struct as convenient."
>>
>> http://dlang.org/struct.html
>
> That really feels very bad for the problem domain I have in
> mind -- random number generation. No implementation should be
> free to make copies of a random number generator "as
> convenient", that should be 100% in the hands of the programmer!
>
>
>> > And if feasible -- how would I go about it?
>>
>> Disallowing automatic copying and providing a function comes
>> to mind.
>
> Yes, I considered that, but I don't think it really delivers
> what's needed :-(
>
> Let me give a concrete example of why I was thinking in this
> direction. Consider RandomSample in std.random. This is a
> struct (a value type, instantiated on the stack). However, it
> also wraps a random number generator. It needs to be consumed
> once and once only, because otherwise there will be unintended
> statistical correlations in the program. Copy-by-value leads
> to a situation where you can accidentally consume the same
> sequence twice (or possibly, only _part_ of the sequence).
>
> Now, indeed, one way is to just @disable this(this) which
> prevents copy-by-value. But then you can't do something
> natural and desirable like:
>
> iota(100).randomSample(10, gen).take(5).writeln;
>
> ... because you would no longer be able to pass the
> RandomSample instance into `take`.
>
> On the other hand, what you want to disallow is this:
>
> auto sample = iota(100).randomSample(10, gen);
>
> sample.take(5).writeln;
> sample.take(5).writeln; // statistical correlations result,
> // probably unwanted
>
> The first situation is still possible, and the second
> disallowed (or at least, guarded against), _if_ a copy-by-value
> is finalized by tweaking the source to render it an empty range.
>
> I would happily hear alternative solutions to the problem, but
> that's why I was interested in a struct with the properties I
> outlined in my original post.
Naïve compromise solution?
struct S(bool noCopy = true)
{
//replace with real state
int state = 0;
static if(noCopy) @disable this(this);
@property auto copyable()
{
//did the move manually because I got
//weird results std.algorithm.move
auto ret = cast(S!false)this;
this.state = this.state.init;
return ret;
}
}
auto s(int state)
{
return S!()(state);
}
void main()
{
import std.stdio, std.algorithm;
auto s = s(42);
auto s1 = s.move;
assert(s == S!().init);
s1.copyable.writeln;
assert(s1 == S!().init);
}
Then at least the simplest mistakes are avoided. Also, it means
people are more likely to read important docs i.e. "Why do I have
to call this copyable thing? Oh, I see, I'll be careful."
I'm not sure how good an idea it is to totally enforce a range to
be non-copyable, even if you could deal with the function call
chain problem. Even in totally save-aware code, there can still
be valid assignment of a range type. I'm pretty sure a lot of
phobos ranges/algorithms would be unusable.
More information about the Digitalmars-d-learn
mailing list