Shall I use immutable or const while passing parameters to functions

H. S. Teoh via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Apr 9 22:44:09 PDT 2015


On Fri, Apr 10, 2015 at 05:15:52AM +0000, jkpl via Digitalmars-d-learn wrote:
> On Tuesday, 7 April 2015 at 15:11:39 UTC, tcak wrote:
> >I have data in memory, and I want a function to take a part of data for
> >processing only. It will only read and won't change.
> >
> >char[] importantData;
> >
> >
> >With Immutable,
> >
> >void dataProcessor( string giveMeAllYourData ){}
> >
> >dataProcessor( cast( immutable )( importantData[5 .. 14] ) );
> >
> >
> >
> >With Const,
> >
> >void dataProcessor( in char[] giveMeAllYourData ){}
> >
> >dataProcessor( cast( const )( importantData[5 .. 14] ) );
[...]

It's a very bad idea to cast away immutable or const without
understanding what it does. This breaks the type system and may
introduce subtle bugs into your program, because the compiler may
optimize based on const/immutable, and breaking the type system could
make the optimization break your program.

This diagram may help you understand when to use const:

	       const
	      /     \
	(mutable)    immutable

Basically, what this means is that both mutable and immutable implicitly
converts to const, so you don't need to cast anything to const, you can
just pass it as-is. However, immutable and mutable cannot implicitly
convert to each other, unless the type is a by-value type with no
indirections (in which case it's making a copy, so there is no breakage
of const/immutable).

Unless C++, const in D means *physical* const, that is, you cannot
modify the *entire* data (including everything it points to), even if
semantically modifying, say, a caching member doesn't logically modify
the data. That's why const is transitive. Immutable means the data does
not change, *ever*, after it has been initialized. The compiler is free
to assume that immutable data can be stored in registers even if there
is an intervening function call that takes that data by reference,
because nothing is ever supposed to modify it, not even another thread.
If you randomly cast away immutable, or if you cast something into
immutable but later on somebody modifies it through a mutable reference,
you will break the type system and may cause the compiler to emit wrong
code. The compiler is also free to put immutable data in ROM, which
means you might get a segfault if later on you attempt to modify it
through a casted mutable reference.

So basically, it's a very bad idea to cast away const/immutable or cast
into immutable, unless you know what you're doing. You don't ever need
to cast to const, because you can just assign the data to const
directly. Const means *you*, the holder of the const reference, cannot
modify the data, but somebody else, somewhere else, who has a mutable
reference to it may modify it. Immutable means *nobody* can modify the
data, ever.

In your case, it's enough to use const or in, you don't need a cast. You
should not use immutable if you ever need to pass in mutable data to the
function; that's what const is for. Const means the function cannot
modify the data, but the caller may. Immutable means nobody can modify
the data, which is wrong if the caller holds a mutable reference to it.

Usually, the only time a function needs to take immutable parameters is
when it wants to make sure the *caller* won't modify the data either,
say if the function is caching a hash of the data for later use, and the
hash will get invalidated if the caller can freely modify the data.


T

-- 
Amateurs built the Ark; professionals built the Titanic.


More information about the Digitalmars-d-learn mailing list