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