2022-07-30

Why didn't I think of that description?

For the last couple of weeks I've been making my way through A Brief History of the Earth (subtitle "Four Billion Years in Eight Chapters") by Andrew H. Knoll. Brief shout-out to the author for including the (anti-)neutrino among the products associated with beta decay in his discussion of radiometric dating.

Nice book so far (I've reached the last chapter). I had a rough appreciation for much of the subject matter coming in, but it is clear that there has been much progress since the last time I read up on the discipline. Some open questions have been answered outright, and many details have come into focus where rough outlines existed before. All very cool.

One detail of the writing, however, is worthy of special mention. The bibliography for each chapter is divided into two sections: "Approachable Readings" and "More Technical References". I sorely wish I'd thought to use "approachable" as a description of pop-sci material more often in the past.

2022-07-25

2022-07-11

Little surprises #8: using the preprocessor to create latent bugs

Aside: As opposed to using the build system or the template processor which are totaly different except in the ways they are completely the same.


Languages with C-derived syntax and exceptions generally have a try-catch construct and the ones I'm familiar with have a little trap for the inattentive programmer: the catch block is a different scope from the try blocks. Which means when you merrily write try { ErrorInfo e; someRiskyOperation(e) } catch (...) { print("Risky operation failed with error %s\n",e.explanation()); } because the argument to someRiskyOperation is an out-param1 and you hope to capture the error data that was generated before the exception was thrown, you actually get a compilation error because e isn't in scope when you try to issue the message.

Not a big problem, of course, at least two work-around are obvious.

Except that I tried to send a message to our logger, so the code looked like try { ErrorInfo e; someRiskyOperation(e) } catch (...) { LOG_WARN("Risky operation failed with error " + e.explanation()); } where LOG_WARN is a macro whose purpose is to capture the file and line where the error occured.2 And that's a problem if this code occurs in a library that can be compiled with logging support turned off by simply defining the logging macros as nulls: #define LOG_WARN(explanation) , because in that case the compiler never sees the offending e.explanation. It was rewritten as nothing even before lexing. So you can test the code with logging turned off to your hearts content and never find the bug. Sigh.


1 Yes, I agree: out-params are generally evil. It's a legacy API. Perhaps we'll get around to replacing it eventually.

2 When it actually does something it looks something like #define LOG_WARN(explanation) do { \ logger:Message logmsg(__FILE__, __LINE__, explanation, logger::Warning); \ logger::getLogHandler().post(logmsg); \ while(false) and it can't be a function because __FILE__ and __LINE__ are macros and have to be evaluated in place. Unless and until the language provides operators for capturing source position data like that this is the best we can do.

2022-07-10

The Rip-off from Cleveland Depths.

Title in reference to Fritz Leiber's 1962 novella "The Creature from Cleveland Depths".1

The complex of product options that go by "activity tracker", "health monitor", or "wellness monitor" (and smart watches that include that suite of functionality) aren't exactly the "tickler"s in the story, but they share a lot of DNA with them. They are, after all, automated systems we wear explicitly so they can nudge us toward better versions of ourselves. You can get other parts of the tickler package as apps. Either for your phone or, if you choose the right smart watch for the wrist mounted device itself.2

One of the psychologically interesting things is that the prime statistics these things recorded when they first took off was ... steps. They were glorified, electronic pedomenters.3 Pedometers have been around for ages and never made such a big splash before. I suppose gamification is the key to that. Anyway, today's rantlet is about the way a wrist mounted pedometer fails us: you don't get credit for pushing a shopping cart. I can trek up and down every aisle of the local, big-box, warehouse club and the fool machine registers a few hundred steps because pushing the fool cart more or less immobilizes my wrist. I only get credit for putting things in the cart. The old waist-mounted mechanical jobs managed that kind of use better.

Okay, so it's seriously a first-world problem. You're right. And it's of no actual consequence. You're right about that, too. It still annoys me.


1 Available from Project Gutenberg or in audio form from Librivox.

2 I wear a Withing ScanWatch so I can't get a bunch of apps on my wrist, but I do get reasonably comprehensive health tracking, weeks of battery life (I only every charge it while I shower), and the aesthetic appeals to me.

3 Indeed, the cheapest ones still are, but many do a lot more these days.

2022-07-03

Who shaves the barber?

Or how should a logging framework appraise the caller of unexpected situations caught and handled, anyway?

2022-07-02

The ABCs of aspect oriented C++ (part1)

OK, so the title is a little ambitious, but I am going to show you how to prove a limited level of aspect orientations for a few cases.

What the heck is "aspect oriented programming", anyway?

Honestly, I'm not strong on the subject never have worked in that format myself, but the short version is that it allows you to add behavior to program abstraction without editing the associated code. Common examples are attaching entry and exit loggers or call count tracker to functions without editing the function. C++ has no built in support for it.

Anyway, I'm going to start by showing you a very limited and specific trick that has the same flavor, then generalize it.

Example: interface with non-trivial behavior

We have a hand-rolled serialization mechanism we use on a work project. It supports selected fundamental and standard-library type and provides an interface (AKA Abstract Base Class) for building support into classes we write for ourselves1

class SerialInterface { public: SerialInterface1() = default; ~SerialInterface1() = default; virtual bool serialize(std::ostream & out) const = 0; virtual bool deserialize(std::istream & in) = 0; };

Class we want to (de)serialize derive from SerialInterface and implement the virtual methods using some utility code to maintain uniform behavior.2 The return values tell you if the process was successful or not.

We have classes whose sole purposes is to be serialized and deserialized to support interprocess data transfer, which makes it very convenient to accept the input stream in a constructor

class Client: public SerialInterface1 { public: Client(std::istream & serialData) : Client() { deserialize(serialData); } };

But what happened to the status? It's lost, which is a problem.

Now, we could throw in the the event deserialize returns failure, but who like exceptions? An alternative would be to cache the success value and offer an interface to query the value. But then you have to duplicate the code in every client class. What we would like is to give the base class the status caching behavior without needing any duplicated code in the client classes. We achieve this by splitting the implementation of serialize and deserialize into a wrapper defined in the base class and a code implementation defined by the clients.

class SerialInterface2 { public: SerialInterface2() = default; ~SerialInterface2() = default; bool status() const { return _serializeImpl; } bool serialize(std::ostream & out) const { _serializationStatus = serializeImpl(out); return status(); } bool deserialize(std::istream & in) { _serializationStatus = deserializeImpl(out); return status(); } private: virtual bool serializeImpl(std::ostream & out) const = 0; virtual bool deserializeImpl(std::istream & in) = 0; bool _serializationStatus = true; };

Now all client class support status inquires without needing any code to support it. We've provided a status aspect to all the clients.

More general aspects for callables

It is very common for the examples I see in explanations of AOP to focus on providing aspects to callable subprograms (functions, procedures, whatever you want to call them). And that is interesting because modern C++ already has a highly general idea of "a thing you can call like a function", which means that we can try to use the approach from SerialInterface2 to provide aspects to callables.

To generalize the behavior we provide virtual implementations for code to be run both before and after the the callable.

class FunctionAspect { public: using function_t = bool(int, double&, const std::string &); FunctionAspect() = delete; FunctionAspect(std::function & func): _callable(func) {} bool operator()(int i, double & d, const std::string & s); private: virtual void prologue() = 0; virtual void epilogue() = 0; std::function _callable; }; bool FunctionAspect::operator()(int i, double & d, const std::string & s) { prologue(); bool result = _callable.operator()(i,d,s); epilogue(); return result; }

Concrete derivative classes can then provide arbitrary code wrappers around any std::function with the appropriate signature. That restriction is, of course, a major drawback, but we're on the road to general purpose aspects.


1 Come to think of it, we could have avoided exactly this complexity if we had access to a general support for AOP in C++ in the first place.

2 Yeah, we should probably have used JSON, but it works.

2022-03-13

Recycling categories

My wife and I try to take advantage of whatever recycling options are available to us (and we compost, too), and because I've dragged her around the country following my jobs for the past couple of decade we've lived in places with varied levels of availability. Travel has brought us in to contact with still more way to organize the process.1

Now, I'm far from an expert on this industry, but I know it can be a challenging domain to work in. The work of sorting mixed waste into coherent categories is non-trivial and costs real money if done in bulk after the material is turned in or depends on ordinary people's willingness and ability to get the sorting right. And sorting errors are significant:2 batches of material are often diverted to landfill due to "contamination"; a word which apparently covers a lot of sins from including food-waste (pizza boxes in your cardboard recycling, anyone), to mixing different categories of material together, or carelessly tossing plain garbage in a recycling bin.

Our local arrangements require individuals wishing to recycle to bring recyclables to a central facility3 and load them into dumpsters and big bins in six different categories (paper, cardboard, glass, plastic, aluminum, and ferrous metals4). Which leads us to some questions:

  • Just what plastics are allowed?

    At least these are generally marked with the numbered recycling trefoil, but we're encountered places with an added requirement specifying only bottles with necks. Huh? And in most places I've lived plastic bags can't be recycled in the municipal system. You have to take those to the various stores that accept them.

  • What is the difference between paper and cardboard?

    How do I decide? Does it matter if the paper is glossy or not?

  • What aluminum items are accepted?

    In some places it's just cans; in others you can bring foil and disposable cookware (if clean). What about substantial pieces of structural meta?

  • Glass?

    Does is need to be sorted by color? What if it's broken?

  • About that food waste thing...

    Does it rule out greasy paper? What about bottles and cans with beer or soda remnants?5

  • Batteries?

    These are a significant source of hazardous waste in landfill streams, but in most places they are hard to recycle. It's generally the case that you have to sort by chemistry and that cracked and leaking batteries are an extra pain.6

And so on and so forth. It's not trivial to know what is expected. You have to find, read, and indeed pay attention to the documentation supplied by your locality. Uhg.

Then there is the matter of what to do if you're not sure (or if, say, you and your spouse disagree about what the rules are). Should you submit things which you are unsure of at the possible cost of "contaminating" a load or contributing to a contractor terminating a contract? Or should you knowingly send things to landfill to insure that other stuff gets recycled?

I haven't traveled widely enough recently to have a good notion of how they do these things outside of the USA, but when I was going to Japan regularly in the noughties they seem to have a much more unified system (same bins and iconography in Tokyo and Osaka airports, JR station in several places, and in the small villages in Toyama prefecture. Europe was more varied than Japan but more consistent than the US.


1 When we attended a wedding on the big island of Hawaii just after the turn of the millennium the resort provided us with a laminated copy of the island's waste disposal guidelines card, listing approximately thirty different categories of trash, recyclables, and hazardous waste and detailing how/where each was to be disposed of (there were three categories of used batteries).

2 In one place we lived the city recycling unit made yearly reports on actual the levels of waste in various categories and the target's their upstream contractors would accept. And you can learn something about the process just be examining those targets: they would accept a much higher rate of ferrous metals in the aluminum then other types of contamination, so you have to figure that magnets were employed to divert the unwanted metals to the correct processing chain.

3 At least the lot in question is open 24/7. In one place the lot was open about seven hours a days (except on Sunday) with some days of the week including morning hours and others evening hours.

4 They mean iron and steel. I've checked because, the bin is labeled "tin cans" even though no one has used tin for cans in many decades. Linguistic habits can linger long after they are no longer strictly applicaable.

5 Not rinsing is a pet-peeve of mine. Not so much because of the smell, but because the aluminum bins at our local places are often swarming with bees. But I've met people who argue (not without a point) that we live in a desert currently experiencing a drought and they don't want to waste water on the effort.

6 I've had at-work arrangements for batteries when I worked on-site at national labs, and in my last job where we had an environmental health professor who knew all the right people and maintained a drop-off site in has departmental office. Which gives you some idea of how arcane that process can be.