On Wednesday, 9 October 2013 at 04:41:35 UTC, Ali Çehreli wrote:
On 10/08/2013 03:03 PM, qznc wrote:

> On Wednesday, 2 October 2013 at 13:09:34 UTC, Daniel Davidson
wrote:
>> 1. If a variable is never mutated, make it const, not
immutable.
>> 2. Make the parameter reference to immutable if that is how
you will
>> use it anyway. It is fine to ask a favor from the caller.
>> ...
>
> I think guideline 1 should be about "arguments" not
"variables".
> Functions should take const arguments, so they can be called
with
> mutable and immutable values.

As demonstrated in the presentation, const erases the actual type. So, the function must take a copy if the argument is to be used in an immutable context.

Instead, if the immutable appears on the interface, that copy will be avoided.


True. But what does it mean to be "used in an immutable context". In your example you pass a variable to a function `void usefulFunction(string s)`. The problem with transitivity is once you start making rules regarding it, those rules must also be transitive (or turtles all the way down as you say). The point is, the desire in the example wants to use the guideline only at the top level and break it at the next level. If usefulFunction were following the guideline it would have a signature `void usefulFunction(const(char)[] s)` instead.

If the guideline were: "if a function parameter is not mutated, make it const" and it were applied that way everywhere, the problem you suggest would not be hit. But we can't go changing any `standardFunction(string s)` to `standardFunction(const(char)[] s)`. Using const on parameters seems to be the prevalent guideline - even though passing strings breaks it.

In regards to parameters, when, if ever, is there benefit to immutable over const (if you assume all called functions from that function have const parameters/signatures). The only reason I can think is if a *member* function wants to hold onto a reference or copy for future use and the designer wants to guarantee that member is truly immutable. An example would be a struct that initializes with an immutable(T) that the struct wants to then use throughout its life.

struct S { this(ref immutable(T) t) { _t = t; } immutable(T) _t; }

This is all very confusing and to me unsettled. I've brought up questions like this many times and have yet to hear Walter or Andrei weigh in. Either we (you and I) are missing something and making things much more difficult than necessary or it is just difficult. I think a third likely possibility is that composition in the face of structs with mutable aliasing is not heavily used by them.

> I would rephrase the second guideline as: "Never dup or idup
an argument
> to make it mutable or immutable, but require the caller to do
this
> (might be able to avoid it)".

Agreed. But it means you agree with me that immutable should indeed appear on function signatures as needed.


I don't really agree. Naturally, if const were used all the way down there would be no need for copies. It is the introduction of immutable (via string in your example) that breaks the rule and causes the pain. But then if the rule were adopted globally - immutable is never used on parameters in a signature, only const is used, when would you start seeing any benefit to the immutable keyword?

> For more guidelines:
>
> 3. Return value, which are freshly created, should never be
const. They
> should be mutable or immutable.

Agreed. I say that it should be mutable if the function is pure, as such a return values is automatically convertible to immutable.

> Basically, I cannot come up with a case, where const would be
preferable
> to mutable and immutable. Maybe someone is able to find a
good example?


I don't know if these are good examples, but they are examples:

From zip.d:
        const(void)[] compress(const(void)[] buf)

From vibe:
        const(Json) opIndex(string key) const {


[snip]

> 4. Data structures should not restrict themselves to be
mutable, const,
> or immutable.

What is the template of a struct that can be used as such? Providing simple values seems to be insufficient:

struct MyInt
{
    int i;
    private int[] history;
}

What else should the struct above have to make it usable as mutable, const, immutable?


I'm confused by the term "usable as mutable, const, immutable"? Isn't it true that types are not mutable, const, immutable in their definition but only in their context?

[snip]

We have to nail this down already. We have this great addition of immutable in the language but we either don't know how to use it or the language is lacking hopefully trivial things to make it work.


Amen, brother!

Either it is a great addition and usable, or it is not so great an addition. At times I find myself questioning even the basic benefit of immutable in the context of sharing. I've heard that immutable is great because it means the data can be shared across threads and you have confidence it will never change. This sounds good. But then you have to choose signatures:

void foo(const(MutableType) mt);
void foo(immutable(MutableType) mt);

Naturally the inclination is to choose the second as it is a stronger guarantee that no threads are changing the data. Cool. But wait, the first one still probably requires the same guarantee, even if it does not state it. If in the const case another thread changes the state of mt during the function foo then it will fail. foo actually requires that mt not be change by other threads during its operation - that is the only sane way of using the data in the function.

Take, for example, LinearCongruentialEngine from random.d. It has a function:

    bool opEquals(ref const LinearCongruentialEngine rhs) const

Why is it using const here instead of immutable? Does it not care about other threads? No - it just is not smart enough to deal with it. It assumes other threads won't be changing it or if they are caveat developer. So when do you use immutable as a signal that not only will this function not change it, no thread will change it either? Probably when you know you have to deal with threading. But that then would be coupling two maybe orthogonal decisions - the threading of a program and the signature of functions.

Where is Scott Myers when you need him :-)


Ali

Reply via email to