-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce defects
/ forbidDefects
pragma to enable tracking defects
#493
Comments
We already have
From the optimizer's perspective a |
One of the biggest hidden defects is the |
You're right that for many users I know this use case is somewhat rare, but in my mind it's an important part of a "real" systems language. Though of course if you ask 8 programmers what "systems language" is you'll get 12.5 answers. My position on panics is largely what Torvalds discussed in a linux mailing list due to the sorta problems I work on. Actually I've actually wanting to write a Linux driver in Nim – mostly for fun. Panics would be unacceptable in that scenario. This is part of why I dislike Rust programming -- handling all error cases with However, that's a bit off topic of the PR. I believe that adding a For example, I could envision cases of using
It would be awesome to prove index bounds safe. However, I'm skeptical we could do so in every case (inject some hand wavy pointing to the halting problem). IMHO there will always be some need for runtime bounds checking. A bit further out there, but flips from cosmic rays are not only possible, but statistically guaranteed (see some stats). Obviously this isn't possible to be solved generally, but rather given that array indexing is such a key action, it seems prudent to be able to check it even it shouldn't be possible to incorrectly index something.
Good points, though see above I don't trust even verified code to not run into these errors. There's probably lots to learn from Ada/SPARK, which seems to still use a mix of compile and runtime checking:
What's an OS? ;) Yes you can reboot with a watchdog, but how to you record and log error/defects/etc if the world just dies? Again I refer to Linus's reasoning in the LKML link. Ideally OOM should be treated in some cases as just another possible failure. You get a too large JSON to parse due to OOM, post it's often better to return an error and not kill the kernel, device, etc. |
@beef331 the |
That's an understatement, I'd wager any library that uses subrange types has a range defect bug somewhere. |
Conversions between subranges that are not value preserving at compile-time are explicit conversions. What's there to do about them, they are explicit. |
import std/times
echo parse("61", "mm") Is the most poignant example I can provide that demonstrates the present issue with subrange types. To use the |
That only demonstrates a problem with times.nim unless there is no explicit conversion code in times.nim. |
The conversion from base to subrange is implicit through the procedure call https://github.com/nim-lang/Nim/blob/version-1-6/lib/pure/times.nim#L2001 There is no visible explicit conversion. It's all done in procedure dispatch. Which I would like to believe hid the bug that the code presently does not ensure the parsed values are within range. |
Does Also, I am uninformed about this discussion but if defects are so different from catchable exceptions (which you don't "catch", you "except") in their intended behavior but they still have to be exception types, why bother separating them in the type system and not how they're called, i.e. |
Bummer. That's bad. :-) |
I don't know, but I assume that one can use some fixed size preallocated memory for communication with the watchdog.
Yes, I know Linus's "reasoning". But it makes little sense since in reality every function call can trigger an OOM just by the sake of being a call which needs stack space. And the stack size is 4KB or 8KB for the kernel. Mapping both heap OOM and stack OOM to an exception/defect that can be turned into ENOMEM via We should embrace exceptions and forget about the idea of static checking runtime errors that are about arbitrary run-time resource constraints. But this would be against the current zeitgeist with |
It depends a lot of the device. At the simplest the watchdog is literally just a GPIO pin connected to a timer. Though you could leave a bit of memory for logging, though sometimes the watchdog will reset the whole power system and you'll loose the ram too. Generally you may be fine with loosing your networking as it restarts, but not a thread controlling hardware. Hmmm, generally speaking I guess if a panic is limited to a thread that'd handle my concerns -- but I think panics kill a whole process? I actually sorta dig that concept... Would changing panics to "thread-local" be possible or even help with the codegen optimization issues? If so then building on the It reminds me of Erlang/Elixir's style of treating each thread (actor) as a separate process with exceptions but also "panics" of sorts. It requires architecting code differently but makes the overall system more predictable. If an actor dies, you can decide if it's parent actor dies too, or just gets an interrupt/signal to let it know. Divide by zeroes would effectively kill the current actor, and you can't catch it as a normal exception. https://learnyousomeerlang.com/errors-and-processes
That's a good point about the stack memory. I'm used to having a pre-allocated stack and a you-better-be-happy-with-it setup. Hmmm, some googling seems to indicate that the kernel uses a static stack as well, so that 4kb/8kb seems to be all a kthread gets:
That sounds like too much sophistry! ;) Though it sounds like linux kernel just requires the stack to be static, and you better not go over it. I'd be curious to know how Ada/SPARK treats it.
haha, fair point. Mainly I just like to know what things are possible. Hence this PR. Even if I can't handle the case, it's nice to know what defects are possible. |
Yes, Erlang gets this right. |
Abstract
Introduce a
defects
pragma to track defects similar to tracking exceptions via theraises
pragma. This would include adding a parallel pragma toforbids
likeforbidDefects
. Alternativelyforbids
may be able to extended to support both defects and exceptions since it's a mechanism for filtering and not declaration.Goals would be to provide tracking of defects. It does include making the standard library consistent, though this would be useful tooling for that goal. It would also give end users more control over what error mechanisms they want to allow or to ban.
Motivation
It's somewhat confusing dealing with defects vs raises as an "end user". I didn't really know about
defects
for many months after learning and using Nim and thoughtraises:[]
would cover all error cases. Little did I know! ;)On the one hand
raises:[]
andforbids:[X]
are helpful but can lead to missing important defects likeIndexDefect
when using a library. The standard library is a bit inconsistent between when exceptions and defects are used. I believe that this is partly due to not having the ability to usefully track the difference.Prior to
forbids:[XYZ]
effects tracking weren't particularly useful for forbidding only a subset of effects. Whileforbids
was a small change it made tracking and utilizing effects substantially more useful. Panics can be implemented using exceptions or not, so it makes since to keep them separate fromraises
, but now they don't benefit from this change.Adding a
defects: []
andforbidDefects: []
/forbids:[defect]
would enable more precise tracking. This would enable useful discussions on whether an exception or defect makes sense, while enablingpanics:on
andpanics:off
camps to do what they will with them.Finally adding a
defects
effects pragma would – I believe – be a step toward making the standard library and other libraries more consistent.Description
The idea of a
defects: []
has been discussed before. However, this was beforeforbids:[XYZ]
which I believe enhances the utility of bothraises: []
and a possibledefects: []
.The previous discussion in issue 180 propsed an alternative exceptions hierarchy. This seemed too complicated and would require a larger re-work with probably breaking changes. This proposal is more about refining the system as it exists to make things more consistent rather than replacing it.
One benefit of tracking
defects
andforbidDefects
would be enabling users to know what error cases a library uses or can exhibit. One use case could be to avoid libraries that provide certain defects.To be clear: this proposal isn't about fixing the defects/exceptions split or the standard library but providing basic tooling and annotations to help with those decisions. Ideally this could then be adopted in the standard library to make it more consistent.
There's lots of discussions on this topic. Here's a few I found:
system.Defect
should not be tracked #77Code Examples
Very short example to show a possible use cases. These aren't too well thought out but hopefully show some use cases:
Alternatively
forbids
may be able to be extended to support both defects and exceptions while not causing conflicts between them:Backwards Compatibility
As far as I know this wouldn't affect backwards compatibility.
The text was updated successfully, but these errors were encountered: