guidelines for parameter types

H. S. Teoh hsteoh at quickfur.ath.cx
Tue Dec 18 10:06:40 PST 2012


On Tue, Dec 18, 2012 at 01:51:31PM +0100, Dan wrote:
> On Tuesday, 18 December 2012 at 06:34:55 UTC, Ali Çehreli wrote:
[...]
> >That makes a difference whether V is a value type or not. (It is
> >not clear whether you mean V is a value type.) Otherwise, e.g.
> >immutable(char[]) v has a legitimate meaning: The function
> >requires that the caller provides immutable data.
> 
> When is 'immutable(char[]) v' preferable to 'const(char[]) v'? If
> you select 'const(char[]) v' instead, your function will not mutate
> v and if it is generally a useful function it will even accept
> 'char[]' that *is* mutable. I agree with the meaning you suggest,
> but under what circumstances is it important to a function to know
> that v is immutable as opposed to simply const?

It's not just about whether the function mutates something or not.
Sometimes the function counts on the data not changing, ever. For
example, if you're implementing a library AA type, you'd want the key to
be immutable so that whatever hash value you computed for the bucket
will not suddenly become invalid just because the user changed it from
underneath you:

	// Problematic example
	struct AA {
		struct Bucket {
			const(char)[] key;
			uint  hash;
			const(char)[] value;

			Bucket* next;
		}
		Bucket*[] htable;

		void addEntry(const(char)[] key, const(char)[] value) {
			// N.B.: Bucket now stores a reference to key
			auto buck = new Bucket(key, hashof(key), value);

			// The validity of this depends on the
			// referenced key not changing, ever.
			htable[buck.hash % htable.length] = buck;
		}

		const(char)[] opIndex(const(char)[] key) {
			auto hash = hashof(key);
			auto buck = htable[hash % htable.length];
			while (buck) {
				if (buck.key == key)
					return buck.value;
				buck = buck.next;
			}
			// throw out of bounds error here
		}
	}
	void main() {
		AA aa;
		char[] myKey = "abc";

		// OK: char[] implicitly converts to const(char)[].
		aa.addEntry(myKey, "some value");

		myKey[0] = 'c';	// <--- oops! now the entry's Bucket is wrong!

		auto v = aa["abc"];	// this will throw, 'cos the
					// right slot is found but the
					// entry's .key value has
					// changed, so it won't match

		auto u = aa["cbc"];	// in all likelihood, this will
					// also throw because the hash
					// of "cbc" is unlikely to be
					// equal to the hash of "abc" so
					// we won't find the right slot
	}

In this case, the key passed to .addEntry *must* be immutable. That's
the only way to guarantee that the AA's internal structures won't get
invalidated by outside code.


T

-- 
Skill without imagination is craftsmanship and gives us many useful objects such as wickerwork picnic baskets.  Imagination without skill gives us modern art. -- Tom Stoppard


More information about the Digitalmars-d-learn mailing list