-
Notifications
You must be signed in to change notification settings - Fork 23
enforce: like doAssert for for catchableExceptions + allows customizing exception type #266
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
Comments
The if statement is clear and readable, "encourages" writing proper error messages and is not something people will have to search for in the documentation. I don't think the stdlib is the right place for these tiny, highly specific one-char-savers that will never be used in practice because nobody searches the stdlib for "enforce" trying to save themselves from writing a perfectly normal if statement. |
how is that a 1-char saver? if not condition:
raise newException(msg, SomeException)
vs
# in simplest form: still produces informative msg: `(pathto/file(2,3): "a == 1" failed [CatchableError]`
enforce a == 1
# or with optional msg (when `a == 1` isn't enough) and typ (when the default `CatchableError` isn't desirable), as shown in top post and you're missing this point:
|
I like it except for the idea that the error message is produced automatically from the source code. Tying the error message to a particular implementation is amateurish, error messages that a system produces should be stable so that people can search the internet for them, sometimes they are translated into other languages etc. |
I think this should be designed with DrNim preCondition/postCondition, ascertain/ensure in mind so that we don't have too many "contract" words. Otherwise I agree, the if + raise is quite long. |
it's no different from
I can change to |
DrNim uses The "keywords" used are:
|
These are all not supposed to be error messages for end-users! |
you could argue uncaught exceptions also shouldn't reach end-users. The reality is that we routinely have to read both exceptions and assertions, whether during development or in realeased software. The condition is almost always useful to show and not showing it would just lead one to paraphrase the condition and translating to english, often loosing in precision. eg from os.nim: if file.isNil:
raise newException(IOError, "File is nil") with condition rendered and message omitted: # shows: 'file.isNil' failed [IOError]
enforce file.isNil, typ=IOError this is simpler to read/write the code and results in error message that is no worse than the following where the condition is not rendered and message compulsory: enforce file.isNil, "File is nil", IOError A good Most of the examples are similar:
if not root.isAbsolute:
raise newException(ValueError, "The specified root is not absolute: " & root)
=>
# simpler:
enforce root.isAbsolute, fmt"{root=}, ValueError which shows: 'root.isAbsolute' failed; root="main.nim" [ValueError] if dir.len == 0: # treating "" as "." is error prone
raise newException(ValueError, "dest is empty")
=>
enforce dir.len == 0, typ=ValueError here the autogenerated message 'dir.len == 0' is enough since the context wouldn't add any useful information |
Well you said it yourself:
vs.
Which one do you think can be translated into other languages?
Agreed, which is why we should nudge programmers into clear error messages and not seduce them to save keystrokes, user-experience be damned. |
This looks like an ad-hoc workaround for a proper DbC module, I would prefer a proper DbC module on stdlib. |
if you change Exceptions (or at least return codes) are fundamental to correctness, eg try writing Furthermore, the overhead of any condition checking in things like os.nim will be dwarfed by the cost of the actual system call, so it's a false saving. Hence my comment here: nim-lang/fusion#19 (comment) regarding note regarding external vs internal dataexternal input for a publicly exposed proc covers input arguments and depending on cases other global data (eg environment variables accessed) since it could be accessed by any client. |
I am not saying the idea is bad, I am just saying why not make a assert a > b
assert b > 0
assert a > 0
assert a < int.high
assert b < int.high Something like: enforce a > b, b > 0, a > 0, a < int.high, b < int.high I would prefer the naming |
Looking forward to seeing this in your next library, @timotheecour. |
This RFC is stale because it has been open for 1095 days with no activity. Contribute a fix or comment on the issue, or it will be closed in 30 days. |
Uh oh!
There was an error while loading. Please reload this page.
Too many times I see assert or doAssert being used in a place where a catchableException should've been used, because:
The current approach is to use:
while this works, it has following drawbacks:
assert condition
orassert condition, msg
CatchableException
condition
isn't renderedproposal
enforce
, which works likedoAssert
, but by default raises a CatchableException; the exception type can be customizedstd/asserts
containingenforce
; (catchable + customizable doAssert ) Nim#15606example
precedent
in D, they also use both
assert
andenforce
: https://dlang.org/library/std/exception/enforce.htmlThe text was updated successfully, but these errors were encountered: