On 5/13/15 8:00 PM, Jakob Ovrum wrote:
On Wednesday, 13 May 2015 at 17:49:38 UTC, Steven Schveighoffer wrote:
OK, then consider that this:

void main()
{
   string x;
   x ~= "hello";
   x ~= " world";
}

would require locking. That's unacceptable. Nobody would append with
strings if this all required locking for no reason. The runtime
currently does NOT lock for this case, it considers immutable and
const to be thread-local.

Well, it's necessary because the design of druntime arrays is
incompatible with D2's type system. Without locking, multi-threaded
applications that use dynamic array operations could easily contain some
particularly hard to track concurrency bugs.

I don't think we should go there. I would say it's very unlikely to have this bug occur, but you are right it could occur. I just don't think destroying append performance for all const and immutable array types is worth it to fix the bug opportunity.

No, I think the answer is simpler. Introduce shared(immutable), and
then we can distinguish between immutable data that is shared and data
that is not shared. It also makes implementing local heaps easier.
Shared really is orthogonal to mutability.

Basically, shared(immutable(T)) would only be useful to allocators,
including arrays because they may need to allocate when growing. I don't
think it would be useful beyond that; the sharedness of immutable data
is probably not interesting to any other kind of code.

Yes, it really only matters for cases where the immutable pointer can be used to obtain mutable data. But these are important cases.

The fact that most code doesn't share *at all*, makes it less of an issue. Perhaps we need some way to indicate that when an array is shared, it can no longer be appended in-place. It would be as simple as flipping the APPENDABLE bit. The problem is, you're not always passing the immutable array directly.

It would make immutable considerably harder to use than it is today.
shared(immutable(T)) would be implicitly convertible to
shared(const(T)), but not const(T), which precludes the vast majority of
mutation-agnostic D code out there today (I have never seen
shared(const(T)) used in the wild). We would no longer be able to do
even the simplest things, like passing a path string to another thread
and use std.file.read on it.

Yeah, there is no attribute that takes shared/unshared. I don't know a good solution to that, and I understand that shared(immutable) screws up most usages for immutable. It's not a good answer.

The problem is that when you share an immutable pointer, it changes the rules for that pointer, but no type information has been altered. It's impossible to track.

I think the idea of making immutable not shared by default is probably not a good answer, but I don't know of a good one. I have a feeling whatever answer we choose is going to be really painful :(

-Steve

Reply via email to