why won't byPair work with a const AA?

Steven Schveighoffer via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Wed Aug 2 05:20:23 PDT 2017


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


More information about the Digitalmars-d-learn mailing list