Ignore unsafe and impure code in any contract and catch all Exceptions (fixes issue 4995 and regression 10981)#2155
Ignore unsafe and impure code in any contract and catch all Exceptions (fixes issue 4995 and regression 10981)#2155hpohl wants to merge 1 commit intodlang:masterfrom
Conversation
|
Or should we enforce that the invariant is nothrow, when any of the public member functions are? Are the other attributes enforced for invariant calls? (@safe/pure) |
This fix takes Jonathan's second road. And I think it is the right one.
Right now, the invariant calls are implicit, see |
|
I don't know what to do now, though. Fix all invariant signatures in Phobos? |
|
Let's see the enumerated ways.
I think 3. is better than others, because it gives the control opportunity for the exception handling to the programmer. |
|
I like 3 too. As a note, regarding (2) we can translate any exception into an assertion error without loss of information by setting the original exception as chained from the assertion error. |
|
Actually I'm in favor of 3, despite my phrasing. |
|
Thanks, @andralex and @yebblies. It might break existing user code, but we can help fixing the appeared bugs by providing more strict @safe/pure/nothrow Phobos. I'm sure that it is possible, from the experience of my recent Phobos contribution and related compiler bug fixes. @hpohl, Would you have any opinion about that? |
|
I don't like the idea of enforcing nothrowness of the invariant depending on the existance of a nothrow method. A little unrelated change (adding a nothrow method) may break all invariant code. |
|
And this should not depend on the nothrowness of the function where the invariant is called in.. I will change that. |
|
@hpohl raises a very good point about |
|
It's a bad idea to let any |
src/func.c
Outdated
There was a problem hiding this comment.
This is worse than before. It will break existing code, such as:
class C {
nothrow:
/* many methods */
invariant() { ... } // impliitly annotated with nothrow
}
There was a problem hiding this comment.
The parser doesn't distinguish nothrow: invariant() { } and nothrow invariant() { }. How to resolve that? And even if it does break code, it is easy to fix.
There was a problem hiding this comment.
It's current design. So there is no solution.
Additionally, even if it is possible, breaking existing nothrow invariant {} is also bad idea.
There was a problem hiding this comment.
So you think marking an invariant with nothrow even though no Exception will ever escape is okay? It still forces the invariant body to not throw, though.
There was a problem hiding this comment.
I think nothrow invariant should be enforced only when it is necessary.
class C1 { void foo(){} invariant(){} } // nothrow invariant is not necessary
class C2 { void foo1(){} void foo2(){} invariant(){} } // same
class C3 { void foo1(){} nothrow void foo2(){} invariant(){} } // invariant should be nothrowCompiler should raise an error only for C3.
There was a problem hiding this comment.
Why do you want Exceptions to be able to escape from contracts?
There was a problem hiding this comment.
Anyway, you're right, the check is bad, I will remove it.
There was a problem hiding this comment.
Because normal function can throw Exception on default.
Some D users will surely imagine an invariant as a special function, that is implicitly called at the start and the end of public member functions. For them, implicit nothrow enforcement for invariant may be unacceptable behavior.
I don't say that current this change is essentially wrong, but I'm much worried that a built-in language semantics will reject system programming, especially if it requires runtime overhead. We should become very very carefully to add such runtime behavior.
There was a problem hiding this comment.
Some D users will surely imagine an invariant as a special function, that is implicitly called at the start and
the end of public member functions. For them, implicit nothrow enforcement for invariant may be unacceptable behavior.
That usage of invariants is unacceptable. Maybe they make use of a library which uses contract programming the right way and recieve a giant loss of performance caused by unneeded checks in the library. D has other devices to achieve the same "invariant" effect.
I don't say that current this change is essentially wrong, but I'm much worried that a built-in language semantics will reject system programming, especially if it requires runtime overhead. We should become very very carefully to add such runtime behavior.
There is no additional runtime overhead in release builds. Can you outline an example where these semantics reject system programming?
There was a problem hiding this comment.
For them, implicit nothrow enforcement for invariant may be unacceptable behavior.
I'm not going to enforce nothrow invariants, because all Exceptions get caught. You do so.
|
Okay, let's bring this back to life. Given that catching bugs is the only valid use of ExceptionsAll Reasons:
class Address {
private bool valid() { /* ... */ }
string value() { /* ... */ }
invariant() {
// 'valid' may throw an exception.
assert(valid);
}
}
void foo(Address a) {
// ...
auto v = a.value;
// ...
}
void bar(Address b) {
// ...
try {
b.foo;
} catch (Exception) {
// Silently eat the exception.
}
}
/**
* Validates a string.
* Throws: Exception if the string is invalid.
*/
void validate(string s) { /* ... */ }
struct S {
string val;
invariant() {
val.validate;
}
}
PurityPurity should be ignored when calling Reasons:
SafetyI'm not sure about this but I think the rules of Purity apply here, too. So you are able to call a throwing, impure and |
|
I agree completely. Having said that, |
|
And again I'd like to hear what @andralex, @WalterBright and @9rnsr think about this so I can get something implemented. |
I really do. |
|
Need to fix http://d.puremagic.com/issues/show_bug.cgi?id=3753 to make this work. |
|
This PR has a number of possible approaches. The difficulty is there are a number of attributes: that may apply to invariants. Currently, const is applied. The PR applies pure (but does not check it) and @trusted, and adds code to silently convert thrown Exceptions to Errors inside of nothrow functions. I'm uneasy with this. We also have backwards compatibility to be concerned about.
|
|
this has kinda bitrotten... please rebase? |
|
Don't have the time to rebase all that stuff. Feel free to close. May come back at some point. |
|
As this is still based on the C++ frontend, it might take a serious effort to revive it. |
|
I am planning on adopting this, however, I would like to iron down what is the way forward. After reading the comments, I personally think that the best strategy would be:
What do you think about this? @andralex @WalterBright @hpohl |
http://d.puremagic.com/issues/show_bug.cgi?id=4995
http://d.puremagic.com/issues/show_bug.cgi?id=10981