• 0 Posts
  • 75 Comments
Joined 2 years ago
cake
Cake day: September 2nd, 2023

help-circle

  • I know this thread is old. But I disagree with you.

    I agree that depending on how you use a debugger, some race conditions might not happen.

    However, I don’t agree that debuggers are useless to fix race conditions.

    I have a great example that happened to me to prove my point:

    As I was using a debugger to fix a normal bug, another quite strange unknown bug happened. That other bug was indeed a race condition. I just never encountered it.

    The issue was basically:

    1. A request to initiate a session arrives
    2. That request takes so long that the endpoint decides to shut down the session
    3. A request to end the session arrives

    And so handling the session start and session end at the same time resulted in a bug. It was more complicated than this (we do use mutexes) but it was along those lines.

    We develop in a lab-like condition with fast networking and computers, so this issue cannot happen on its own. But due to the breakpoint I put in the session initiation function, I was able to observe it. But in a real world scenario it is something that may happen.

    Not only that, I could reproduce the “incredibly rare” race condition 100% of the time. I just needed to place a breakpoint in the correct place and wait for some amount of time.

    Could this be done without a debugger? Most of the time yes, just put a sleep call in there. Would I have found this issue without a debugger? Not at all.

    An even better example:

    Deadlocks.

    How do you fix a deadlock? You run the program under a debugger and make the deadlock happen. You then look at which threads are waiting at a lock call and there’s your answer. It’s as simple as that.

    How do you print-debug a deadlock? Put a log before and after each lock in the program and look at unpaired logs? Sounds like a terrible experience. Some programs have thousands of lock calls. And some do them at tens of times per second. Additionally, the time needed to print those logs changes the behaviour of the program itself and may make the deadlock harder to reproduce.






  • Same thing with git.

    There is no shortage of git beginners that refuse to use a GUI.

    They ask for help for something, I haven’t used git CLI in years, so I tell them “go to this place and click those button”, then they open the vscode terminal and ask “but can I do it from CLI?” Okay then I go to search the command. Meanwhile I tell them to checkout a branch or something as basic as that and watch them struggle for way longer than it took me to find the command I was looking for.

    I get that thousands of elitists have convinced you that using git from a GUI is a sin. But it’s fine, I won’t tell no one. I use a GUI myself.


  • The C example is the wonderful happy path scenario that only manifests in dreams.

    Most projects don’t have a dependency list you can just install in a single apt command. Some of those dependencies might not be even available on your distro. Or there is only a non-compatible version available. Or you have to cast some incantation to make that dependency available.

    Then you have to set some random environment variables. And do a bunch of things that the maintainers see as obvious since they do it every day, so it’s barely documented.

    And once you have it installed, you go to run it but discover that the fantastic CLI arguments you found online that would do what you installed this program to do, are not available in your version since it’s too new and the entire CLI was reworked. And they removed the functionality you need since it was “bad practice and a messy way to do things”.

    All of this assuming the installation process is documented at all and it’s not a “just compile it, duh, you should know how to do it”.


  • In my case, I don’t usually encounter cases where I can’t just ?. But when I do, just make an error enum (kinda like thiserror) that encapsulates the possible errors + possibly adds more.

    On the call site, just convert to string if I don’t care about specifics (anyhow-style).

    I don’t find this much painful.

    Concise: not much on the declaration side, since you have to create an entire enum for each function in worst-case scenario. But on code side, it’s just .map_err(MyError)?.

    Type-safe: can’t beat errors as enum values wrapped in Result.

    Composable: i don’t think you can beat rust enums in composability.

    I don’t use anyhow/thiserror, so I’m not sure. But I believe thiserror fixes the conciseness issue for this.



  • Rust allows you to choose whatever method you want.

    • Early return propagating the error
    • Early return ignoring the error (maybe by returning a default value)
    • Explicit handling by if-else (or match) to distinguish between error and not error cases.
    • Early return and turn the error into another type that is easier to handle by the caller.
    • Assume there is no error, and just panic if there is. (.unwrap)

    There are only 2 error handling methods that you cannot do:

    • Exceptions
    • Ignore the error and continue execution

    And that is because both of them are bad because they allow you to do the second one, when .unwrap is just there and better.

    If your concept of “not ugly” is “I just want to see the happy path” then you either write bad code that is “not ugly” or write good code that is “ugly”. Because there is no language that allows you to handle errors while not having error handling code near where the errors are produced.




  • You used macro_rules, which is not common at all. Most rust files don’t contain any macro definition.

    This code doesn’t even compile. There is a random function definition, and then there are loose statements not inside any code block.

    The loop is also annotated, which is not common at all, and when loops are annotated it’s a blessing for readability. Additionally, the loop (+annotation) is indented for some reason.

    And the loop doesn’t contain any codeblock. Just an opening bracket.

    Also, the function definition contains a lifetime annotation. While they are not uncommon, I wouldn’t say the average rust function contains them. Of course their frequency changes a lot depending on context, but in my experience most functions I write/read don’t have lifetime annotations at all.

    Yes, what you wrote somewhat resembles rust. But it is in no way average rust code.







  • My comment explicitly avoids the “standard” problem.

    A user could have many "theming system"s installed at once, while only having 1 DE. The user ideally would configure only one, and some program should try to translate that system into the other ones.

    Then each app will fetch the list of theming systems the user has installed, and choose whichever the app prefers. And if there’s no match, fall back to a default hard coded theme.