Immutable and unique in C#

Sönke Ludwig sludwig at outerproduct.org
Sun Nov 11 10:59:19 PST 2012


Am 11.11.2012 18:20, schrieb Robert Jacques:
> 
> What's wrong with std.typecons.Unique?

 - Does not implicitly cast to immutable
 - Has no way to enforce uniqueness of data referenced within the
contained object
 - Cannot be passed between threads (i.e. in std.concurrency) and if it
would be passable, it would not be safe
 - Does not allow temporal elevation to non-unique in pure contexts
 - No support for arrays and unique partitions

Probably more, but basically in its current form it's mostly useless
apart from documenting the intent. Some of the things can be fixed in
the library type, but to make it really sound and useful, a library
solution is not enough (at least not with the current means that the
language offers).

> By the way, back when concurrency in D was actively being discussed and
> developed, (IIRC) Walter did try to implement unique as a proper type in
> D, but ran into several gotchas.

Do you remember which? All I could find was a thread stating that Walter
did not like the idea of adding an additional transitive type modifier
along const, immutable and shared because of the combinatorial number of
types. Oddly, I could have sworn that I have commented on unique at that
time, but can't find that either.

> In essence, while we all want
> unique/mobile, for unique/mobile to be non-broken it also needs at least
> a lent/scope and an owned type.

The system described in the paper does not need need lent/owned types.
That can be attributed to the fact that their function definition
disallows access of mutable global fields. So as long as only 'pure'
functions operate on a given 'isolated' value, their recovery
rules allow working pretty comfortable, while still statically enforcing
memory isolation.

Calling normal, impure methods or functions would have to break the
'isolated' property and inhibit recovery. This would be the place where
the system with 'lent'/'owned' would allow more freedom, but only at the
cost of a generally higher complexity.

> Ownership type systems are a relatively
> new area of CS and as demonstrated by the paper, still an active area of
> research. The thorny issue of these systems is that you need to
> associate variables with types. For example, this.x = that.y; is only
> valid if x and y are both owned by the same region. This is easy to
> verify at runtime, but not at compile-time.

At least the following assignments can be verified statically using only
local information, no need to track exact memory region ownership:

unique <- unique
immutable <- unique
writable <- unique
writable <- writable

this.x = this.y inside an 'isolated' memory region would be valid as
long as it happens in a pure context and no non-unique/non-immutable
values are passed into the function. Anything else would inhibit
recovery of 'isolated' after the implicit conversion to 'writable' that
is necessary to pass the object to a function/method.

> Anyways, ownership types (or
> whatever supersedes them) were pushed back to D3 and we were left with
> message passing for the common user, synchronized for traditional
> lock-based shared memory and shared for lock-free programming.

Yeah, I'm well aware of that.. unfortunately ;)

This system has the potential to be backward (vs current state) and
forward (vs a full ownership system) compatible, while not affecting
anything of the existing language (like needing to store explicit
ownership information).

However, I have to admit that without actually trying it and seeing how
usable it is first hand, it's difficult to tell how usable it is in
practice (e.g. because D functions have to be explicitly tagged 'pure'
for the recovery to work). Maybe also error messages would be difficult
to understand or something else.


More information about the Digitalmars-d mailing list