[-] o11c@programming.dev 1 points 10 months ago

For one thing: don't bother with fancy log destinations. Just log to stderr and let your daemon manager take care of directing that where it needs to go. (systemd made life a lot easier in the Linux world).

Structured logging is overrated since it means you can't just do the above.

Per-module (filterable) logging are quite useful, but must be automatic (use __FILE__ or __name__ whatever your language supports) or you will never actually do it. All semi-reasonable languages support some form of either macros-which-capture-the-current-module-and-location or peek-at-the-caller-module-name-and-location.


One subtle part of logging: never conditionally defer a computation that can fail. Many logging APIs ultimately support something like:

if (log_level >= INFO) // or <= depending on how levels are numbered
    do_log(INFO, message, arguments...)

This is potentially dangerous - if logging of that level is disabled, the code is never tested, and trying to enable logging later might introduce an error when evaluating the arguments or formatting them into the message. Also, if logging of that level is disabled, side-effects might not happen.

To avoid this, do one of:

  • never use the if-style deferring, internally or externally. Instead, squelch the I/O only. This can have a significant performance cost (especially at the DEBUG level), which is why the API is made in the first place.
  • ensure that your type system can statically verify that runtime errors are impossible in the conditional block. This requires that you are using a sane language and logging library.
  • run your testsuite at every log level, ensure 100% coverage of log code, and hope that the inevitable logic bug doesn't have an unexpected dynamic failure.
[-] o11c@programming.dev 2 points 10 months ago

ReplaceFile exists to get everyone else's semantics though?

[-] o11c@programming.dev 1 points 1 year ago* (last edited 1 year ago)

True, but successfully doing dynamically-linked old-disto-test-environment deployments gets rid of the real reason people use static linking.

[-] o11c@programming.dev 2 points 1 year ago

If there's a .pc file shipped, pkg-config can simplify your life by figuring out the flags for you.

[-] o11c@programming.dev 2 points 1 year ago

The problem is that the application developer usually thinks they know everything about what they want from their dependencies, but they actually don't.

[-] o11c@programming.dev 2 points 1 year ago

The problem is that what everybody really wants is parameterization, not concatenation. But most solutions therefor are flaky even if they exist.

[-] o11c@programming.dev 3 points 1 year ago

It's solving (and facing) some very interesting problems at a technical level ...

but I can't get over the dumb decision for how IO is done. It's $CURRENTYEAR; we have global constructors even if your platform really needs them (hint: it probably doesn't).

[-] o11c@programming.dev 2 points 1 year ago

There's probably a way to do "specify icon as part of the linker call" which should be easier.

[-] o11c@programming.dev 1 points 1 year ago

and I already explained that Union is a thing.

[-] o11c@programming.dev 2 points 1 year ago

chunks: [AtomicPtr>; 64], appears before the explanation of why 64 works, and was confusing at first glance since this is completely different than the previous use of 64, which was arbitrary. I was expecting a variable-size array of fixed-size arrays at first (using something like an rwlock you can copy/grow the internal vector without blocking - if there was a writer, the last reader of the old allocation frees it).

Instead of separate flags, what about a single (fixed-size, if chunks are) atomic bitset? This would increase contention slightly but that only happens briefly during growth, not accesses. Many architectures actually have dedicated atomic bit operations though sadly it's hard to get compilers to generate them.

The obvious API addition is for a single thread to push several elements at once, which can be done more efficiently.

[-] o11c@programming.dev 2 points 1 year ago

All of these can be done with raw strings just fine.

For the first pathlib bug case, PATH-like lookup is common, not just for binaries but also data and conf files. If users explicitly request ./foo they will be very upset if your program instead looks at /defaultpath/foo. Also, God forbid you dare pass a Path("./--help") to some program. If you're using os.path.dirname this works just fine.

For the second pathlib bug case, dir/ is often written so that you'll cause explicit errors if there's a file by that name. Also there are programs like rsync where the trailing slash outright changes the meaning of the command. Again, os.path APIs give you the correct result.

For the article mistake, backslash is a perfectly legal character in non-Windows filenames and should not be treated as a directory component separator. Thankfully, pathlib doesn't make this mistake at least. OTOH, / is reasonable to treat as a directory component separator on Windows (and some native APIs already handle it, though normalization is always a problem).

I also just found that the pathlib.Path constructor ignores extra kwargs. But Python has never bothered much with safety anyway, and this minor compared to the outright bugs the other issues cause.

[-] o11c@programming.dev 2 points 1 year ago

What you are missing, of course, is the Rc<Refcell<T>> that you have to stick everywhere to make a nontrivial Rust program. It's like monads in Haskell, parentheses in lisp, verbosity in Java, or warnings in C - they're the magic words you have to incant correctly to make things work in their weird paradigms.

view more: ‹ prev next ›

o11c

joined 1 year ago