On Thursday, 4 August 2016 at 13:08:11 UTC, ag0aep6g wrote:
On 08/03/2016 09:33 PM, Mark J Twain wrote:
The built in array is mutable and exposes the same interface for the immutable copy. The only difference is that the immutable copy is marked
immutable.

I don't understand. An immutable array does not let you overwrite elements. A mutable array does. So they have different interfaces, don't they?

My method changes the interface. An "immutable" type has an immutable
interface while a mutable type has a mutable interface.

For simple types, and value types, there is obviously no advantage...
their interfaces are essentially empty/DNE.

Can you show some example code where there is an advantage over built-in arrays?

[...]
As far as I see, "marking for reuse" is practically the same as freeing here. If Data were static, there could be a difference.

For built-in arrays, you can mark an array for reuse by setting the
length to 0 and calling assumeSafeAppend, like so:

No again. Data in the example above is a local variable that allocates memory that would generally be free'ed at the end of the function call. Hence every call to foo results in a malloc/free pair for Data. By
reusing the memory, if possible, one can potentially skip the
malloc/free. Therefore instead of potentially thrashing the memory pool, after a few runs of foo, Data would generally not allocate.

[...]
Your assumeSafeAppend works while the object is in existence. This thing
works between the existence of the object.

The allocator (e.g. the GC) is free to reuse memory it obtained from the operating system. So repeatedly allocating and freeing the same amount of memory can already be faster than one might think.

Of course, the compiler is also free to reuse stuff, if it's guaranteed that no reference escapes the function. I don't expect dmd to do stuff like this. ldc or gdc might.

What do Mutable/ImmutableArray enable beyond this? What do they do that built-in arrays don't? Again, example code would help doofuses like me make sense of this.

The problem is that you have fixated on the *array* and not the general principle. The Array was an example. Get Array out of your mind and think of them as general structures. It could be a queue. D has no built in queue, then what? What if it is a widget, then what? Immutable Widget vs Mutable Widget.

Marking a widget immutable is not the same as having an ImmutableWidget. Can you see the difference? I assure you there is. The immutable keyword only prevents data manipulation, it does not change the interface. For simple primitives, there is not much difference, but for larger complex types, the immutable keyword doesn't cut it.

immutable Queue!int q1;
ImmutableQueue!int q2;

q1.Enqueue(x); // Compile time error if no tricks, but the error is further up the line inside Enqueue, when it actually modifies the data. We can cast away immutability and end up defeating the purpose and end up with run-time problems.

q2.Enqueue(x); // Compile time error, Enqueue doesn't exist in ImmutableQueue. cannot cast away immutable. At most we can convert q2 to a mutable class, which is a copy, then replace q2 with the copy.

There are difference and the second case is better. The error reporting is more accurate and no casting can be done to bypass immutability. We essentially get all this stuff for free if we simply use templates to build the hierarchy and separate the template in to different parts(immutable, mutable, etc).

Now, an ImmutableQueue might not be hugely useful if we have no way to access the data, but it could provide [] access. Again, don't get bogged down in the specifics, I'm talking about general application here. The more complex the type and hierarchy the more useful such a method is and the less useful immutable keyword is.

The immutable keyword is a blind, it only does one thing. Building immutability in to the type system itself allows the programmer to make immutable smarter and control exactly what it does.









Reply via email to