digitalmars.D.learn - Are contracts intended for verifying safety;
- Somebody (8/8) Nov 07 2016 void moveFrom(int[] a, in int[] b) @trusted in{
- ag0aep6g (12/19) Nov 07 2016 No, it's not ok. Contracts and (most) asserts are not included in
- Somebody (7/18) Nov 07 2016 Can the version switch be used to detect noboundscheck? I was
- Jonathan M Davis via Digitalmars-d-learn (39/47) Nov 07 2016 That's a matter of debate. What you're saying is that the contract for t...
- Somebody (9/50) Nov 07 2016 All pure functions which a programmer, save for a blackhat
- Jonathan M Davis via Digitalmars-d-learn (9/15) Nov 07 2016 No. @trusted. The calling function could only be marked @safe if the cal...
- Somebody (5/13) Nov 07 2016 Oh, I see. I think I prefer to use the modified enforce trough
void moveFrom(int[] a, in int[] b) trusted in{ assert(a.length >= b.length); } body { memmove(cast(void*)a.ptr, cast(void*)b.ptr, b.length * int.sizeof); } Is this ok? And if not, how should it be done, preferably without changing the condition or memmove call?
Nov 07 2016
On 11/07/2016 06:30 PM, Somebody wrote:void moveFrom(int[] a, in int[] b) trusted in{ assert(a.length >= b.length); } body { memmove(cast(void*)a.ptr, cast(void*)b.ptr, b.length * int.sizeof); } Is this ok? And if not, how should it be done, preferably without changing the condition or memmove call?No, it's not ok. Contracts and (most) asserts are not included in release builds, but the rules for safe/ trusted don't change. So you'd be breaking safe in release builds. You can use std.exception.enforce instead, in the body instead of a contract: void moveFrom(int[] a, in int[] b) trusted { import std.exception: enforce; enforce(a.length >= b.length); memmove(/* ... as above ... */); }
Nov 07 2016
On Monday, 7 November 2016 at 19:30:01 UTC, ag0aep6g wrote:No, it's not ok. Contracts and (most) asserts are not included in release builds, but the rules for safe/ trusted don't change. So you'd be breaking safe in release builds. You can use std.exception.enforce instead, in the body instead of a contract: void moveFrom(int[] a, in int[] b) trusted { import std.exception: enforce; enforce(a.length >= b.length); memmove(/* ... as above ... */); }Can the version switch be used to detect noboundscheck? I was thinking that if, it could be used to make an overload of enforce that acts just like in your example, but is taken off with bounds checking. Then it would not violate safety any more than arrays do, yet could be compiled to as efficient a release build as the contract version, if needed.
Nov 07 2016
...and it would, unlike enforce(), of course throw an Error instead of an Exception.
Nov 07 2016
On 11/07/2016 09:16 PM, Somebody wrote:Can the version switch be used to detect noboundscheck?Apparently, yes: `version (D_NoBoundsChecks)`. http://dlang.org/spec/version.html#predefined-versionsI was thinking that if, it could be used to make an overload of enforce that acts just like in your example, but is taken off with bounds checking. Then it would not violate safety any more than arrays do, yet could be compiled to as efficient a release build as the contract version, if needed.You're probably aware of it, but just to be sure: Note that -noboundscheck (or -boundscheck=off) absolutely breaks safety.
Nov 07 2016
On Monday, 7 November 2016 at 20:42:26 UTC, ag0aep6g wrote:Apparently, yes: `version (D_NoBoundsChecks)`. http://dlang.org/spec/version.html#predefined-versions You're probably aware of it, but just to be sure: Note that -noboundscheck (or -boundscheck=off) absolutely breaks safety.Yes I am. Using that is in my understanding unwise in any trivial project. Thanks for your help and the warning. This anyway seems to let choose the best tradeoff when compiling, unlike enforce, assert in system or my original contracted version.
Nov 07 2016
On Monday, November 07, 2016 17:30:09 Somebody via Digitalmars-d-learn wrote:void moveFrom(int[] a, in int[] b) trusted in{ assert(a.length >= b.length); } body { memmove(cast(void*)a.ptr, cast(void*)b.ptr, b.length * int.sizeof); } Is this ok? And if not, how should it be done, preferably without changing the condition or memmove call?That's a matter of debate. What you're saying is that the contract for the function requires certain conditions be true for the function arguments, and if they are true, then the function is safe. And that's legitimate. But at the same time, it doesn't absolutely guarantee safety, because if the caller passes arguments that violate the contract, and the function is compiled with -release, then unsafe things will occur. So, you could mark the function as system, and then make it clear in the documentation that the function's safety depends on the function's arguments meeting the pre-condition. So, the caller then knows when they can mark the call as being trusted. There have been several discussions about trusted over the last couple of years (both in the newsgroup and on github), and I don't know what the official stance on this sort of thing currently is. I know that at one point, it was argued that trusted functions were safe so long as their arguments were valid, but then you get stuff like auto foo(int* arr, size_t index) trusted { return *(arr + index); } or auto foo(int* arr, size_t length) trusted { return arr[0 .. length]; } or auto foo(int[], size_t index) trusted { return *(arr.ptr + index); } and it doesn't seem like a good idea to me to mark functions like that as trusted. It's too much like you're trying to have array indexing be marked as trusted while circumventing the array bounds checks without any guarantee that the values are going to be valid. So, while I don't know what the official stance is, I'd suggest having the function be trusted and having the documentation make it clear what the preconditions are so that the calling function can be marked trusted. - Jonathan M Davis
Nov 07 2016
On Monday, 7 November 2016 at 20:24:25 UTC, Jonathan M Davis wrote:That's a matter of debate. What you're saying is that the contract for the function requires certain conditions be true for the function arguments, and if they are true, then the function is safe. And that's legitimate. But at the same time, it doesn't absolutely guarantee safety, because if the caller passes arguments that violate the contract, and the function is compiled with -release, then unsafe things will occur. So, you could mark the function as system, and then make it clear in the documentation that the function's safety depends on the function's arguments meeting the pre-condition. So, the caller then knows when they can mark the call as being trusted. There have been several discussions about trusted over the last couple of years (both in the newsgroup and on github), and I don't know what the official stance on this sort of thing currently is. I know that at one point, it was argued that trusted functions were safe so long as their arguments were valid, but then you get stuff like auto foo(int* arr, size_t index) trusted { return *(arr + index); } or auto foo(int* arr, size_t length) trusted { return arr[0 .. length]; } or auto foo(int[], size_t index) trusted { return *(arr.ptr + index); } and it doesn't seem like a good idea to me to mark functions like that as trusted. It's too much like you're trying to have array indexing be marked as trusted while circumventing the array bounds checks without any guarantee that the values are going to be valid.All pure functions which a programmer, save for a blackhat perhaps, has any reason to use are safe with correct arguments. So we would have no use for safe when we have pure, were that argument about arguments wise to follow. So I agree with you that they definitely would be a bad idea without contracts. However, with contracts, as you said, it is less clear.So, while I don't know what the official stance is, I'd suggest having the function be trusted and having the documentation make it clear what the preconditions are so that the calling function can be marked trusted. - Jonathan M DavisI reckon you meant marking the calling function safe?
Nov 07 2016
On Monday, November 07, 2016 20:38:00 Somebody via Digitalmars-d-learn wrote:No. trusted. The calling function could only be marked safe if the callee were trusted, and I was suggesting that it be marked system so that it's then clear to the caller that they need to pass the correct arguments for it to be okay to treat it as safe and mark the caller as trusted. If need be, the contract can be documented to make it clear what's required for it to be reasonable to mark the caller as trusted. - Jonathan M DavisSo, while I don't know what the official stance is, I'd suggest having the function be trusted and having the documentation make it clear what the preconditions are so that the calling function can be marked trusted.I reckon you meant marking the calling function safe?
Nov 07 2016
On Monday, 7 November 2016 at 21:05:32 UTC, Jonathan M Davis wrote:No. trusted. The calling function could only be marked safe if the callee were trusted, and I was suggesting that it be marked system so that it's then clear to the caller that they need to pass the correct arguments for it to be okay to treat it as safe and mark the caller as trusted. If need be, the contract can be documented to make it clear what's required for it to be reasonable to mark the caller as trusted. - Jonathan M DavisOh, I see. I think I prefer to use the modified enforce trough (see above), so I have no need to make trusted layers in the calling site. Thanks anyway.
Nov 07 2016