When should we use `expect` and when should we return error? - substrate

I saw many codes using expect. (In parity-bridges-common, frontier)
AFAIK the expect would cause a runtime panic.
And if we schedule a call that contains the expect part. That would break the chain.

expect should only be use when the code is never expected to fail. If there is any possibility that it might fail than the error should be appropriately handled.

Related

How can Go code plan for exceptions (panic)?

I do not know Go. I was going through the docs to get an idea of the language and came up against the Defer Panic Recover functionality.
Panic seems to work like exceptions. However I could not find how my code would guard against these exceptions, which can be thrown by layers deep below the ones I call. Java has checked exceptions. Does Go have something similar?
How does this work?
Edit: There seem to be 2 ways to think about this
Panic is very rare and it should be allowed to kill the program as described here
Panic can be used in the regular flow of code - as an example of defer panic as explained here, which describes how to use it for malformed input.
My question pertains to usage of panic in situations like 2, which seems to be easily doable.
Sure, you can use panic to control the regular flow of the program, but I think the more idiomatic way is to just return an error to the caller in such cases (like the case of malformed user input).
Panic is normally used in exceptional cases that imply some kind of a bug in the program. You can call the panic yourself if something goes wrong, but it's also called automatically in the case of nil pointer dereference, out of bounds array access and other similiar cases. Often things like this should crash the program, which it does by default, but if your program is some kind of service, you probably don't want the whole program to crash, you just want it to stop what it was doing when it encountered the crash and return to it's normal state.
Take a web server for example, if some strange request causes an out of bounds array access due to some bug. You don't want the whole server to crash, instead you want it to exit the handler function for that request, but keep listening for new requests. The way to do that is described pretty well in your example two. So you defer a recover() function in the place where you want the panic to stop. If the recover returns an error you know your program was paniccing. You can then do some logging, maybe send an email to yourself saying that something is wrong, etc., and then continue normal program flow. But if you had some validation function that noticed there's something wrong with the request, you probably wouldn't want it to panic. Instead you'd want it to return an error the the caller (request handler) which could then answer the request with 400 bad request, and then exit the handler normally.

Is function parameter validation using errors a good pattern in Go?

Is parameter validation using error return codes considered good practice ? I mean where should somebody use errors vs panics (are there any guidelines?).
For instance:
Is checking for non-nil + returning an error if it is nil a good
practice ?
Or checking for correct integer ranges etc.
I imagine that using errors that often would make Go feel very C-ish and would look pretty bad. Are panics a good alternative in those situations ?
Or should a Gopher use the Python/Ruby/JS-approach "just let it fail" ?
I'm a bit confused because panics are for real "errors" in my understanding. But using errors all the time is just bad.
And even if I would return error code: What could I do if somebody passes wrong parameter to my function but ignores the errors codes ? -> Nothing! So honestly I would say panics are nice for those situations but in a language where error codes are used over panics this is not very clear.
"Escaping" panics1 in Go (I mean, those which might be produced by the functions comprising the public API of your package) are to deal with errors programmers do. So, if your function gets a pointer to an object, and that can't be nil (say, to indicate that the value is missing) just go on and dereference the pointer to make the runtime panic itself if it happens to be nil. If a function expects an integer that must be in a certain range, panic if it's not in that range — because in a correct program all values which might be passed to your function are in that range, and if they don't then either the programmer failed to obey the API or they did not sanitize the value acquired from the outside which, again, is not your fault.
On the other hand, problems like failure to open a file or pefrorm some other action your function is supposed to perform when called correctly should not cause panics and the function should return an appropriate error instead.
Note that the recommendation for explicit checking for null parameters in the functions of public APIs in .NET and Java code has different goal of making such kinds of errors sort-of more readable. But since 99% of .NET and Java code just lets all the exceptions propagate to the top level (and then be displayed or may be logged) it's just replacing one (generated by runtime) exception with another. It might make errors more obvious—the execution fails in the API function, not somewhere deeper down the call stack—but adds unnecessary cruft to these API functions. So yes, this is opinionated but my subjective opinion is: to let it just crash is OK in Go—you'll get a descriptive stack trace.
TL;DR
With regard to processing of run-time problems,
panics are for programming errors;
returning errors is for problems with carrying out the intended tasks of functions.
1 Another legitimate use for panics is quick "cold-path" returning from deep recursive processing/computation; in this case panic should be caught and processed by your package, and the corresponding public API functions should return errors. See this and this for more info.
The answer to this is subjective. Here are my thoughts:
Regarding panic, I like this quote from Go By Example (ref)
A panic typically means something went unexpectedly wrong. Mostly we use it to fail fast on errors that shouldn’t occur during normal operation, or that we aren’t prepared to handle gracefully.
In the description of your use case, I would argue that you should raise an errors and handle the errors. I would further argue that it is good practice to check the error status when one is provided by the function you are using and that the user should check if one is provided in the documentation.
Panics I would use to stop the execution if I run across an error that is returned from the function you are writing that I check and don't have a way to recover from.

