January 15, 2020
On Wednesday, 15 January 2020 at 23:24:38 UTC, IGotD- wrote:
> @safe is a subset of D that guarantees no memory corruption.

Not quite. @safe is a subset of D that guarantees no memory corruption, as long as people write only correct @trusted code (and there might be more restrictions). This weaker definition is being used because the strong one is considered impractical.

There might be text in the documentation that suggests the stronger definition, but that is not going to take precedence. The weaker one is widely accepted as more useful. If anything, a conflict would surely be resolved by changing the documentation.
January 16, 2020
On Wednesday, 15 January 2020 at 23:46:11 UTC, ag0aep6g wrote:
> You're saying that it is useful for me as a user of Phobos when I see that, for example, std.stdio.File.open is @trusted [1], right?
>

Speaking of libraries, as you can see many calls will go the C library which is of course is unsafe code. The only way I can see it is that @safe code should be able to call unsafe code by default, for convenience.

Now there is a possibility that the programmer wants that the code shall not call any unsafe code what so ever. Then I think that a function attribute should be added that tells that the code is not allowed to call any unsafe code down the line. This is better because.

1. It is a restriction set by the programmer and not some arbitrary promise from a third party.
2. It is absolute. The compiler can check this, either it hits unsafe or it doesn't. It is either true or false and it cannot be questioned.

January 16, 2020
On 16.01.20 00:24, IGotD- wrote:
> On Wednesday, 15 January 2020 at 23:01:57 UTC, Joseph Rushton Wakeling wrote:
>>
>> Presumably your programs are therefore self-crafted binary, since you couldn't possibly trust the humans who wrote the standard library to write valid code, or the compiler writers to translate it correctly into machine instructions? :-)
>>
> 
> @safe is a subset of D that guarantees no memory corruption.

@safe does not mean "this unconditionally can not corrupt memory", it says "if its @trusted dependencies are written right, @safe code can not introduce memory corruption". If you don't write @trusted code yourself and only use the standard library, @safe gives you the guarantee you mention per the language and standard library specification, but in practice there can be bugs in the language implementation or its dependencies. Assuming a correct compiler implementation of the safety checks, the locations where memory corruption can be caused will however all be within `@trusted` function calls.

