January 09, 2020
On Thursday, 9 January 2020 at 19:00:27 UTC, Steven Schveighoffer wrote:
> But I think this is digressing from the DIP discussion quite a bit. Probably best to continue if necessary in a new thread.
>
> -Steve

I don't agree. This is discussing a method to implement safe be default. If you are going to make a breaking change that causes almost all code to not compile, all tutorials and documentation to be invalidated. Every existing discussion to become obsolete. It makes sense to view all options. D's proposed safe by default is sub-par to comparison to Rust's and C#'s safe by default that use one keyword and unsafe blocks. Even though it lists Rust and C# as part of the reason for this change, it doesn't go into detail about how D's implementation is fundamentally different from how C# and Rust implement safe by default. You can't "turn on" safety, you can only turn it off with a keyword.


January 09, 2020
On 09.01.20 20:00, Steven Schveighoffer wrote:
> On 1/9/20 1:47 PM, Johannes Pfau wrote:
> 
>> So by modifying @safe code only, you introduced a memory safety issue.
> 
> Yes, this is why a function with ANY trusted blocks must be examined completely, and changes to the non-trusted parts must be checked to see if they cause problems with the trusted blocks.
> 
> HOWEVER, it is still of tremendous value to have the rest of it mechanically checked. So I still prefer this usage to trusting the whole function.

If your @trusted code relies on @safe code to maintain safety-critical invariants, your @trusted code is broken. Any reasonable formalization of @trusted would declare such an usage invalid, so lowering the scope of @trusted to small blocks is not per se desirable.

@safe code can't be trusted. It may be edited by programmers who are not allowed to write @trusted code.
January 09, 2020
On Thursday, 9 January 2020 at 18:47:23 UTC, Johannes Pfau wrote:
> @safe void someFunction()
> {
>     int[4] data;
>     // Lot's of code
>     @trusted
>     {
>         data.ptr[3] = 42;
>     }
> }
>
> Now someone changes data to int[2]:
>
> @safe void someFunction()
> {
>     int[2] data;
>     // Lot's of code
>     @trusted
>     {
>         data.ptr[3] = 42;
>     }
> }
>
> So by modifying @safe code only, you introduced a memory safety issue. The interface of a @trusted function however is more strictly defined:
>
> @trusted function set(ref int[4] data)
> {
>     data.ptr[3] = 42;
> }

Unfortunately, that kind of @trusted misuse is pretty common.

@system variables is a feature that can help in such cases. There's a DIP in the making:

https://github.com/dlang/DIPs/pull/179

You could then write someFunction as:

    @safe void someFunction()
    {
        @system int[4] data;
        // Lot's of code
        @trusted
        {
            data.ptr[3] = 42;
        }
    }

Now you're guaranteed that "lot's of code" can't touch `data`, and you can rely on that in the @trusted section.
January 09, 2020
On Thursday, 9 January 2020 at 19:22:28 UTC, Timon Gehr wrote:
> On 09.01.20 20:00, Steven Schveighoffer wrote:
>
> If your @trusted code relies on @safe code to maintain safety-critical invariants, your @trusted code is broken. Any reasonable formalization of @trusted would declare such an usage invalid, so lowering the scope of @trusted to small blocks is not per se desirable.
>
> @safe code can't be trusted. It may be edited by programmers who are not allowed to write @trusted code.

@trusted is a completely unnecessary declaration and should be removed. This DIP should really already assume that @trusted is removed.

There are @safe and @unsafe (or @system or whatever you call it). Safe code can call unsafe code a vice versa and it is the responsibility of the programmer to test the code and use the libraries the programmer think are stable enough. If you think about it there isn't a "middle", an almost safe, "I promise my @trusted code is bug free".
January 09, 2020
On 1/9/20 2:22 PM, Timon Gehr wrote:
> On 09.01.20 20:00, Steven Schveighoffer wrote:
>> On 1/9/20 1:47 PM, Johannes Pfau wrote:
>>
>>> So by modifying @safe code only, you introduced a memory safety issue.
>>
>> Yes, this is why a function with ANY trusted blocks must be examined completely, and changes to the non-trusted parts must be checked to see if they cause problems with the trusted blocks.
>>
>> HOWEVER, it is still of tremendous value to have the rest of it mechanically checked. So I still prefer this usage to trusting the whole function.
> 
> If your @trusted code relies on @safe code to maintain safety-critical invariants, your @trusted code is broken. Any reasonable formalization of @trusted would declare such an usage invalid, so lowering the scope of @trusted to small blocks is not per se desirable.
> 
> @safe code can't be trusted. It may be edited by programmers who are not allowed to write @trusted code.

