On Thursday, 4 August 2016 at 18:58:18 UTC, ag0aep6g wrote:
On 08/04/2016 08:22 PM, Mark J Twain wrote:
The problem is that you have fixated on the *array* and not the general
principle. The Array was an example.

I'm having trouble understanding what you're getting at, so I'm trying to get it from the example you gave. If there's merit in your idea, then surely you can give a example where it provides benefit over the immutable keyword.

Get Array out of your mind and
think of them as general structures. It could be a queue.

Ok.

D has no built
in queue, then what?

You can still have an immutable queue, or a queue of immutable elements. Just like with arrays.

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?

No.

I assure you there is.

Please show.

The immutable keyword
only prevents data manipulation, it does not change the interface.

I'm still not sure what that means. An immutable object does not have mutating operations in its interface. A mutable object does. So the interfaces are different.

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.

Not true. Since Enqueue isn't marked const or immutable, it can't be called on an immutable object. The compiler rejects the call itself. It doesn't reject the mutation that happens inside Enqueue, because that's perfectly fine in a non-const, non-immutable method.

In code:

----
struct Queue
{
    void Enqeue(int dummy) {}
}

void main()
{
    Queue m;
    m.Enqeue(1);
    immutable Queue i;
i.Enqeue(2); /* Error: mutable method test.Queue.Enqeue is not callable using a immutable object */
}
----

We can cast away immutability and end up defeating the purpose and end
up with run-time problems.

You can break everything with casts, yes.

q2.Enqueue(x);  // Compile time error, Enqueue doesn't exist in
ImmutableQueue.

It doesn't exist for an immutable Queue, either.

cannot cast away immutable.

You can still cast from ImmutableQueue to MutableQueue.

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.

Sorry, but I still don't see what ImmutableWhatever does that `immutable Whatever` can't do. As far as I see, your example about having better error locations is wrong.

Ok, Simple:

immutable does not remove the interface! Regardless of how you are thinking about it, your exmaple, i still have Enqueue. Only the compiler has stopped compiling.

struct Queue
{
    void Enqeue(int dummy) {}
}

void main()
{
    Queue m;
    m.Enqeue(1);
    immutable Queue i;
i.Enqeue(2); /* Error: mutable method test.Queue.Enqeue is not callable using a immutable object */
}

In the case of ImmutableQueue, There is no Enqueue!

See, there is a difference between "not callable" and "does not exists". It seems maybe minor, and maybe it is, but immutability and "Immutability" are not exactly the same. I actually think they would work well together, and of course, a lot of overlap exist.

`immutability` only logically makes something immutable, as it can easily be proved. One can cast out immutable and mutate very easily(take address, change values). `Immutable` cannot be cast because there is no type relationship. Any time a change has to be made to an Immutable object, a copy is created. Of course, one could call this a "long winded cast", but it's more safe and requires more verbosity, hence less ambiguity and therefore less problems.

Again, there is a lot of overlap, I'm not claiming this replaces `immutable`. But it does things that immutable doesn't. I'm not even claiming it is perfect in and of itself. After all, it is somewhat arbitrary. One has to design the templates to be immutable, and if they are not then it means nothing and just represents different types(e.g., ImmutableQueue vs Queue means nothing unless ImmutableQueue is truly an immutable type of Queue, which can only be designed properly designed with intent).

What I would say to you is, either try it on some examples, or don't. I'm not trying to take away your favorite blanket... just present another tool for solving some problems. If you don't like it, that's fine, don't use it. Don't get upset, it won't affect your world if you don't want it to. For those that see some use out of it, use it, else don't. Simple as that.









Reply via email to