On 8/1/17 7:44 PM, H. S. Teoh via Digitalmars-d-learn wrote:
On Tue, Aug 01, 2017 at 07:31:41PM -0400, Steven Schveighoffer via 
Digitalmars-d-learn wrote:
On 8/1/17 7:15 PM, H. S. Teoh via Digitalmars-d-learn wrote:
On Tue, Aug 01, 2017 at 07:09:45PM -0400, Steven Schveighoffer via 
Digitalmars-d-learn wrote:
If this were a true implementation without the opaqueness, it
would not work properly.
[...]

Actually, a proper implementation would still work, provided you
declare your pointer types carefully.  Sketch of idea:

        auto byKeyValue(AA)(AA aa) {
                struct Result {
                        const(Slot)* current; // N.B.: proper type
                        bool empty() { ... }
                        auto front() { return Pair(*current); }
                        void popFront() {
                                current = current.next;
                                ...
                        }
                }
                return Result(aa);
        }

Basically, the type of `current` must be const(Slot)* rather than
const(Slot*), which would be the default inferred type. But since
it's legal to assign a const pointer to a pointer to const (you
can't modify the original pointer, nor what it points to, but it's
valid to copy the pointer to a mutable pointer variable, as long as
what is pointed to is still const), this actually will work without
breaking / bypassing the type system.

No, you can't const the Slot, because if the value type is a pointer,
you can't then cast away the const-ness of it legally.

There are ways to get it right, it involves templating for mutability.
[...]

Counter-proof:

        struct Slot {
                Slot* next;
                const(string) key;
                const(int) value;
        }
        struct AA {
                Slot*[] slots;
        }
        unittest {
                const(AA) aa;

                static assert(is(typeof(aa.slots[0]) == const(Slot*)));
                const(Slot)* p = aa.slots[0];   // N.B.: legal
                p = p.next;                     // N.B.: legal
        }

Note especially the type checked for in the static assert: you cannot
modify any of the Slot pointers in the AA, but you *can* assign them to
mutable (but tail-const) pointers. Therefore you totally can iterate a
const AA without any casts or any breaking of the type system. And
there's no need to template for mutability either.

You can iterate a const AA, but if you want to iterate a non-const AA, you need a different type.

For instance, if your AA is int*[string], you will get const(int*) out of it, which may not be what you want.

Unless your range is a slice or a pointer, then you can't do it properly without having separate types for const, immutable, mutable ranges. You can use templates to build them, but it's not straightforward or pleasant.

-Steve

Reply via email to