How do you handle error checking? I always feel sad after I add error checking to a code that was beautifully simple and legible before.
It still remains so but instead of each line meaning something it becomes if( call() == -1 ) return -1; or handleError() or whatever.
Same with try catch if the language supports it.
It's awful to look at.
So awful I end up evading it forever.
"Malloc can't fail right? I mean it's theoetically possible but like nah", "File open? I'm not gonna try catch that! It's a tmp file only my program uses come oooon", all these seemingly reasonable arguments cross my head and makes it hard to check the frigging errors. But then I go to sleep and I KNOW my program is not complete. It's intentionally vulnerable. Fuck.
How do you do it? Is there a magic technique or one has to reach dev nirvana to realise certain ugliness and cluttering is necessary for the greater good sometimes and no design pattern or paradigm can make it clean and complete?

  • 1
    You could hide at least a part of it in macros
  • 0
    @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.
  • 1
    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.
  • 1
    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...)
  • 1

    match call() {
    Ok(value) => println!("Value: {}", value),
    Err(error) => panic!("Error {} caught", error)

    // You can't miss it.
    // The compiler will whine of you do.
  • 1
  • 1
    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.
  • 0
    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.
  • 0
    I guess any non-zero return code is fail code. Why don't you check it for being a zero?
  • 0
    @martikyan Sometimes not. Example: recv will return -1 on error and 0 is not an error.
  • 0
    @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
  • 2
    @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.
  • 0
    @Voxera I have a feeling you have one specific language in mind. Wouldn't mind getting a specific mention to try and look into :)
  • 1
    @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.
  • 2
    @Voxera Thanks ma'am. Will check this out. See if it was what I was looking for.
Add Comment