@trust is an encapsulation method, not an escape

Walter Bright via Digitalmars-d digitalmars-d at puremagic.com
Thu Feb 5 20:39:47 PST 2015


On 2/5/2015 8:20 PM, Dicebot wrote:
> I am not even sure how you can show the example though, to be honest - implied
> issues are about maintaining code and not just writing it.

Let's start with std.array.uninitializedArray():

    auto uninitializedArray(T, I...)(I sizes) nothrow @trusted

Note how it says it is 'trusted'. Yet it can be used to create an uninitialized 
array of pointers! There is no freakin' way this function should pass muster. 
Worse, multiple modules use it:

array.d:            return uninitializedArray!(Unqual!E[])(n);
array.d:auto uninitializedArray(T, I...)(I sizes) nothrow @trusted
array.d:    double[] arr = uninitializedArray!(double[])(100);
array.d:    double[][] matrix = uninitializedArray!(double[][])(42, 31);
array.d:    auto s1 = uninitializedArray!(int[])();
array.d:            return uninitializedArray!(T[])(n);
array.d:        auto result = uninitializedArray!(RetTypeElement[])(length);
array.d:            auto result = uninitializedArray!(RetTypeElement[])(length);
array.d:        auto result = uninitializedArray!(RetTypeElement[])(length);
file.d:    import std.array : uninitializedArray;
file.d:        auto buf = uninitializedArray!(ubyte[])(size);
file.d:        void[] result = uninitializedArray!(ubyte[])(initialAlloc);
numeric.d:    import std.array : uninitializedArray;
numeric.d:        auto memSpace = uninitializedArray!(lookup_t[])(2 * size);
numeric.d:        ret = uninitializedArray!(Complex!F[])(range.length);
numeric.d:        ret = uninitializedArray!(Complex!F[])(range.length);
parallelism.d:                auto buf = uninitializedArray!(MapType!(Args[0], 
functions)[])(len);
parallelism.d:                    temp = uninitializedArray!Temp(workUnitSize);
parallelism.d:                    temp = uninitializedArray!Temp(workUnitSize);
stdio.d:    import std.array : appender, uninitializedArray;
stdio.d:                buf = uninitializedArray!(char[])(i);
stdio.d:                buf = uninitializedArray!(char[])(i);
stdio.d:    import std.array : appender, uninitializedArray;
utf.d:        import std.array : uninitializedArray;
utf.d:        auto copy = uninitializedArray!(Unqual!OutChar[])(str.length + 1);

So I already know there are serious problems. Looking closer, I see there's 
another function:

auto minimallyInitializedArray(T, I...)(I sizes) nothrow @trusted

which initializes everything to 0, pointers and all. I agree this one can be 
trusted. The difference between their implementations is a parameter they pass 
to arrayAllocImpl(), which says whether to 0 it or not.

But really, it's only pointer types (and types composed of pointers) that make 
it system code. Since uninitializedArray() is a template, we can have two 
implementations for it that are statically selected based on the element type.
One is @system, when E is a type that contains a pointer. The other is @trusted, 
when E is not a pointer.

That solves that problem without great effort.

Upstream of uninitializedArray(), the only problem then is when it is called to 
generate an uninitialized array of pointers. In order to make the call safe, the 
caller must then ensure that the array gets initialized with safe values. And 
that code should be properly marked as @trusted, and not before.

I.e. start at the bottom, and work up until you find the right place to make it 
trusted. Rinse, repeat. I am not seeing where the problem with doing this is.


More information about the Digitalmars-d mailing list