January 31, 2017
On Tuesday, 31 January 2017 at 10:00:03 UTC, Stefan Koch wrote:
> On Tuesday, 31 January 2017 at 09:31:23 UTC, Nordlöw wrote:
>>
>> How can we be sure that the return value points to the same content as `s1`?
> Because of the return attribute.
> return means I am passing this value through myself.

I thought it meant "the parameter can be returned" not "the parameter *will* be returned".
January 31, 2017
On Tuesday, 31 January 2017 at 10:20:59 UTC, Olivier FAURE wrote:
> I thought it meant "the parameter can be returned" not "the parameter *will* be returned".

And what about multiple `return`-qualified function parameters?
January 31, 2017
On Tuesday, 31 January 2017 at 10:17:09 UTC, Olivier FAURE wrote:
> On Tuesday, 31 January 2017 at 01:30:48 UTC, Walter Bright wrote:
>> 3. Nothing s2 transitively points to is altered via s2.
>
> Wait, really? Does that mean that this code is implicitly illegal?
>
> import core.stdc.string;
>
>     void main()
>     {
>         int*[10] data1;
>         int*[10] data2;
>
>         memcpy(data1.ptr, data2.ptr, 10);
>     }
>
> Since memcpy is @system, I have no way to know for sure (the compiler obviously won't warn me since I can't mark main as @safe), so I'd argue the prototype doesn't carry that information.

Point 3 is about `const`, which as far as I know is unaffected by application of @safe. Did you mean to quote a different point?
January 31, 2017
On Tuesday, 31 January 2017 at 01:30:48 UTC, Walter Bright wrote:
> Just from D's type signature, we can know a lot about memcpy():
>
> 1. There are no side effects.
> 2. The return value is derived from s1.
> 3. Nothing s2 transitively points to is altered via s2.
> 4. Copies of s1 or s2 are not saved.
>
> The C declaration does not give us any of that info, although the C description
> does give us 2, and the 'restrict' says that s1 and s2 do not overlap.
>
> The Rust declaration does not give us 1, 2 or 4 (because it is marked as unsafe). If it was safe, the declaration does not give us 2.
>
> By this information being knowable from the declaration, the compiler knows it too and can make use of it.

Well, I would not have taken memcpy as an example in favor of D. Good C compilers (like gcc) know what memcpy does and are able to optimize it according to its arguments. DMD may know better about memcpy through its declaration but does not make any use about it.

A simple example:
// cmemcpy.c
#include <string.h>
#include <stdio.h>

int main(void) {
	char a[16] = "world hello";	
	char b[16] = "";

	memcpy(b, a, 12);
	memcpy(b, a + 6, 5);
	memcpy(b + 6, a, 5);
	printf("%s -> %s\n", a, b);
}
//------------

gcc -Ofast produces the following code:
main:
.LFB0:
	.cfi_startproc
	subq	$40, %rsp
	.cfi_def_cfa_offset 48
	movl	$.LC0, %edi
	movabsq	$7307126011096887159, %rax
	movq	%rax, (%rsp)
	movq	%rsp, %rdx
	movq	%rax, 16(%rsp)
	leaq	16(%rsp), %rsi
	movq	$7302252, 24(%rsp)
	movl	22(%rsp), %eax
	movq	$0, 8(%rsp)
	movl	$7302252, 8(%rsp)
	movl	%eax, (%rsp)
	movzbl	26(%rsp), %eax
	movb	%al, 4(%rsp)
	movl	16(%rsp), %eax
	movl	%eax, 6(%rsp)
	movzbl	20(%rsp), %eax
	movb	%al, 10(%rsp)
	xorl	%eax, %eax
	call	printf
	xorl	%eax, %eax
	addq	$40, %rsp
	.cfi_def_cfa_offset 8
	ret

No call to memcpy, this has been optimized out by the compiler.

Now a D equivalent:
// dmemcpy.d
module dmemcpy;

import core.stdc.string, std.stdio;

void main() {
	char [16] a_ = "world hello", b_ = "";
	void* a = &a_[0], b = &b_[0];

	memcpy(b, a, 12);
	memcpy(b, a + 6, 5);
	memcpy(b + 6, a, 5);
	writefln("%s -> %s", a_, b_);
}
//--------------------

