D safety! New Feature?
Mark Twain via Digitalmars-d
digitalmars-d at puremagic.com
Tue Aug 2 14:48:58 PDT 2016
One of the biggest problems with memory is that it's inherently
unsafe. We know the solution to that is immutability. Immutable
memory is inherently safe. The problem is that Immutable memory
is useless because it cannot be changed. To make it useful and
safe we have to cheat by creating mutable things then turning
them in to immutable things, which is safe, but generally not the
other way around, which is unsafe.
So, Immutable memory sort of as a direction, that if we follow
it, we are safe, and when we go in the opposite direction, we are
unsafe.
Now, to real world stuff. I was building some container classes
using mixin templates like:
// An Immutable Array Template
template _ImmutableArray(T, A)
{
// Has functionality to create itself from a indexable object
and supply accessor methods for indexing, etc. The typical array
stuff.
}
template _MutableArray(T,A)
{
mixin _ImmutableArray!(T,A);
// Adds stuff so we can mutate the array(change it's length,
remove elements, etc...
}
struct ImmutableArray(T)
{
mixin _ImmutableArray!(T,A);
}
struct MutableArray(T)
{
mixin _MutableArray!(T,A)
}
With such a pattern we can build up a hierarchy of templates that
have corresponding run-time types. We can use introspection by
having things like IsImmutable, etc. Very oop like, but with
static constructs. On top of these we can build stacks(just a
MutableArray), a queue(a MutableArray with Enqueue and Dequeue),
a circular queue(a fixed array(length can't change)), and their
immutable variants.
Now the cool thing about this, I think, is that we can do stuff
like:
global ImmutableArray!int Data;
MutableArray!int DataCopy = Data.Copy; // Creates a mutable copy
of Data.
... Do work with DataCopy ...
Data.Replace(DataCopy); // Makes a copy of DataCopy.
Note that Data is immutable and doesn't even have functionality
that mutate the Data. So we know that we never mutate Data(this
is checked at compile time). Immutable data always has it's own
copy. The difference is that this is a weaker form of standard
immutability. It allows us to logically separate code that
mutates something with the code that doesn't. We can reduce
overhead of allocating relatively simply:
void foo()
{
MutableArray!int Data;
scope(Exit) Data.Reuse();
}
Reuse can simply mark the memory reusable rather then freeing it.
This memory can then be reused the next time foo is called(or
possibly use the stack for memory). Utilities could find optimal
uses for typical program behavior. e.g., foo uses on average 500
bytes for Data. Hence allocate the capacity for Data to 500 bytes.
While compiler support would make this shine, I think the main
benefit is that one doesn't keeps mutable functionality with
mutable data and immutable functionality with immutable data. The
more a program works with immutable the safer it gets. It's
leaving the little dropping of mutable data around that create
the hard to find bugs. It makes it easier to reason about
code(compiler or tool support can make it even better).
Basically all the benefits of immutability as that is all it is
but with a bit more type logic than the keyword.
e.g., If you use intelligent and mark something immutable, You'll
still have "access" visually to all the mutable functionality. If
you don't use intelligent, you'll get a compile time error higher
up the stream that is more meaningful(basically trying to access
a member that doesn't exist in the type).
More information about the Digitalmars-d
mailing list