Thread overview | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
November 07, 2016 Are contracts intended for verifying @safety; | ||||
---|---|---|---|---|
| ||||
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? |
November 07, 2016 Re: Are contracts intended for verifying @safety; | ||||
---|---|---|---|---|
| ||||
Posted in reply to Somebody | 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 ... */);
}
|
November 07, 2016 Re: Are contracts intended for verifying @safety; | ||||
---|---|---|---|---|
| ||||
Posted in reply to ag0aep6g | 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.
|
November 07, 2016 Re: Are contracts intended for verifying @safety; | ||||
---|---|---|---|---|
| ||||
Posted in reply to Somebody | ...and it would, unlike enforce(), of course throw an Error instead of an Exception. |
November 07, 2016 Re: Are contracts intended for verifying @safety; | ||||
---|---|---|---|---|
| ||||
Posted in reply to Somebody | 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
|
November 07, 2016 Re: Are contracts intended for verifying @safety; | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | 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 Davis I reckon you meant marking the calling function @safe? |
November 07, 2016 Re: Are contracts intended for verifying @safety; | ||||
---|---|---|---|---|
| ||||
Posted in reply to Somebody | 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-versions > 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. You're probably aware of it, but just to be sure: Note that -noboundscheck (or -boundscheck=off) absolutely breaks safety. |
November 07, 2016 Re: Are contracts intended for verifying @safety; | ||||
---|---|---|---|---|
| ||||
Posted in reply to ag0aep6g | 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.
|
November 07, 2016 Re: Are contracts intended for verifying @safety; | ||||
---|---|---|---|---|
| ||||
Posted in reply to Somebody | On Monday, November 07, 2016 20:38:00 Somebody via Digitalmars-d-learn wrote:
> > 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.
> >
> I reckon you meant marking the calling function @safe?
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 Davis
|
November 07, 2016 Re: Are contracts intended for verifying @safety; | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | 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 Davis
Oh, 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.
|
Copyright © 1999-2021 by the D Language Foundation