| |
|
Jonathan M Davis 
| On Friday, July 4, 2025 10:30:02 AM Mountain Daylight Time Richard (Rikki) Andrew Cattermole via Digitalmars-d wrote:
> On 05/07/2025 4:18 AM, Jonathan M Davis wrote:
> This is exactly my point. They are tuned wrong.
>
> They are currently acting as an internal detail of a function, and that has no business being exposed at the function API level.
>
> Other programmers do not need this information.
>
> What they need is logic level criteria for a function to work.
>
> The purpose of contracts first and foremost is to document the requirements of a called function and they are currently not succeeding at this job, because their focus is on internal details rather than external.
I don't know why you think that their focus is on internal details. At least with in contracts, they're used to assert the state of the function's arguments. They're verifying that the caller is following the contract that the function gives for its input, and if the documentation is written correctly, then those requirements are in the documentation. And if the caller passes any arguments which fail the contract, then it's a bug in the caller. So, the contracts are essentially test code for the calling code.
Now, contracts as they currently stand in D _are_ flawed, but not because of how assertions work. They're flawed because of how the contracts themselves are implemented.
How they should have been implemented is for them to be compiled in based on the compilation flags of the caller, not the ones used when compiling the function itself. So, if you were using a library with contracts, and you compiled your code with assertions compiled in, then you'd get the checks that are in the contracts, and if you compiled without assertions (presumably, because it was a production build), then they wouldn't be compiled in. They're testing the caller's code, not the function's code, so whether the contracts are compiled in should depend on how the caller is compiled.
However, the way that contracts are currently implemented is that they're part of the function itself instead of being attached to it, and whether they're compiled in or not depends on how the function itself is compiled. This means that contracts are effectively broken unless they're used in templated code.
And that's why personally, I never use contracts. I think that the idea is sound, but the implementation is flawed due to how they're compiled in.
So, ignoring the issue of classes, I don't at all agree that AssertErrors need to be recoverable, because they're used in contracts. Contracts are like any other assertion in the sense that they're catching a bug in the code, not validating user input.
That being said, the fact that the contracts on virtual functions have to catch AssertErrors and potentially ignore them (due to the relaxing or tightening of contracts based on inheritance) means that yes, AssertErrors need to be recoverable in at least the context of classes. The programmer really shouldn't be trying to recover from AssertErrors, but the runtime actually has to within that limited context - and for that to work properly, destructors and other clean up code actually needs to work properly when AssertErrors are thrown in the contracts of virtual functions.
But if you're arguing that programmers should be trying to recover from failed contracts, then I don't agree at all. They're intended for catching code that fails to stick to a function's contract in debug builds, and that's really not a situation where there should even be a need to consider recovering from an AssertError.
If a programmer wants to write a function where the arguments are checked, and the intention is that the program will recover when bad arguments are given, then Exceptions should be used, not assertions.
- Jonathan M Davis
|