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