Non-techincal brain, is @safe by default good or not?
Mathias LANG
geod24 at gmail.com
Thu May 28 13:04:15 UTC 2020
On Thursday, 28 May 2020 at 11:07:16 UTC, Johannes Loher wrote:
>
> Again, please file a bug report. This is either a bug with
> @safe or there is some @trusted in `move` (or one of the
> functions it calls) that calls `opPostMove`.
Oh I know exactly how it happened. I just went over the code
quickly, saw `@trusted`, and saw it calling a user-supplied hook,
and crafting a test case was trivial.
This is because, at the top level, there is a function which
checks if the destruction is `@safe` (well, it checks quite a few
other things actually, but that's not the point here), and if it
is, just blindly trust a lower function, which itself happens to
be more correct in its usage of @trusted.
That's the technical explanation. The higher level explanation is
that we had code that was written correctly, audited, then a
language feature was added, and support for it was added by
different contributors over time. And the *whole* code was not
re-audited for `@trusted`.
> Both of the examples you provide are bugs but I realize that
> there are real examples of what you are trying to show. One
> situation where this happens is if libraries have non-template
> functions that take a callback as parameter. The library author
> has to make a decision whether to make his function @safe,
> which requires all callbacks passed to it also to be @safe, or
> to make it @system, which makes it unusable in @safe code, even
> if it actually is safe because the callback that was passed is
> @safe. @trusted allows both kinds of usages but is a really bad
> idea because it allows unchecked @system code to be called from
> @safe code.
Yes, that's a point I tried to make over and over, but it seems
no one was interested.
And as mentioned, it also affects OOP code.
Slight correction though: Accepting a `@trusted` delegate will
**not** allow you to pass a `@system` delegate. I tried.
> This is why some people in the community have suggested to
> allow attribute inference also for non-template functions. That
> would solve the issue might might be a better default than both
> @system and @safe. However, I don't think anybody has thought
> that through completely yet. Some people have voiced concerns
> regarding inheritance and .di files (and probably more) but I
> think it might be possible to do this.
That's a terrible idea:
- It will be a massive slowdown for anyone not compiling
all-at-once: at the moment the frontend knows about "root
module", which are module for which the compiler will do codegen.
As such, it doesn't do any semantic analysis on functions that
are not in root modules (except for the prototype). Inference for
everything means you have to perform full semantic analysis for
everything. Compiling by packages means performing full semantic
for your whole program multiple times over. It also means
whatever function in Phobos, every D program will also need to
perform semantic analysis on them if it imports it. The compiler
could (should) be smarter and have lazier semantic, but we need
to implement it, and at the core, this suggestion does not scale.
- You would have to either disable that for OOP code, which would
be a weird special case, or find a way to negate it, or ... ? I
can't even picture a way to make this work. If you have a class,
and your base implementation of `toString` just returns a
literal, it has all attributes available, however derived code
might want to use `format`.
- It doesn't solve the actual problem: You still will write your
function prototype as `void requestHTTP(scope void delegate(scope
ref HTTPRequest) /* @safe */ req)`.
You need to express a way to tie `requestHTTP`'s attributes to
`req`'s attributes , not just infer `req`'s attributes. And the
way you do this needs to be subtle, because you might want to
express: "I am `@safe` is this is `@safe`" and "I am `nothrow` no
matter what" as well as "I am not `@nogc` even if `req` is". At
the moment we can express the second and the third variant but
not the first.
IMO the real answer is to come up with something like `inout` for
attributes. `inout` is a wildcard. It's exactly what you want for
delegates. It doesn't solve the issue with OOP though, although
it makes it easier to mitigate it (see `Throwable.toString` for
how you could have a conditionally `@nogc` / `nothrow` / etc...
method).
More information about the Digitalmars-d
mailing list