Thread overview
Greenwashing: best practices
May 30, 2020
Johannes T
May 30, 2020
Paul Backus
May 31, 2020
Johannes T
May 30, 2020
ag0aep6g
May 31, 2020
Johannes T
May 31, 2020
ag0aep6g
May 30, 2020
I was searching for ways to mitigate DIP's 1028 greenwashing concerns without resorting to @safe extern. It turns out, D already has tools to address that. It's a matter of recognizing and promoting best practices. Allow me to elaborate.

Verified C functions require @trusted declaration when used in safe code. It's a slight antipattern, similar to a bad comment:
// implementation looks safe
ssize_t recv(void*, size_t);

Yes, @trusted is parsed and can be searched, that's not the point. It's too far from the source code. What version was vetted? Are we linking against an older one that leaked? Hard to say without checking. This leads to the first advice:

Declarations should reside in .di files and not be scattered throughout D code. It allows us to keep .di closer to the library and version it separately. If the version changes, there is no need to search for affected D sources.

Many bindings already do that. I wasn't aware of it and just used extern(C) as needed.

Let's assume we've created a .di file with some internal C backend stuff. Trying to call it doesn't compile. The next advice could be:

To force unchecked functions to compile, the corresponding declarations should be surrounded by @trusted { } block. The block suggests it was rubber-stamped without audit. It's also the path of least resistance for multiple functions. @trusted should only be added to a single declaration if it was verified.

I imagine being a C++ programmer trying out D and don't see much inconvenience following this. More importantly, when the program crashes, I would remember adding @trusted { } and can't blame D's safety annotation.
May 30, 2020
On Saturday, 30 May 2020 at 21:31:11 UTC, Johannes T wrote:
> Verified C functions require @trusted declaration when used in safe code. It's a slight antipattern, similar to a bad comment:
> // implementation looks safe
> ssize_t recv(void*, size_t);
>
> Yes, @trusted is parsed and can be searched, that's not the point. It's too far from the source code. What version was vetted? Are we linking against an older one that leaked? Hard to say without checking.

Realistically, if you're writing portable code, the version that's vetted is the version described by the documentation or standard that describes the interface you're programming to. So in this case, you'd refer to the POSIX standard's page on `recv`:

https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html

If a particular version of a particular implementation on a particular platform has a bug, well, that's the implementation's problem, not yours. You can't possibly vet every version of `recv` that your code could ever be linked with (especially because some of those versions may not even exist at the time you do the vetting!).

> Declarations should reside in .di files and not be scattered throughout D code. It allows us to keep .di closer to the library and version it separately. If the version changes, there is no need to search for affected D sources.
>
> Many bindings already do that. I wasn't aware of it and just used extern(C) as needed.

As far as I know there's no advantage to using a .di file over a regular .d file for C bindings. It *is* a good idea to put translated C headers in their own files, rather than sprinkling declarations around willy-nilly, for the same reason it's good to put your C declarations in .h files, rather than sprinkling them around willy-nilly.


> To force unchecked functions to compile, the corresponding declarations should be surrounded by @trusted { } block. The block suggests it was rubber-stamped without audit. It's also the path of least resistance for multiple functions. @trusted should only be added to a single declaration if it was verified.
>
> I imagine being a C++ programmer trying out D and don't see much inconvenience following this. More importantly, when the program crashes, I would remember adding @trusted { } and can't blame D's safety annotation.

Sure, I guess you could do this if you wanted to prototype something quickly and didn't care much about making sure it was 100% memory-safe.

On the other hand, you could *also* just write the whole thing as @system, and leave migrating to @safe for later--at which point the compiler will bug you about your C function calls, and you can take the time to fix them *properly*. This has the advantage that you never give yourself a false sense of security by pretending code is @safe when it actually isn't.
May 31, 2020
On 30.05.20 23:31, Johannes T wrote:
> To force unchecked functions to compile, the corresponding declarations should be surrounded by @trusted { } block. The block suggests it was rubber-stamped without audit. It's also the path of least resistance for multiple functions. @trusted should only be added to a single declaration if it was verified.

I think it would be a mistake to try and distinguish `@trusted` from `@trusted { ... }` that way. A UDA (.e.g `@audited`) would be a better fit if you want to communicate that an audit has happened.

As far as I'm aware, there is generally no expectation of @trusted extern functions having their implementations verified. First and foremost, @trusted marks a safe interface [1]. Whether the implementation is bug-free is secondary.

On a D function, @trusted is also just an "I think it's safe" comment by the author. It doesn't indicate that the code was audited by anyone else.


[1] https://dlang.org/spec/function.html#safe-interfaces
May 31, 2020
On Saturday, 30 May 2020 at 22:00:27 UTC, Paul Backus wrote:
> [..]
> If a particular version of a particular implementation on a particular platform has a bug, well, that's the implementation's problem, not yours. You can't possibly vet every version of `recv` that your code could ever be linked with (especially because some of those versions may not even exist at the time you do the vetting!).
> [..]

That's a good point. Also, when an issue is discovered in a newer release, changing back to @system wouldn't be a sensible path. The safety of the interface should govern the attribute. I didn't realize that.

> [..]
> As far as I know there's no advantage to using a .di file over a regular .d file for C bindings.
> [..]

You're right, .di shouldn't cause contention. Use whatever is more consistent.

> [..]
> On the other hand, you could *also* just write the whole thing as @system, and leave migrating to @safe for later--at which point the compiler will bug you about your C function calls, and you can take the time to fix them *properly*. This has the advantage that you never give yourself a false sense of security by pretending code is @safe when it actually isn't.

I hope Nick Treleaven's great idea with `@safe module foo;` will gain traction. It would make the migration path more convenient.
Thanks!
May 31, 2020
On Saturday, 30 May 2020 at 22:01:14 UTC, ag0aep6g wrote:
> On 30.05.20 23:31, Johannes T wrote:
>> To force unchecked functions to compile, the corresponding declarations should be surrounded by @trusted { } block. The block suggests it was rubber-stamped without audit. It's also the path of least resistance for multiple functions. @trusted should only be added to a single declaration if it was verified.
>
> I think it would be a mistake to try and distinguish `@trusted` from `@trusted { ... }` that way. A UDA (.e.g `@audited`) would be a better fit if you want to communicate that an audit has happened.

You're right. It does seem bad and shouldn't be promoted. I think there is still some value using it as a smell. If you see @trusted: or @trusted { }, it's probably there to shut up the compiler.

> As far as I'm aware, there is generally no expectation of @trusted extern functions having their implementations verified. First and foremost, @trusted marks a safe interface [1]. Whether the implementation is bug-free is secondary.
>
> On a D function, @trusted is also just an "I think it's safe" comment by the author. It doesn't indicate that the code was audited by anyone else.
>
> [1] https://dlang.org/spec/function.html#safe-interfaces

That's an important distinction. I didn't realize it until recently.
Thank you.


May 31, 2020
On 31.05.20 13:08, Johannes T wrote:
> I think there is still some value using it as a smell. If you see
> @trusted: or @trusted { }, it's probably there to shut up the
> compiler.

Agreed.