I'm not saying it's safe. I'm saying I want the mechanical checking outside the trusted escape. e.g. I want the compiler to check these parts, but I know this one part needs trusting. D doesn't give a better way to express this other than safe code with trusted escapes.

If I could mark the whole thing trusted, and turn on the mechanical checking for everything except line X, then I'd do that instead.

-Steve
January 09, 2020
On 09.01.20 07:19, Arine wrote:
> On Wednesday, 8 January 2020 at 18:59:38 UTC, Timon Gehr wrote:
>> On 08.01.20 08:10, Arine wrote:
>>>
>>> @trusted doesn't really make sense. It is pretty much @system that @safe can call. It's actually kind of bad as how easily it can be misused. @trusted: comes to mind. You can have @trusted destructors. So when you are reading @safe code you can't easily tell where potentially @unsafe code is located. As the @trusted is applied to the function, not at the call site (like Rust/C#).
>>> ...
>>
>> This line of reasoning makes no sense.
>>
>> @trusted void foo(T...)(T args){ ... }
>>
>> is like
>>
>> @safe void foo(T...)(T args){ unsafe{ ... } }
>>
>> It's the same thing. The point is that the interface of foo is assumed to safe by all callers even though the implementation might not be.
> 
> That'd be a code smell. If you have to put the entire body of a function in unsafe, that function should just be defined as unsafe.

Nonsense. If a function provides a safe interface, @safe code should be able to call it freely. Forcing client code to unnecessarily sprinkle unsafe blocks everywhere is a bad idea.

> You've just given the perfect illustration of why @trusted is terrible.
> ...

