February 27, 2018
On Tuesday, 27 February 2018 at 12:39:04 UTC, Jonathan M Davis wrote:
> On Tuesday, February 27, 2018 04:20:38 Timothee Cour via Digitalmars-d wrote:
>> [...]
>
> Except that that's really not how @trusted is supposed to be used. The programmer needs to verify that the caller is using a.ptr in a manner that is actually @safe, because the compiler is not smart enough to determine that for you. Wrapping it in an @trusted function means that the caller won't get an error and that the programmer won't necessarily know that they need to verify the calling code. It's the code that's using ptr that needs to be verified, not the actual accessing of ptr.
>
> Hiding the access to ptr within an @trusted function goes against that entire idea of @trusted and makes it easy to use ptr without realizing that you need to be checking the code that's using it, since you just called a wrapper function to silence the compiler instead of listening the compiler and studying the code using ptr to verify its @safety.
>
>> [...]
>
> In almost all cases, &a[0] is equivalent to a.ptr except that it does bounds checking, so it's actually @safe and thus doesn't need to be manually verified by the programmer, unlike your pointer function suggestion.

There's a common case where it's not equivalent - when the pointer is null. Imagine I have a C function I want to call:

extern(C) void fun(int* things);

Imagine also that it's ok to call with null. Well, now I can't use a slice to call this and have it be 1) @safe and 2) not throw RangeError. I ran into this the other way.

Atila
February 27, 2018
On 02/27/2018 06:32 PM, Atila Neves wrote:
> On Tuesday, 27 February 2018 at 12:39:04 UTC, Jonathan M Davis wrote:
[...]
>> In almost all cases, &a[0] is equivalent to a.ptr except that it does bounds checking, so it's actually @safe and thus doesn't need to be manually verified by the programmer, unlike your pointer function suggestion.
> 
> There's a common case where it's not equivalent - when the pointer is null. Imagine I have a C function I want to call:
> 
> extern(C) void fun(int* things);
> 
> Imagine also that it's ok to call with null. Well, now I can't use a slice to call this and have it be 1) @safe and 2) not throw RangeError. I ran into this the other way.

As Jonathan says, you have to manually verify that it's safe, because it generally isn't. `arr.ptr` can be invalid but not null, even in @safe code.

Consider:

----
void fun(int* things) @safe
{
    int x = things is null ? 0 : *things;
    import std.stdio;
    writeln(x);
}

void main()
{
    int[] arr;
    fun(arr.ptr); /* Ok, prints "0". */

    arr = [1, 2, 3];
    fun(arr.ptr); /* Ok, prints "1".*/

    arr = arr[$ .. $]; /* This is @safe. */
    fun(arr.ptr); /* Not ok, prints garbage. */
}
----

The first two calls are actually safe and can be @trusted. The third call is invalid and must not be possible in @safe code.

Maybe it would be possible require `arr.ptr` to be valid or null in @safe code. This would outlaw `arr[$ .. $]` and bounds checking would have to catch it. I don't know if that would be any practical than banning `arr.ptr`.
February 27, 2018
On 2/27/18 12:32 PM, Atila Neves wrote:

> There's a common case where it's not equivalent - when the pointer is null. Imagine I have a C function I want to call:
> 
> extern(C) void fun(int* things);
> 
> Imagine also that it's ok to call with null. Well, now I can't use a slice to call this and have it be 1) @safe and 2) not throw RangeError. I ran into this the other way.

fun(x.length ? &x[0] : null);

I think even the compiler could elide the bounds check since you already did it, but I'm not sure that actually happens.

-Steve
February 27, 2018
On 2/27/18 3:00 PM, Steven Schveighoffer wrote:
> On 2/27/18 12:32 PM, Atila Neves wrote:
> 
>> There's a common case where it's not equivalent - when the pointer is null. Imagine I have a C function I want to call:
>>
>> extern(C) void fun(int* things);
>>
>> Imagine also that it's ok to call with null. Well, now I can't use a slice to call this and have it be 1) @safe and 2) not throw RangeError. I ran into this the other way.
> 
> fun(x.length ? &x[0] : null);

Hm... borrowing from Timothee's suggestion:

