digitalmars.D.learn - Best way to make a template function conditionally trusted
- tsbockman (10/10) Apr 01 2021 Suppose I have a templated struct member function for which I can
- Paul Backus (18/29) Apr 01 2021 Here's a technique I've used:
- tsbockman (2/9) Apr 01 2021 Thanks. That is somewhat better than my version.
- ikod (5/9) Apr 02 2021 Compiler should be able to derive safety of templated functions.
- tsbockman (41/48) Apr 03 2021 The compiler's approach to verifying memory safety is very
Suppose I have a templated struct member function for which I can compute at compile-time when the function is memory safe, and when it is not. But, the compiler cannot correctly determine this automatically. What is the best way to express this in code? Other than straight-up duplicating the implementation, the only answer I've come up with so far is to create a `private system` implementation function, and then separate `public system` and `public trusted` wrappers with appropriate template constraints. Is there a better way?
Apr 01 2021
On Thursday, 1 April 2021 at 22:35:01 UTC, tsbockman wrote:Suppose I have a templated struct member function for which I can compute at compile-time when the function is memory safe, and when it is not. But, the compiler cannot correctly determine this automatically. What is the best way to express this in code? Other than straight-up duplicating the implementation, the only answer I've come up with so far is to create a `private system` implementation function, and then separate `public system` and `public trusted` wrappers with appropriate template constraints. Is there a better way?Here's a technique I've used: // infer function attributes auto func(...) { // do your compile-time memory-safety check here enum bool shouldBeSystem = ...; static if (shouldBeSystem) { // force inference of system cast(void) () system {}(); } () trusted { // rest of code goes here }(); } As long as the compile-time check is correct, this is sound: the trusted lambda can be called from safe code if and only if `shouldBeSystem == false`.
Apr 01 2021
On Friday, 2 April 2021 at 00:03:32 UTC, Paul Backus wrote:On Thursday, 1 April 2021 at 22:35:01 UTC, tsbockman wrote:Thanks. That is somewhat better than my version.Is there a better way?Here's a technique I've used: ... As long as the compile-time check is correct, this is sound: the trusted lambda can be called from safe code if and only if `shouldBeSystem == false`.
Apr 01 2021
On Thursday, 1 April 2021 at 22:35:01 UTC, tsbockman wrote:Suppose I have a templated struct member function for which I can compute at compile-time when the function is memory safe, and when it is not. But, the compiler cannot correctly determine this automatically.Compiler should be able to derive safety of templated functions. You may just omit safe/ trusted. But there are some rules and restrictions: https://dlang.org/spec/function.html#function-attribute-inference
Apr 02 2021
On Friday, 2 April 2021 at 19:49:30 UTC, ikod wrote:On Thursday, 1 April 2021 at 22:35:01 UTC, tsbockman wrote:The compiler's approach to verifying memory safety is very simplistic: it declares a function non-` safe` if any potentially unsafe operation is found in its implementation, without regard for the context. It can only ever infer ` safe` or ` system`, never ` trusted`. The reason ` trusted` is in the language at all is to allow the programmer to manually mark as memory safe those functions which contain operations that would be unsafe in some other context, but which the programmer has manually analyzed and verified to be incapable of violating memory safety, no matter what inputs it receives. Consider the following program: ```D import std.stdio; void writeSafe()(int[2] stuff ...) { foreach(n; 0 .. stuff.length) writeln(stuff[n]); } void writeTrusted()(int[2] stuff ...) { foreach(n; 0 .. stuff.length) writeln(stuff.ptr[n]); } void main() safe { writeSafe(3, 5); writeTrusted(3, 5); } ``` `writeSafe` and `writeTrusted` generate identical code, and are equally memory safe in reality. The compiler even knows this on some level, because it correctly deduces that the bounds check for `stuff[n]` can never fail, and omits it even in `writeSafe`. Nevertheless, because `.ptr` can be used to violate memory safety in other contexts, `writeSafe` is inferred as ` safe`, while `writeTrusted` is inferred as ` system`. And so, the program above will not compile as it stands. This is, of course, a trivial example where there is no benefit to using the non-` safe` version, but there are more complex cases where the desired algorithm is memory safe as a whole, but it cannot be expressed in D without using some operations that are forbidden in ` safe` code.Suppose I have a templated struct member function for which I can compute at compile-time when the function is memory safe, and when it is not. But, the compiler cannot correctly determine this automatically.Compiler should be able to derive safety of templated functions. You may just omit ` safe`/` trusted`.
Apr 03 2021