On 8/17/18 3:36 AM, Atila Neves wrote:
Here's a struct:
-----------------
struct MyStruct {
import core.stdc.stdlib;
int* ints;
this(int size) @trusted { ints = cast(int*) malloc(size); }
~this() @trusted { free(ints); }
scope int* ptr() { return ints; }
}
-----------------
Let's try and be evil with -dip1000:
-----------------
@safe:
// struct MyStruct ...
const(int) *gInt;
void main() {
auto s = MyStruct(10);
gInt = s.ptr;
}
-----------------
% dmd -dip1000 scope_inout.d
scope_inout.d(26): Error: scope variable this may not be returned
Yay!
What if instead of `auto` I write `const` instead (or immutable)? This
is D we're talking about, so none of this boilerplate nonsense of
writing two (or three) basically identical functions. So:
-----------------
// used to be scope int* ptr() { return ints; }
scope inout(int)* ptr() inout { return ints; }
Does scope apply to the return value or the `this` reference?
What happens if you remove the return type? (i.e. scope auto)
-----------------
% dmd -dip1000 scope_inout.d
% echo $?
0
# nope, no error here
Wait, what? Turns out now it compiles. After some under-the-breath
mumbling I go hit issues.dlang.org and realise that the issue already
exists:
https://issues.dlang.org/show_bug.cgi?id=17935
I don't see what this bug report has to do with the given case.
For reasons unfathomable to me, this is considered the _correct_
behaviour. Weirder still, writing out the boilerplate that `inout` is
supposed to save us (mutable, const and immutable versions) doesn't
compile, which is what one would expect.
So: @safe + inout + scope + dip1000 + custom memory allocation in D gets
us to the usability of C++ circa 1998. At least now we have valgrind and
asan I guess.
"What about template this?", I hear you ask. It kinda works. Sorta.
Kinda. Behold:
------------
scope auto ptr(this T)() { return ints; }
------------
After changing the definition of `ptr` this way the code compiles fine
and `ints` is escaped. Huh. However, if you change `auto s` to `scope
s`, it fails to compile as <insert deity> intended. Very weird.
This seems like a straight up bug.
If you change the destructor to `scope` then it also fails to compile
even if it's `auto s`. Because, _obviously_, that's totally different.
I'd file an issue but given that the original one is considered not a
bug for some reason, I have no idea about what I just wrote is right or
not.
What I do know is I found multiple ways to do nasty things to memory
under the guise of @safe and -dip1000, and my understanding was that the
compiler would save me from myself. In the meanwhile I'm staying away
from `inout` and putting `scope` on my destructors even if I don't quite
understand when destructors should be `scope`. Probably always? I have
no idea.
This doesn't surprise me. I'm beginning to question whether scope
shouldn't have been a type constructor instead of a storage class. It's
treated almost like a type constructor in most places, but the language
grammar makes it difficult to be specific as to what part it applies.
-Steve