If as assert fails, is there a bug?

I've always followed the logic: if assert fails, then there is a bug. Root cause could either be:
Assert itself is invalid (bug)
There is a programming error (bug)
(no other options)
I.E. Are there any other conclusions one could come to? Are there cases where an assert would fail and there is no bug?
If assert fails there is a bug in either the caller or callee. Why else would there be an assertion?
Yes, there is a bug in the code.
Code Complete
Assertions check for conditions that
should never occur. [...]
If an
assertion is fired for an anomalous
condition, the corrective action is
not merely to handle an error
gracefully- the corrective action is
to change the program's source code,
recompile, and release a new version
of the software.
A good way to
think of assertions is as executable
documentation - you can't rely on them
to make the code work, but they can
document assumptions more actively
than program-language comments can.
That's a good question.
My feeling is, if the assert fails due to your code, then it is a bug. The assertion is an expected behaviour/result of your code, so an assertion failure will be a failure of your code.
Only if the assert was meant to show a warning condition - in which case a special class of assert should have been used.
So, any assert should show a bug as you suggest.
If you are using assertions you're following Bertrand Meyer's Design by Contract philosophy. It's a programming error - the contract (assertion) you have specified is not being followed by the client (caller).
If you are trying to be logically inclusive about all the possibilities, remember that electronic circuitry is known to be affected by radiation from space. If the right photon/particle hits in just the right place at just the right time, it can cause an otherwise logically impossible state transition.
The probability is vanishingly small but still non-zero.
I can think of one case that wouldn't really class as a bug:
An assert placed to check for something external that normally should be there. You're hunting something nutty that occurs on one machine and you want to know if a certain factor is responsible.
A real world example (although from before the era of asserts): If a certain directory was hidden on a certain machine the program would barf. I never found any piece of code that should have cared if the directory was hidden. I had only very limited access to the offending machine (it had a bunch of accounting stuff on it) so I couldn't hunt it properly on the machine and I couldn't reproduce it elsewhere. Something that was done with that machine (the culprit was never identified) occasionally turned that directory hidden.
I finally resorted to putting a test in the startup to see if the directory was hidden and stopping with an error if it was.
No. An assertion failure means something happened that the original programmer did not intend or expect to occur.
This can indicate:
A bug in your code (you are simply calling the method incorrectly)
A bug in the Assertion (the original programmer has been too zealous and is complaining about you doing something that is quite reasonable and the method will actually handle perfectly well.
A bug in the called code (a design flaw). That is, the called code provides a contract that does not allow you to do what you need to do. The assertion warns you that you can't do things that way, but the solution is to extend the called method to handle your input.
A known but unimplemented feature. Imagine I implement a method that could process positive and negative integers, but I only need it (for now) to handle positive ones. I know that the "perfect" implementation would handle both, but until I actually need it to handle negatives, it is a waste of effort to implement support (and it would add code bloat and possibly slow down my application). So I have considered the case but I decide not to implement it until the need is proven. I therefore add an assert to mark this unimplemented code. When I later trigger the assert by passing a negative value in, I know that the additional functionality is now needed, so I must augment the implementation. Deferring writing the code until it is actually required thus saves me a lot of time (in most cases I never imeplement the additiona feature), but the assert makes sure that I don't get any bugs when I try to use the unimplemented feature.

How to distinguish a Win32 socket handle from other pipe handles?

I need to determine whether a handle that my code did not create, for which GetFileType()==FILE_TYPE_PIPE, is a socket or not. There does not seem to be an API for this.
I have tried the following. The general idea is to use a socket-specific function and treat failure as meaning non-socket.
getsockopt() -- This was my first attempt. Unfortunately it seems to hang when called by many threads on the same (non-socket) handle.
WSAEnumNetworkEvents() -- this is what Gnulib does but will have undesirable side effects if the handle is a socket.
getpeername() -- this is what cygwin does but this will fail for some sockets too. Guessing whether an error implies socket-ness does not seem reliable and future safe.
I do not mind if the solution only work on some versions of Windows, e.g. Vista, I can always fall back to some other method in the general case.
I'm thinking that perhaps you could attempt to call GetNamedPipeInfo() on your handle. If the call succeeds you know that the handle is a pipe handle, otherwise it must be a socket.
Have you tried WSADuplicateSocket. Then just check WSAPROTOCOL_INFO to see if it is in fact a named pipe...
You can use GetNamedPipeHandleState() as well, evaluating the result with GetLastError().

Test Cases AND assertion statements

The code in this question made me think
assert(value>0); //Precondition
if (value>0)
{
//Doit
}
I never write the if-statement. Asserting is enough/all you can do.
"Crash early, crash often"
CodeComplete states:
The assert-statement makes the application Correct
The if-test makes the application Robust
I don't think you've made an application more robust by correcting invalid input values, or skipping code:
assert(value >= 0 ); //Precondition
assert(value <= 90); //Precondition
if(value < 0) //Just in case
value = 0;
if (value > 90) //Just in case
value = 90;
//Doit
These corrections are based on assumptions you made about the outside world.
Only the caller knows what "a valid input value" is for your function, and he must check its validity before he calls your function.
To paraphrase CodeComplete:
"Real-world programs become too messy when we don't rely solely on assertions."
Question: Am I wrong, stuborn, stupid, too non-defensive...
The problem with trusting just Asserts, is that they may be turned off in a production environment. To quote the wikipedia article:
Most languages allow assertions to be
enabled or disabled globally, and
sometimes independently. Assertions
are often enabled during development
and disabled during final testing and
on release to the customer. Not
checking assertions avoiding the cost
of evaluating the assertions while,
assuming the assertions are free of
side effects, still producing the same
result under normal conditions. Under
abnormal conditions, disabling
assertion checking can mean that a
program that would have aborted will
continue to run. This is sometimes
preferable.
Wikipedia
So if the correctness of your code relies on the Asserts to be there you may run into serious problems. Sure, if the code worked during testing it should work during production... Now enter the second guy that works on the code and is just going to fix a small problem...
Use assertions for validating input you control: private methods and such.
Use if statements for validating input you don't control: public interfaces designed for consumption by the user, user input testing etc.
Test you application with assertions built in. Then deploy without the assertions.
I some cases, asserts are disabled when building for release. You may not have control over this (otherwise, you could build with asserts on), so it might be a good idea to do it like this.
The problem with "correcting" the input values is that the caller will not get what they expect, and this can lead to problems or even crashes in wholly different parts of the program, making debugging a nightmare.
I usually throw an exception in the if-statement to take over the role of the assert in case they are disabled
assert(value>0);
if(value<=0) throw new ArgumentOutOfRangeException("value");
//do stuff
I would disagree with this statement:
Only the caller knows what "a valid
input value" is for your function, and
he must check its validity before he
calls your function.
Caller might think that he know that input value is correct. Only method author knows how it suppose to work. Programmer's best goal is to make client to fall into "pit of success". You should decide what behavior is more appropriate in given case. In some cases incorrect input values can be forgivable, in other you should throw exception\return error.
As for Asserts, I'd repeat other commenters, assert is a debug time check for code author, not code clients.
Don't forget that most languages allow you to turn off assertions... Personally, if I was prepared to write if tests to protect against all ranges of invalid input, I wouldn't bother with the assertion in the first place.
If, on the other hand you don't write logic to handle all cases (possibly because it's not sensible to try and continue with invalid input) then I would be using the assertion statement and going for the "fail early" approach.
If I remember correctly from CS-class
Preconditions define on what conditions the output of your function is defined. If you make your function handle errorconditions your function is defined for those condition and you don't need the assert statement.
So I agree. Usually you don't need both.
As Rik commented this can cause problems if you remove asserts in released code. Usually I don't do that except in performance-critical places.
I should have stated I was aware of the fact that asserts (here) dissappear in production code.
If the if-statement actually corrects invalid input data in production code, this means the assert never went off during testing on debug code, this means you wrote code that you never executed.
For me it's an OR situation:
(quote Andrew) "protect against all ranges of invalid input, I wouldn't bother with the assertion in the first place." -> write an if-test.
(quote aku) "incorrect input values can be forgivable" -> write an assert.
I can't stand both...
For internal functions, ones that only you will use, use asserts only. The asserts will help catch bugs during your testing, but won't hamper performance in production.
Check inputs that originate externally with if-conditions. By externally, that's anywhere outside the code that you/your team control and test.
Optionally, you can have both. This would be for external facing functions where integration testing is going to be done before production.
A problem with assertions is that they can (and usually will) be compiled out of the code, so you need to add both walls in case one gets thrown away by the compiler.

Resources