Jump to page: 1 2 3
Thread overview
Struct that destroys its original handle on copy-by-value
Jul 26, 2015
Martijn Pot
Jul 29, 2015
Adam D. Ruppe
Jul 29, 2015
Vlad Levenfeld
Jul 30, 2015
Marc Schütz
Jul 31, 2015
Kagamin
Jul 31, 2015
Ali Çehreli
Jul 31, 2015
Dicebot
Jul 31, 2015
Ali Çehreli
Jul 31, 2015
Dicebot
Jul 31, 2015
H. S. Teoh
Jul 31, 2015
Dicebot
Jul 31, 2015
Ali Çehreli
Aug 01, 2015
John Colvin
Aug 02, 2015
Dicebot
Aug 03, 2015
Kagamin
Aug 03, 2015
Dicebot
July 26, 2015
Hello all,

A design question that came up during the hackathon held during the last Berlin D Meetup.

I was trying to come up with a range that can be copied by value, but when this is done, destroys the original handle.  The idea would be behaviour something like this:

    auto originalRange = myWeirdRange(whatever);
    originalRange.take(10).writeln;
    assert(originalRange.empty,
           "The original handle points to an empty range after copy-by-value.");

A very minimal prototype (missing out the details of front and popFront as irrelevant) would be something like:

    struct MyWeirdRange (R)
        if (isInputRange!R)
    {
      private:
        R* input_;   // Assumed to never be empty, FWIW.  I'm missing out
                     // a template check on that for brevity's sake.

      public:
        this (return ref R input)
        {
            /* return ref should guarantee the pointer
             * is safe for the lifetime of the struct,
             * right ... ?
             */
            this.input_ = &input;
        }

        bool empty () @property
        {
            return this.input_ is null;
        }

        auto front () @property { ... }

        void popFront () { ... }

        void opAssign (ref typeof(this) that)
        {
            /* copy the internal pointer, then
             * set that of the original to null
             */
            this.input_ = that.input_;
            that.input_ = null;
        }
    }

Basically, this is a range that would actively enforce the principle that its use is a one-shot.  You copy it by value (whether by direct assignment or by passing it to another function), you leave the original handle an empty range.

However, the above doesn't work; even in the event of a direct assignment, i.e.

    newRange = originalRange;

... the opAssign is never called.  I presume this is because of the ref-parameter input, but it's not obvious to me according to the description here why this should be: http://dlang.org/operatoroverloading.html#assignment Can anyone clarify what's going on here?

Anyway, my main question is: is this design idea even feasible in principle, or just a bad idea from the get-go?  And if feasible -- how would I go about it?

Thanks & best wishes,

    -- Joe
July 26, 2015
On Sunday, 26 July 2015 at 11:30:16 UTC, Joseph Rushton Wakeling wrote:
> Hello all,
>
> A design question that came up during the hackathon held during the last Berlin D Meetup.
>
> [...]

Sounds like unique_ptr (so UniqueRange might be a nice name). Maybe you can get some ideas from that.
July 26, 2015
On 26/07/15 13:45, Martijn Pot via Digitalmars-d-learn wrote:
> Sounds like unique_ptr (so UniqueRange might be a nice name). Maybe you can get
> some ideas from that.

There is already a Unique in std.typecons.  However, I'm not sure that it's doing what I require.

Example:

    Unique!Random rng = new Random(unpredictableSeed);
    rng.take(10).writeln;

... will fail with an error:

    Error: struct std.typecons.Unique!(MersenneTwisterEngine!(uint, 32LU, 624LU, 397LU, 31LU, 2567483615u, 11LU, 7LU, 2636928640u, 15LU, 4022730752u, 18LU)).Unique is not copyable because it is annotated with @disable

My aim by contrast is to _allow_ that kind of use, but render the original handle empty when it's done.

July 29, 2015
On Sunday, 26 July 2015 at 11:30:16 UTC, Joseph Rushton Wakeling wrote:
> Hello all,
>
> A design question that came up during the hackathon held during the last Berlin D Meetup.
>
> [...]

Ping on the above -- nobody has any insight...?
July 29, 2015
On Sunday, 26 July 2015 at 12:16:30 UTC, Joseph Rushton Wakeling wrote:
> My aim by contrast is to _allow_ that kind of use, but render the original handle empty when it's done.

I don't think D offers any way to do that. With the disabled postblit, you can force people into a method you write that returns a new copy and clears the original, but that won't just work with assignment.

The ref assign might not be forbidden by the written doc but I'm guessing that is just an oversight - struct assignment in D  never clears the original, it is always a simple copy (perhaps plus other code)....
July 29, 2015
On Wednesday, 29 July 2015 at 19:10:36 UTC, Adam D. Ruppe wrote:
> On Sunday, 26 July 2015 at 12:16:30 UTC, Joseph Rushton Wakeling wrote:
>> My aim by contrast is to _allow_ that kind of use, but render the original handle empty when it's done.
>
> I don't think D offers any way to do that. With the disabled postblit, you can force people into a method you write that returns a new copy and clears the original, but that won't just work with assignment.
>
> The ref assign might not be forbidden by the written doc but I'm guessing that is just an oversight - struct assignment in D
>  never clears the original, it is always a simple copy (perhaps plus other code)....

Slightly OT, but this is something that would be possible with a copy constructor, I think?
July 30, 2015
On Wednesday, 29 July 2015 at 19:10:36 UTC, Adam D. Ruppe wrote:
> On Sunday, 26 July 2015 at 12:16:30 UTC, Joseph Rushton Wakeling wrote:
>> My aim by contrast is to _allow_ that kind of use, but render the original handle empty when it's done.
>
> I don't think D offers any way to do that. With the disabled postblit, you can force people into a method you write that returns a new copy and clears the original, but that won't just work with assignment.
>
> The ref assign might not be forbidden by the written doc but I'm guessing that is just an oversight - struct assignment in D
>  never clears the original, it is always a simple copy (perhaps plus other code)....

Hmm... are you implying that `opAssign(ref T other)` should be disallowed? Why? I find this the obvious way to implement move semantics, and it is also what std.algorithm.move does:

http://dlang.org/phobos/std_algorithm_mutation.html#.move
July 31, 2015
On Sunday, 26 July 2015 at 12:16:30 UTC, Joseph Rushton Wakeling wrote:
> Example:
>
>     Unique!Random rng = new Random(unpredictableSeed);
>     rng.take(10).writeln;
> My aim by contrast is to _allow_ that kind of use, but render the original handle empty when it's done.

`take` stores the range, you can try to use some sort of a weak reference.
July 31, 2015
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

> And if feasible -- how would I go about it?

Disallowing automatic copying and providing a function comes to mind.

Ali

July 31, 2015
On Friday, 31 July 2015 at 17:21:40 UTC, Ali Çehreli 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."

I believe this restriction should be banned. Considering classes have inherent reference + heap semantics (and you can only bail out of that with hacks) saying struct can't be anything but data bags makes impossible to implement whole class of useful designs.

The fact that Phobos has to violate it itself to get stuff done is quite telling.
« First   ‹ Prev
1 2 3