Do all the things like ++ or -- rants, post your own rants, comment on others' rants and build your customized dev avatarSign Up
From the creators of devRant, Pipeless lets you power real-time personalized recommendations and activity feeds using a simple APILearn More
You could hide at least a part of it in macros
@electrineer Yeah I gave that a go.
#define SAFE_CALL(call) if(call == -1) return -1;
#define SAFE_CALLNZ(call) if(call != 0) return -1;
But it feels wrong. That macro is gonna cut my method off and sometimes I'm gonna use it and sometimes not and then I'll read it and think "Shouldn't all calls be safe?" and all mfrigging calls would end up enclosed in those frigging macros. It'd be horrible.
It's just a part of the program's duty to check for runtime errors. It has to exist somewhere. It shouldn't be a problem if the code is otherwise well structured.
There's no magic technique. In the end you just have to realize that making your code functional is more important than making it clean or pretty. If it's ugly but it works, then at least it works. If it's pretty and clean but doesn't work, then it's useless. Error checking is so important that even if it makes my code messier, I don't care.
Of course, both is ideal, but one has to take priority in cases like this.
That said, if error checking is making your code ugly, then maybe you should rethink how it's structured. I've never really felt it was all that cumbersome to implement. In fact, I quite like try/catch. It still seems well-structured when I use it, and I vastly prefer it to certain other alternatives (looking at you, Golang...)
Try to minimize the scope of each function so you do not need multiple different error checks in it. Then you can often get away with having it in the beginning or the end which leaves the rest if the logic more clean.
And try to make sure to understand on which level you need it. If a certain subtree is a unit of work and any error will have the same resolution you can have a bit more coarse internal checking and handle problems on the outside.
But well written error handling should be part of the overall logic.
That means the code will be better to recover from the error and not just die with a (in best case) good exception.
Yeah sometimes using a single method or function, gives multiple exception. But as i know like because of different exceptions , there will be only one error, so I add multi catch blocks.
And the muti block catch is rarely called, mostly only when testing with some random incorrect inputs .
Before I used to have throw exception instead, but it made the method names and calling messy as I had to mention same throw each time I use that method, but adopting try catch and multi catch , I don't need to use and write throw each time I call the method.
And In like other cases there are always, success, and error cases so I like add sometimes consoles to expect error that never shows up.
I guess any non-zero return code is fail code. Why don't you check it for being a zero?
@electrineer @EmberQuill @aggelalex @Voxera Yeah ok. This is more or less what I expected to get. Thanks, needed the confirmation guys. Then there's no avoiding it. Just gotta handle the errors and slightly clutter up each call prone to error in the case of C and try catch them relevant blocks with C# java etc.
Thanks for the correct though disappointing input. feels.png
@OneOfSimpleMind what one can do it is to isolate any calls out of the application and handle errors from those there and try to keep the rest clean.
A lot can be achieved by using good data structures inside your code, and especially if you use a language that can support good typing or dynamic typing.
Then errors can be just another state the code handles.
Look at how many functional languages uses pattern matching.
Its pretty elegant, and you can often come close even if the language does not quite support it.
@OneOfSimpleMind not really, F# or any Ocaml varieties, typescript (has some support for advanced types, scala, haskel, rust even C# has rudimentary support but not quite the same
All support some form of more advanced types, and there are probably better examples.
But the idea is like in typescript or ocaml derivatives that a function can return data | error
Then your code uses patten matching to se which it was, and data could even be different things with there own patterns.
So error handling is just another pattern and does not add any extra structural complexity, just a few more lines in the same structure.
Most functional languages support something like this.