@trusted @nogc pure nothrow
T* pointer(T)(T[] a){
   return a.length > 0 ? a.ptr : null;
}

This would be fine and @safe, but may not be useful for all purposes. However, it would fix your issue.

-Steve
February 27, 2018
> Hm... borrowing from Timothee's suggestion:
> This would be fine and @safe, but may not be useful for all purposes. However, it would fix your issue.


how about this: https://github.com/dlang/phobos/pull/6231

On Tue, Feb 27, 2018 at 12:09 PM, Steven Schveighoffer via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On 2/27/18 3:00 PM, Steven Schveighoffer wrote:
>>
>> On 2/27/18 12:32 PM, Atila Neves wrote:
>>
>>> There's a common case where it's not equivalent - when the pointer is null. Imagine I have a C function I want to call:
>>>
>>> extern(C) void fun(int* things);
>>>
>>> Imagine also that it's ok to call with null. Well, now I can't use a slice to call this and have it be 1) @safe and 2) not throw RangeError. I ran into this the other way.
>>
>>
>> fun(x.length ? &x[0] : null);
>
>
> Hm... borrowing from Timothee's suggestion:
>
> @trusted @nogc pure nothrow
> T* pointer(T)(T[] a){
>    return a.length > 0 ? a.ptr : null;
> }
>
> This would be fine and @safe, but may not be useful for all purposes. However, it would fix your issue.
>
> -Steve
February 27, 2018
On Tuesday, 27 February 2018 at 11:33:04 UTC, Simen Kjærås wrote:
> That only checks if the first element is the same. For a full 'is slice' check you'd need something like this:
>
>     assert(a.ptr <= b.ptr && b.ptr + b.length <= a.ptr + a.length);
>
> // Or:
>
>     auto c = b.ptr - a.ptr;
>     assert(c >= 0 && c + b.length <= a.length);
>
> And trust me, the compiler complains about both of these. Possibly rightfully in the first example, but the latter never does anything scary with the given pointers.
>
> --
>   Simen

aka isSliceOf -> https://github.com/dlang/phobos/pull/6147
February 27, 2018
On 2/27/2018 4:39 AM, Jonathan M Davis wrote:
> Except that that's really not how @trusted is supposed to be used. The
> programmer needs to verify that the caller is using a.ptr in a manner that
> is actually @safe, because the compiler is not smart enough to determine
> that for you. Wrapping it in an @trusted function means that the caller
> won't get an error and that the programmer won't necessarily know that they
> need to verify the calling code. It's the code that's using ptr that needs
> to be verified, not the actual accessing of ptr.
> 
> Hiding the access to ptr within an @trusted function goes against that
> entire idea of @trusted and makes it easy to use ptr without realizing that
> you need to be checking the code that's using it, since you just called a
> wrapper function to silence the compiler instead of listening the compiler
> and studying the code using ptr to verify its @safety.

Yes, this bears repeating.
February 28, 2018
I don't think a just iterated array is automatically set to null, so taking it's pointer won't hit a memory-proteted area. So undeprectating arr.ptr in @safe would break @safety and be a step backward.

If this is an issue, one can define a @trusted function which takes a starting pointer from array and casts it to size_t before returning it so memory corruption cannot happen via it.

On Tuesday, 27 February 2018 at 09:47:51 UTC, Stefan Koch wrote:
> Checking if an array is the slice of another.

For that there is also std.array.overlap().


March 01, 2018
On Wednesday, 28 February 2018 at 22:34:07 UTC, Dukc wrote:
> I don't think a just iterated array is automatically set to null, so taking it's pointer won't hit a memory-proteted area. So undeprectating arr.ptr in @safe would break @safety and be a step backward.

If it cannot be proven safe by the compiler but is safe anyway it doesn't break @safe, it should just be @trusted. That's what @trusted is about, not about abusing functions to trick unsafe things into compiling @safe-ly.

> If this is an issue, one can define a @trusted function which takes a starting pointer from array and casts it to size_t before returning it so memory corruption cannot happen via it.
>
> On Tuesday, 27 February 2018 at 09:47:51 UTC, Stefan Koch wrote:
>> Checking if an array is the slice of another.
>
> For that there is also std.array.overlap().

1 2
Next ›   Last »