Bartosz Milewski seems to like D more than C++ now :)

H. S. Teoh hsteoh at quickfur.ath.cx
Fri Sep 20 13:42:10 PDT 2013


On Fri, Sep 20, 2013 at 11:04:10AM -0700, Jonathan M Davis wrote:
[...]
> So, in D, if you have a member function that returns a range, the only
> way that it can return a non-const range is if it's able to convert
> the fully const range to a tail-const one (i.e. the range itself is
> non-const but what it refers to is still const). That can easily be
> done by creating an entirely new range from the original (e.g. convert
> it to an array and return that), but converting a const range to a
> tail-const one is very difficult to do with user- defined types.
> 
> To do that, we need to be able to convert const(Range!Foo) to
> Range!(const Foo), and thanks to how templates work those are
> completely different template instantations (meaning that technically,
> they don't necessarily have anything do with each other - e.g. their
> internal layout could be completely different), so the compiler can't
> assume that that conversion will work. You have to write it yourself,
> which quickly runs into problems with recursive template
> instantiations and the like. I believe that it can be done with the
> proper use of static if, but it does mean that you have to know what
> you're doing. It's not straightforward, and the last time that I
> attempted it, I failed.
> 
> This is in stark contrast to arrays, where the compiler knows fulwell
> that it can convert const(int[]) to const(int)[] without causing any
> problems.
[...]

Yeah, this is one of the areas of D's const system that irks me. It's
annoying to deal with even outside of ranges. For example, if you want
to traverse the container (from inside a member function), if the member
function is const, then all references to the container's internal
objects are const:

	class Tree {
		Node* root;
		const(Node)* find() const {
			// curNode is inferred as const(Node*), i.e.,
			// the pointer itself is const, since root is a
			// member of const(Tree).
			auto curNode = root;
			while (someCond) {
				// NG: can't modify a const ptr
				curNode = curNode.left;
			} else {
				// NG: can't modify a const ptr
				curNode = curNode.right;
			}
			...
			// NG: can't convert const(Node*) to
			// const(Node)*.
			return curNode;
		}
	}

The workaround is to explicitly state the type of curNode as tail-const:

	const(Node)* curNode = root;
	...

This is a very simple case, and it's already ugly. Once the code gets
more complex, the problem becomes uglier. For example, because inout is
treated just like const, inout member functions suffer from the same
problem. When you then throw in user-defined types that have
const/immutable members, the waters get even murkier.


T

-- 
Bare foot: (n.) A device for locating thumb tacks on the floor.


More information about the Digitalmars-d mailing list