Not really, but it appears you might not properly understand either @safe/@trusted/@system or @safe/@unsafe or modular software verification. The main drawback of @unsafe is that its meaning on blocks is dual to its meaning on functions. Unsafe blocks are like @trusted (trust me, what's in this block is fine) and @unsafe functions are like @system (be careful, the compiler will not check all preconditions required to call this function safely). The only benefit of @safe/@unsafe is that you need fewer keywords. It's actually more confusing.

>>> If we are going to make @safe the default we don't really need @safe keyword, or @system or @trusted. It's make sense to get rid of all 3 of them and just add @unsafe. If you are going to do it, might as well do it right the first time.
>>
>> I don't care all that much either way, but let's not pretend that what you propose is different to what we have in any important way other than how convenient certain things are to express. Adding trusted statement blocks and deprecating `@trusted:` annotations would have essentially the same effect.
> 
> Did you miss the example?

Of course not. Your example is either terrible or covered by trusted statement blocks. Not sure which.
January 09, 2020
On 09.01.20 20:34, IGotD- wrote:
> On Thursday, 9 January 2020 at 19:22:28 UTC, Timon Gehr wrote:
>> On 09.01.20 20:00, Steven Schveighoffer wrote:
>>
>> If your @trusted code relies on @safe code to maintain safety-critical invariants, your @trusted code is broken. Any reasonable formalization of @trusted would declare such an usage invalid, so lowering the scope of @trusted to small blocks is not per se desirable.
>>
>> @safe code can't be trusted. It may be edited by programmers who are not allowed to write @trusted code.
> 
> @trusted is a completely unnecessary declaration and should be removed. This DIP should really already assume that @trusted is removed.
> 
> There are @safe and @unsafe (or @system or whatever you call it). Safe code can call unsafe code a vice versa and it is the responsibility of the programmer to test the code and use the libraries the programmer think are stable enough. If you think about it there isn't a "middle", an almost safe, "I promise my @trusted code is bug free".

Sorry, but this is plain nonsense. Please read the documentation.
January 09, 2020
On Thursday, 9 January 2020 at 18:47:23 UTC, Johannes Pfau wrote:
> Am Thu, 09 Jan 2020 10:12:23 +1000 schrieb Manu:
>
>> 
>> unsafe blocks is distinctly preferable to me. Functions are usually >1 line, and I hate that we can only mark this at the function level. Unsafely statements are never at the function level, it's usually just one line among a larger function. An unsafe scope would be immensely preferable to me, because I can make it as narrow as the code i'm suspicious of, and the surrounding code doesn't lose its safe checking just by being a bystander.
>
> I agree that the lambda thing is an ugly hack and proper trusted blocks would be better. However, I wonder how languages with such blocks deal with problems such as these:
>
> @safe void someFunction()
> {
>     int[4] data;
>     // Lot's of code
>     @trusted
>     {
>         data.ptr[3] = 42;
>     }
> }
>
> Now someone changes data to int[2]:
>
> @safe void someFunction()
> {
>     int[2] data;
>     // Lot's of code
>     @trusted
>     {
>         data.ptr[3] = 42;
>     }
> }
>
> So by modifying @safe code only, you introduced a memory safety issue. The interface of a @trusted function however is more strictly defined:
>
> @trusted function set(ref int[4] data)
> {
>     data.ptr[3] = 42;
> }
>
> It's not possible to break the set function in @safe code. You could probably argue that the trusted block in someFunction should have covered the int[2] data definition and that you can also write @trusted functions which do not properly check / enforce their parameters and can be broken from @safe code.
>
> But still, it seems like applying trusted/safe at function level provides stronger guarantees. I wonder how other languages deal with that? Not at all and just be extra careful when writing trusted blocks?

Exactly!

Function level seems to be the proper place to granularly expose assumptions and promises in a clean way: put on the stage contracts, documentation and the possibility to easily unittest it ...

I'm -1 on @trusted blocks
January 09, 2020
On Thu, Jan 09, 2020 at 02:35:36PM -0500, Steven Schveighoffer via Digitalmars-d wrote:
> On 1/9/20 2:22 PM, Timon Gehr wrote:
[...]
> > @safe code can't be trusted. It may be edited by programmers who are not allowed to write @trusted code.
> 
> I'm not saying it's safe. I'm saying I want the mechanical checking outside the trusted escape. e.g. I want the compiler to check these parts, but I know this one part needs trusting. D doesn't give a better way to express this other than safe code with trusted escapes.
[...]

Yeah, I also consider this to be valuable.  Another way of doing the same thing is that @trusted *doesn't* allow unsafe operations by default, it just marks that function as needing to be manually verified, but within that function you have to explicitly mark out which parts are to be trusted:

	auto myfunc(Args args) @trusted {
		... // only @safe code allowed here
		@system {
			... // @system code allowed here
		}
		... // only @safe code allowed here
	}

The idea is that you want the compiler to statically check everything outside that nested @system block so that no unsafe operations are permitted there, so that you can isolate block the code that requires temporary suspension of @safe checks to a small, self-contained block.

But the function as a whole cannot be marked @safe because the @system block within interacts with the surrounding code, so you cannot guarantee the resulting combination will actually be @safe.  The function still needs to be audited *as a whole* for safety, but with the benefit that the compiler is also helping with part of the auditing by prohibiting potentially unsafe operations outside explicitly-marked blocks.

Inside a non-@trusted function, @system blocks would be completely verboten. (@system functions don't need such blocks because they're entirely @system already.)


T

-- 
It always amuses me that Windows has a Safe Mode during bootup. Does that mean that Windows is normally unsafe?
January 09, 2020
On 09.01.20 20:09, Arine wrote:
> 
> @safe void someFunction()
> {
>      int[2] data;
>      // Lot's of code
>      @unsafe
>      {
>          static assert( data.length > 3 );
>          data.ptr[3] = 42;
>      }
> }

@safe void someFunction(){
    static struct Nope{
        int[2] payload;
        alias payload this;
        enum length=1337;
    }
    Nope data;
    // ...
    @unsafe{
        static assert(data.length>3);
        data.ptr[3] = 42;
    }
}