Similar concerns apply to other safe languages such as Java. (Why do you think users need to update their JVM regularly? It's not just about performance upgrades.) What do you think "security updates" for your OS do? How is @safe supposed to be _useful_ if it cannot assume the OS, system C libraries, and hardware behave as specified?

> The only way to ensure this is if the compiler have all the source code (will object code also work?) and can check that all the calls are also @safe. If this condition is not met, it is not safe by definition. @trusted code has reduced memory guarantees and can also call unsafe code further along the line and therefore unsafe.
> 
> @trusted is therefore impossible and the criteria cannot be met. It's just a badge meaning nothing.
> ...

Nonsense. It's the place where you inject assumptions into your conditional verifier. It reduces the amount of code you have to audit to convince yourself that a given dependency will not corrupt the internal state of your program.

>> I think you're getting caught up on the choice of terminology. It's just a hierarchy of guarantees:
> 
> No, I'm caught up in the semantics. I see that a condition cannot be met and therefore unnecessary.

You are operating on bad assumptions or bad logic. @trusted is clearly useful, because it makes no sense to require every piece of trusted code to be part of the compiler implementation.

> @trusted is an oxymoron.
> 
@trusted void foo(int[] a,int b){
    if(0<=b&&b<a.length){
        a.ptr[b]=2;
    }
}

@system void bar(int[] a,int b){
    a.ptr[b]=2;
}

How do you not see the difference, that it is useful to annotate that difference, and that it is okay to call foo from @safe code, but not bar?
January 16, 2020
On Wednesday, 15 January 2020 at 23:46:11 UTC, ag0aep6g wrote:
> You're saying that it is useful for me as a user of Phobos when I see that, for example, std.stdio.File.open is @trusted [1], right?

Yes, I am saying exactly that.

> I disagree. It doesn't mean anything other than @safe in that context. Knowing that the function is @trusted instead of @safe is of zero use to a user of Phobos. It cannot help them make any decision whatsoever.

I see what you're getting at here -- you mean that if we're treating this function as a black box that I have no influence over, then both @safe and @trusted mean the same thing in terms of how that black box ought to behave.

But that doesn't mean the distinction isn't useful.  It gives me a clear indication that the code of this function (note, _the code of this function_, not the code of other functions it might call) could contain bugs that would allow memory safety violations.

Contrast this with, say, Rust, where any function can do something like this:

    fn foo(x: &[int]) {
        unsafe {
            // any old horrible stuff can happen here
        }
    }

... where any number of memory safety bugs could exist in that `unsafe { ... }` block, and yet there is no possible clue from the API that this could be going on.

The fact that in a similar situation D forces you to annotate the function with `@trusted`, and alert users to the _possibility_ that memory safety bugs could exist within the code of this function, is useful information even if you can't access the source code.

> I.e., it's a tool for library authors, not for library users. You clearly spoke of an "external" or "outside" user of the function before.

It's clearly much less useful to anyone who doesn't have access to the source code (which doesn't mean it's not useful at all).  But in general, given the ability to read and search the source code (which users as well as authors can do), it's very useful to be able to ask the question: "Of the code in this project that claims to be memory safe, which bits could actually contain memory safety bugs?"
January 16, 2020
On 16.01.20 01:09, IGotD- wrote:
> On Wednesday, 15 January 2020 at 23:46:11 UTC, ag0aep6g wrote:
>> You're saying that it is useful for me as a user of Phobos when I see that, for example, std.stdio.File.open is @trusted [1], right?
>>
> 
> Speaking of libraries, as you can see many calls will go the C library which is of course is unsafe code. The only way I can see it is that @safe code should be able to call unsafe code by default, for convenience.
> ...

That's nonsense, it completely undermines @safe, because many sensible @system functions do not have a safe interface. @safe code shouldn't be able to directly call `free` from the C standard library on arbitrary pointers.

> Now there is a possibility that the programmer wants that the code shall not call any unsafe code what so ever.

@trusted functions are not unsafe, it's just not checked by the compiler.

> Then I think that a function attribute should be added that tells that the code is not allowed to call any unsafe code down the line. This is better because.
> 
> 1. It is a restriction set by the programmer and not some arbitrary promise from a third party.

It's an arbitrary promise from the compiler implementation...

> 2. It is absolute. The compiler can check this, either it hits unsafe or it doesn't. It is either true or false and it cannot be questioned.
> 

This is not better. Why do you trust compilers and standard library behave according to the specification but are unwilling to do that for any other code that cannot be verified by the compiler? You are making an arbitrary distinction where there is none.

The point of @safe is that if you write @safe code (and no @trusted code), memory corruption is not supposed to occur; any memory corruption that occurs anyway is not your own fault. (Except maybe for not doing due diligence when evaluating a potential dependency before using it.)
January 16, 2020
On Thursday, 16 January 2020 at 00:21:21 UTC, Joseph Rushton Wakeling wrote:
> I see what you're getting at here -- you mean that if we're treating this function as a black box that I have no influence over, then both @safe and @trusted mean the same thing in terms of how that black box ought to behave.

Exactly.

> But that doesn't mean the distinction isn't useful.  It gives me a clear indication that the code of this function (note, _the code of this function_, not the code of other functions it might call) could contain bugs that would allow memory safety violations.

And that isn't useful to a user in any way.

[...]
> The fact that in a similar situation D forces you to annotate the function with `@trusted`, and alert users to the _possibility_ that memory safety bugs could exist within the code of this function, is useful information even if you can't access the source code.

I don't agree. @trusted doesn't alert you any more of the possibility of a memory safety bug than @safe. You can't assume that an @safe function won't corrupt your memory any more than you can assume the same about an @trusted function.

[...]
> It's clearly much less useful to anyone who doesn't have access to the source code (which doesn't mean it's not useful at all).

(It is useless, though.)

>  But in general, given the ability to read and search the source code (which users as well as authors can do), it's very useful to be able to ask the question: "Of the code in this project that claims to be memory safe, which bits could actually contain memory safety bugs?"

Yes, but you find those interesting bits by grepping over the source code, not by looking at the attributes of public functions. Many @safe functions have @trusted innards that don't show up in API documentation.
January 16, 2020
On Wednesday, 15 January 2020 at 14:30:02 UTC, Ogi wrote:
> If you think of it, it makes no sense for @trusted to be a function attribute. It doesn’t describe its behavior but its implementation. If you call a function, it should not be your concern; @safe and @trusted are the same thing for you. But these two attributes result in two different signatures. If a function expects a @safe callback, you can’t pass a @trusted function to it without @safe wrapping. If some library makes a function that used to be @safe @trusted, that’s a breaking change. Etc, etc. Why should we introduce complexity out of nowhere?

To me, this is the only part of the argument against @trusted that's really convincing. Having the @safe/@trusted distinction be part of the type system and the ABI is almost 100% downside, and changing that would eliminate some pain points at essentially no cost to the language.

However, both of these issues can be fixed without a huge overhaul of @trusted. The type-system issue can be fixed by introducing implicit conversions between @safe and @trusted functions, and the ABI issue can be fixed by changing how @trusted affects name mangling.

Once these issues are fixed, the only remaining benefits of the proposed overhaul are cosmetic, and IMO not worth the disruption they would cause.

January 15, 2020
On Thu, Jan 16, 2020 at 01:07:21AM +0000, Paul Backus via Digitalmars-d wrote:
> On Wednesday, 15 January 2020 at 14:30:02 UTC, Ogi wrote:
[...]
> > If a function expects a @safe callback, you can’t pass a @trusted function to it without @safe wrapping.
[...]

Hogwash. Did you even test this before making statements like that?

	void fun(void function() @safe dg) { }

	void trustme() @trusted { }

	void main() {
		fun(&trustme);
	}

Compiles fine.


[...]
> However, both of these issues can be fixed without a huge overhaul of @trusted. The type-system issue can be fixed by introducing implicit conversions between @safe and @trusted functions, and the ABI issue can be fixed by changing how @trusted affects name mangling.

@trusted *already* implicitly converts to @safe.  We're arguing over nothing here.


T

-- 
Two wrongs don't make a right; but three rights do make a left...
January 16, 2020
On 16.01.20 02:07, Paul Backus wrote:
> On Wednesday, 15 January 2020 at 14:30:02 UTC, Ogi wrote:
>> If you think of it, it makes no sense for @trusted to be a function attribute. It doesn’t describe its behavior but its implementation. If you call a function, it should not be your concern; @safe and @trusted are the same thing for you. But these two attributes result in two different signatures. If a function expects a @safe callback, you can’t pass a @trusted function to it without @safe wrapping. If some library makes a function that used to be @safe @trusted, that’s a breaking change. Etc, etc. Why should we introduce complexity out of nowhere?
> 
> To me, this is the only part of the argument against @trusted that's really convincing. Having the @safe/@trusted distinction be part of the type system and the ABI is almost 100% downside, and changing that would eliminate some pain points at essentially no cost to the language.
> 
> However, both of these issues can be fixed without a huge overhaul of @trusted. The type-system issue can be fixed by introducing implicit conversions between @safe and @trusted functions,

That's already how it works. The OP just didn't bother to check whether the claim is true:

void main(){
    void delegate()@safe dg0=()@trusted{}; // ok
    void delegate()@trusted dg1=()@safe{}; // ok
}

> and the ABI issue can be fixed by changing how @trusted affects name mangling.
> ...

It's not just the ABI, it's also static introspection. The way to fix that is to treat `@trusted` functions as `@safe` functions from the outside. (E.g.., `typeof(()@trusted{})` would be `void delegate()@safe`.)

> Once these issues are fixed, the only remaining benefits of the proposed overhaul are cosmetic, and IMO not worth the disruption they would cause.
> 

January 16, 2020
On Thursday, 16 January 2020 at 00:40:12 UTC, ag0aep6g wrote:
> And that isn't useful to a user in any way.

The fact that I personally find it useful -- and going by this discussion thread, so do some others -- means that this claim can't possibly be true.

> I don't agree. @trusted doesn't alert you any more of the possibility of a memory safety bug than @safe. You can't assume that an @safe function won't corrupt your memory any more than you can assume the same about an @trusted function.

@safe on a function tells you no more than it promises: that the compiler will alert you to any memory safety violations it is able to detect in that function's implementation.  If it does not detect any, that could be because none are present, or it could be that at some point nested inside the code it calls there is something @trusted that the compiler does not attempt to validate.

@trusted on a function, on the other hand, explicitly tells you that its safety is contingent on something other than compiler validation, and that you should not expect the compiler to validate _any_ part of its internals.

Do you seriously not see any difference between an annotation that tells you: "this function should be memory-safe, and the compiler will attempt to validate this to the best of its ability" versus, "this function should be memory-safe, but the compiler will not make any attempt to validate that"?  And do you seriously not see any value in having that distinction clear?

Obviously the allegedly @safe function _could_ just be a thin wrapper around a @trusted lambda containing all sorts of horrible crack.  But on balance of probabilities, in any library written by vaguely competent people, that should probably not be your _first_ assumption.

> (It is useless, though.)

Don't mistake "I don't find it useful" for "No one finds it useful".

> Yes, but you find those interesting bits by grepping over the source code, not by looking at the attributes of public functions. Many @safe functions have @trusted innards that don't show up in API documentation.

FWIW I do think it may be a bit of a code smell or anti-pattern to have nested @trusted functions inside @safe functions.  Of course, there's still the possibility that a @safe function can call some external but private @trusted function, but it reduces the attack space if the internal code of a @safe function can be fully validated _in its own terms_ (i.e. if it can be validated that there is nothing _inside the function_ that could cause a memory safety bug).

BTW, that's part of the motivation for my suggestions at the beginning of this thread about how @trusted could be improved:
https://forum.dlang.org/post/heujvxcsppiyagxfvliv@forum.dlang.org

If the compiler would validate all the contents of @trusted functions except for lines contained in `@system { ... }` blocks (see the original example if it's not clear what I mean), then that would probably be a preferred way to achieve what developers currently do using @safe functions with some nested @trusted lambdas.  And that would probably mean that APIs would be annotated in a more informative way about the _true_ risk of memory safety bugs.