dmd -O -release -inline -boundscheck=off prouces the following asm:
_Dmain:
		push	RBP
		mov	RBP,RSP
		sub	RSP,020h
		lea	RSI,_TMP0@PC32[RIP]
		lea	RDI,-020h[RBP]
		movsd
		movsd
		lea	RSI,_TMP0@PC32[RIP]
		lea	RDI,-010h[RBP]
		movsd
		movsd
		mov	EDX,0Ch
		lea	RSI,-020h[RBP]
		lea	RDI,-010h[RBP]
		call	  memcpy@PLT32
		mov	EDX,5
		lea	RSI,-01Ah[RBP]
		lea	RDI,-010h[RBP]
		call	  memcpy@PLT32
		mov	EDX,5
		lea	RSI,-020h[RBP]
		lea	RDI,-0Ah[RBP]
		call	  memcpy@PLT32
		lea	RDX,_TMP0@PC32[RIP]
		mov	EDI,8
		mov	RSI,RDX
		push	dword ptr -018h[RBP]
		push	dword ptr -020h[RBP]
		push	dword ptr -8[RBP]
		push	dword ptr -010h[RBP]
		call	  _D3std5stdio27__T8writeflnTAyaTG16aTG16aZ8writeflnFNfAyaG16aG16aZv@PLT32
		add	RSP,020h
		xor	EAX,EAX
		mov	RSP,RBP
		pop	RBP
		ret

So with DMD, calls to memcpy are done verbatim, without any optimization :-(
To be fair, gdc will optimize the memcpy call out too.
But, my main argument here, is that a good C compiler, is able to do a very good job at optimizing memcpy, so the extra information brought by the D language, is not so useful in practice.




January 31, 2017
On Tuesday, 31 January 2017 at 13:50:33 UTC, Richard Delorme wrote:
> But, my main argument here, is that a good C compiler, is able to do a very good job at optimizing memcpy, so the extra information brought by the D language, is not so useful in practice.

The point of Walter's argument was not about performance but, safety guarantees. Guarantees which cannot be given by C, or by Rust due to it's marking as unsafe (as I understand it). So the extra info is very useful for the programmer.

Also, I would compare apples to apples here and compile both the C program and the D code with LLVM.
January 31, 2017
On Tuesday, 31 January 2017 at 10:00:03 UTC, Stefan Koch wrote:
> Because of the return attribute.
> return means I am passing this value through myself.

Ahh, missed that. My mistake.

Thanks, Walter!
January 31, 2017
On Tuesday, 31 January 2017 at 11:32:01 UTC, John Colvin wrote:
> On Tuesday, 31 January 2017 at 10:17:09 UTC, Olivier FAURE wrote:
>> On Tuesday, 31 January 2017 at 01:30:48 UTC, Walter Bright wrote:
>
> Point 3 is about `const`, which as far as I know is unaffected by application of @safe. Did you mean to quote a different point?

Oh yeah, I thought it was about scope. Makes sense then.
January 31, 2017
On Tuesday, 31 January 2017 at 02:18:23 UTC, Mike wrote:
> On Tuesday, 31 January 2017 at 02:01:05 UTC, Walter Bright wrote:
>> On 1/30/2017 5:53 PM, Mike wrote:
>>> One in particular prevents me from using D, period! -
>>> https://issues.dlang.org/show_bug.cgi?id=14758
>>
>> The -betterC switch is the approach we intend to take to deal with that issue.
>
> I recommend against that; it's too blunt of an instrument.  Instead I suggest following through on things like https://issues.dlang.org/show_bug.cgi?id=12270 and considering this proposal (http://forum.dlang.org/post/psssnzurlzeqeneagora@forum.dlang.org) instead.
>
> Mike

The main problem - the opaque extern (C) interface an therefore non-lazy code generation - is already being worked on:
http://forum.dlang.org/thread/o0kdnp$2i2t$1@digitalmars.com
http://forum.dlang.org/thread/wbtjswiwbrtxzqiorwiw@forum.dlang.org
January 31, 2017
On Tuesday, 31 January 2017 at 01:30:48 UTC, Walter Bright wrote:
> 2. The return value is derived from s1.
> 4. Copies of s1 or s2 are not saved.

Actually I didn't know either of those things from looking at the signature because DIP25 and DIP1000 have marketing problems, in that the only way to get info on them is on the DIP pages. I'd be willing to bet money that 80% of the people who use D don't know about the -dip25 flag.

Is there anywhere which gives a simple explaination of both of these DIP's safety checks?
January 31, 2017
On 1/31/2017 5:50 AM, Richard Delorme wrote:
> Well, I would not have taken memcpy as an example in favor of D. Good C
> compilers (like gcc) know what memcpy does and are able to optimize it according
> to its arguments. DMD may know better about memcpy through its declaration but
> does not make any use about it.

That may be true, but is not my point. The compiler cannot have built in knowledge of every function. I just used memcpy() as an example because it is extremely well known.

As for making use of the type signature information, DMD uses it to check the memory safety of arguments supplied to memcpy(), something gcc does not do.