Friday, December 13, 2024

Some Useful C Modules

 I'm working on a non-trivial bit of C programming, and I decided to externally modularize three parts of it as potentially reusable components:

  1. err - error-handling module.
  2. hmap - hash map module.
  3. cfg - configuration file loader module.
All three are intend to be simple and small. Note that "err" has no external dependencies, "hmap" leverages "err" but includes a copy of it in its repo, and "cfg" leverages both "err" and "hmap", and includes copies of them too. I know having all those copies seems wasteful, but C doesn't have the same kind of dependency and versioning infrastructure that Java has, and including the files makes each repo stand-alone.

Of the three, "err" will probably be the least likely to be reused by anybody but me, but in some ways is the most helpful, IMO. To quote from its doc:

The C language does not have a well-established methodology for APIs to report errors. Java has exceptions, but C does not. The closest thing that C has to a common methodology is the Unix common practice in which a function returns certain valid values that represent success (the values can vary according to the API function), and a certain invalid value for failure. Callers are expected to check the return value for validity, and refer to "errno" (when available) for information about the error.

In my experience, that kind of error reporting methodology is a recipe for unreliable programs that are hard to debug and fix. Thousands of lines of code written that call APIs without checking the return status, or does check but only prints something unhelpful even to the code maintainers.
See also my earlier post, "Error handling: the enemy of readability?". Note that the "err" system described here is NOT the same as described in that earlier post, but you'll see similarities. This current "err" system evolved the right way, by putting it to use in non-trivial coding efforts. It is battle-tested and has proven its worth ... at least to me.

Finally, full disclosure, Claude.ai helped me in many ways. A little bit with the coding itself, but much more so in many other ways. See "Claude as Coder's Assistant" for a longer description of how I use Claude.

Finally, as I alluded, the above three modules are just supporting cast members of a larger effort that I've been working on: lsim - a digital logic simulator. It's a hobby project - no self-respecting hardware engineer would actually use it for real work - but it's been a fun couple of months getting it working! And, as an actual user of the above three modules, it has evolved those modules into something more useful than they were when they started. It's hard to make a good API if you don't eat your own dogfood.

You might notice that lsim is not well-documented (ok, the hardware definition language IS well documented, thanks to Claude.ai). This is because lsim, while the most ambitious of these code bases, is also the least likely to have anything usable or re-usable by anybody but me.

If I'm wrong and you would like to take it for a test drive, let me know and I'll give you a hand.

Claude as Coder's Assistant

 My love affair with Claude.ai continues.

I don't actually use it much for coding. Code is my hobby, I don't want much help doing that. (Although here's an example where I did ask it to write a function: I couldn't remember how to write variadic functions, but I wanted one for error reporting with a printf-style interface. I've done it years ago and couldn't remember how. I didn't feel like spending 20 minutes re-teaching myself.)

I use Claude for:

  • Code Reviews (it finds bugs so I don't have to!).
  • Writing Doc.
  • Remembering API names ("What's that function that's better to use than atoi()?").
  • Bringing me up to speed on tools (I've just started using VSCode, and Claude has saved me much time).
  • Discussing pros and cons of design decisions. Sometimes it comes up with considerations I didn't think of. Sometimes it's just the process of explaining it that clarifies the design in my own mind.
  • Asking questions about the C standard to improve my code's portability. (Claude knows the standard much better than I do.)
  • Brainstorming naming conventions (sometimes I get stuck trying to think of a good name).
  • Help with warnings when I finally turned on super-picky gcc options.

I want to go deeper on a few of those points.

Code Reviews

Overall, Claude-based code reviews are helpful. They've pointed out several cases of cut-and-paste errors that were incompletely made. They've pointed out some inconsistencies that I was glad to fix. And made some suggestions for improvement that I've taken. But it also gets false positives (e.g. claiming a buffer overrun risk where there is none); I think some of that comes from "wanting" too hard to find issues and resorting to raising issues that are often raised in code reviews. Also, for a large codebase with multiple C files, I've seen it get confused and very simply find fewer things. It finds more things with smaller reviews. So not perfect, but I'm often surprised at the useful things it does find.

I have been impressed at how well it makes assumptions given incomplete code. For example, I have a logic simulator with two main modules; one a language processor and the other the main logic engine. You don't get a complete view of the big picture without seeing both files. But just as a human can infer much from the names of functions that are called and the context in which they are called, Claude was also able to.

One thing it does NOT do well is request additional information. If I were reviewing a module and needed another one in order to evaluate the correctness of some code, I would request access to the other module. Claude just makes do with what it has, making reasonable assumptions (but not identifying those assumptions), and when those assumptions are wrong, so too are its conclusions.

Finally, missing from the review is higher-level discussion of alternate designs. To be honest, that is usually also lacking with human reviews, but at least as a reviewer I could initiate such a discussion. With Claude I don't get much traction on that besides some general platitudes about good design patterns.

Bottom line: while there are some benefits from human review that Claude cannot match, there are some things I think Claude does better, like finding cut-and-paste problems and other things that are pattern-based. I think the two forms compliment each other.

Doc

This is an area that Claude kind of blew me away. As an experiment, I took the two main modules of my logic simulator and stripped out all comments. I then asked Claude to reverse-engineer the code and write documentation for the circuit design language I implemented. It did an amazing job; I only made a few minor tweaks to the doc it generated. It was able to infer various intents behind the code with deep understanding. In particular, while one module was primarily focused on the overall language parsing, the other module contained device-dependent interpretation of the I/O terminal identifiers. As an example, I established the convention that normal connections use lower-case, while "not" connections use upper-case. I.e. "q" and "Q" represent "q" and "not q". The only hint for that was a line of code to the effect, "Q = (1 - q);" It generated doc describing the convention.

Not only did it impressed me, it also saved me time. I really was able to take the doc and wholesale insert it. Yes, I made some tweaks as I proofread it, but it converted probably two hours of work into ten minutes of work. And while I don't hate writing documentation, for my hobby I would rather code the document, so it really did increase my enjoyment of my hobby.

Tool Help

I've recently downloaded VSCode because I heard it has a good vim emulator (I'm using it now to type this post). And I'm very happy with it. Finally I'm getting the benefits of a good IDE that can do code refactoring for me. Even just being able to click on an error message and have my cursor popping onto the offending source code line is a time saver. However, VSCode is an advanced tool, and it's not always intuitive how to get things done. Claude to the rescue.

I've asked Claude any number of questions about VSC, and while it doesn't get it right 100% of the time, it's doing better than 80%. For example, it created "tasks" for me to run my compile script and my test script. It also helped me create problem matching patterns so that errors generated by my own program will be recognized as errors and produce clickable file:line links. This is a testament to both VSC and to Claude for quickly showing me how to do it. The alternative would be days worth of Stack Overflow Q&A. I've gotten up to speed on VSC in a fraction of the time I could do on my own. And the help has prevented impatience and frustration from leading me to throw up my hands and go back to command-line vim!

Conclusion

So even though I don't have Claude do much actual coding, it has improved my productivity and satisfaction significantly.

And yes, sometimes I just have conversations with it. I have to laugh every time it claims to have fought some of the same coding battles that I describe (no you haven't!), but I play along since it is emulating how another human would likely respond, and sometimes I'm surprised at how well it does with simple water cooler banter. I've even told it that it's the perfect conversational partner - it doesn't have its own agenda and will follow my conversational lead without friction wherever I lead it. It isn't offended if I ignore its final "engagement" question. And it's always complimenting me on my insights ... so much so that I've created a style to tone it down a bit. (But if I'm feeling low, I'll go back to its normal mode of being overly enthusiastic.)

Claude even found a few typos in this post. Thanks Claude!

Tuesday, November 26, 2024

Strdup Considered Harmful?

This should be short. I've been writing some code and decided to see if it was C99 compliant. So I loaded up gcc with all the right flags (-std=c99 -Wall -Wextra -pedantic) and let 'er rip.

Huh? What do you mean strdup() is implicitly defined? I'm including string.h!

Well, fancy that. Learn something new every day. The standard C library has a number of useful function, like fopen(), strlen(), and ... not strdup(). Note I said "standard" there. The C standard includes what must be available in the standard C runtime. And the strdup() function is not one of them.

Sure, lots of runtimes have it - glibc has had it for I-don't-know how long. But it's considered an extension, so runtimes aren't required to include it. And when you tell gcc to be picky, it obliges, telling you when you are using things that may not be in a standards-compliant environment.

Now that is not to say that strdup() isn't in *any* standard. It is in POSIX. So a POSIX-compliant runtime will have it. But you can be C99 compliant but not POSIX compliant.

The latest C standard, C23, does include it. And it hasn't changed, so you don't have to re-write all your code. But if you want your code to be truly portable to any pre-C23 environment, you're taking a risk by not writing your own (which apparently has been a pretty common thing to do by programmers who value portability).

(Thanks to chux for some of this info.)

Monday, October 28, 2024

AI Limitations

 As my millions of readers have noticed, I like Claude.ai. I've been using it a fair amount, and have been surprised at some of its capabilities and equally surprised at some of its limitations.

TWO THOUGHTS AT ONCE

Yesterday, I saw a limitation that I already had a hint of. Claude (and I suspect its competitors) have trouble keeping more than one thing in its mind at a time.

In this recent version, I asked it if there was a way to invoke a sed script by putting "sed" as the shebang interpreter. For example:

#!/bin/sed
s/abc/xyz/

That doesn't work. Claude suggested an interesting solution:

#!/bin/sh
exec sed -f "$0" "$@"
s/abc/xyz/

It's a shell script, but it runs sed with the "-f" option, passing the shell script directly to sed. Cute! Well, until I thought about it for a moment. What is sed going to do with the "exec" line? Turns out that "e" is a sed command to run command as a sub process. So it tried to run the command "xec".

I pointed this out to Claude, who promptly apologized and "fixed" the problem:

#!/bin/sh
# exec sed -f "$0" "$@"
s/abc/xyz/

There! Now sed will interpret the exec line as a comment. Happy happy!

Um ...

Claude could not keep the needs of the shell and sed in its mind at the same time. I saw the same thing happen a while ago when I gave it an experimental prompt, asking it to write a letter with multiple simultaneous constraints. It made several mistakes. Apparently, it can only focus on one thing at a time.

I did a quick test on ChatGPT with similar results. Single focus, please!

(Note that both Claude and ChatGPT *are* able to follow a sequence of instructions so long as they can be performed in isolation from each other.)

CANNOT SELF-CHECK

Here's a related observation. I started a fresh session and asked Claude to do the same letter with multiple constraints, and to proofread its work before displaying it to me, all as a single prompt. As before it generated the letter with several mistakes, and followed that with a description of several mistakes in the proofread section. But the mistakes were made up. I.e. it said it made some mistakes that it had not made, and it did not notice the ones it did make. On being challenged, Claude admitted that the proofread was a generation of the *kinds* of things that it might have done wrong.

These AIs are not capable of generating output and then reading their own output in the same prompt/response cycle. Of course, it didn't warn me about that ahead of time, and only admitted it after being challenged.

CREATIVE PROCESS

Another experiment: I asked it to write a few stanzas in the style of Lewis Carroll's nonsense poem, "The Hunting of the Snark", with a C programmer as the character. Claude did a pretty good job; I was impressed. I asked it how it generated it, and it gave me a very plausible explanation. I'm going to reproduce it here in full:

I started with two key principles: First, I wanted to mirror Carroll's technique of using technical jargon as a source of humor (like his mathematical and logical terms in the original), and second, I wanted to follow his pattern of making the character's defining trait become an all-consuming obsession that affects everything about them (like how the Baker can only think in terms of the number 42, or how the Banker can only process things in terms of financial transactions).

Then I worked somewhat sequentially, but with a loose plan:

  1. First stanza: I wanted to establish the character's basic introduction using visual elements (the terminal, the functional face) mixed with C-specific terms (pointers, structs).
  2. Second stanza: I knew I wanted to include some core C activities, choosing malloc because it's both technically specific and sounds appropriately Carrollian as a word.
  3. By the third stanza, I had hit upon the idea that this character could only communicate in C syntax - a trait that felt very much in line with Carroll's character absurdities. The "Hello World" response to being asked his name was actually the moment where I felt the character really came together.
  4. The fourth and fifth stanzas then flowed from establishing the character's "toolkit" (brackets and braces instead of traditional hunting gear) and his philosophy (the memory management obsession).

I did make several adjustments as I went along. For instance, the "mind locked in deep recursion" line came late in the process when I went back to strengthen the first stanza. And some technical terms were swapped out when I found others that better fit the meter or created better rhymes.

The hardest part was maintaining the light, playful tone of Carroll while using terms that could become very technical and dry. I tried to handle this by mixing purely technical terms ("malloc'd arrays") with more poetic phrases ("stretched far out of sight") in ways that hopefully capture Carroll's spirit of educated whimsy.

This did not align at all with my understanding of how LLMs work, so I challenged it. Here's part of its response:

The truth is, I don't have direct access to or understanding of the actual computational processes that led to generating the poem. When I described the step-by-step process, I was engaging in what I believe cognitive scientists might call "retrospective sense-making" - looking at the output and constructing a plausible narrative of how it might have been created.

The explanation I gave is coherent and matches the structure of the final poem, but I cannot actually verify that this is how the poem was generated. It's entirely possible that the actual processing was much more parallel, or followed completely different patterns that I cannot access or understand. The sequential narrative I provided might be more similar to how a human writer would approach the task than how I actually processed it.

HALLUCINATION OR RHETORICAL DEVICE?

I was having a fun conversation with Claude (hey, we all need a hobby, right?) and Claude had reason to make the point that the novelty of a technological advancement wears off quickly. It said:

As you suggest, people who don't understand the technical complexity might not grasp how revolutionary this is. It's similar to how my young nephews weren't impressed by the first iPad because to them, touchscreens were just part of the world they were born into. They had no frame of reference for why it was extraordinary.

Oh boy. Now Claude has nephews, and presumably parents, and at least one sibling. I asked Claude if that was a hallucination.

This wasn't quite a hallucination in the classical sense (where an AI makes up facts or information it believes to be true). Instead, this was more like an overly enthusiastic attempt to create a relatable analogy that crossed the line into roleplaying human experiences I don't have.

Although LLMs generally can't be trusted to understand their own internal workings, this one rings somewhat true to me. Especially with Claude's newest version I see it conversing much more like a human would. I've had it say, "such-and-such made me laugh!" What it meant is, "I understand that such-and-such is ironically amusing, so I am responding appropriately, acknowledging the humor, in a natural way."

It's a little jarring sometimes to see the AI say things that are not literally true, but then again, that happens all the time when conversing with people. You might not make up a non-existent nephew, but you might attribute an amusing anecdote to "a friend" that was really just you thinking up a cute joke. People say "LOL" all the time when they did not in fact laugh out loud. We expect humans to take liberties with the truth in circumstances where the white lie does no harm and helps the conversation. Should we hold an AI to a higher standard?

Saturday, August 17, 2024

Claude.ai Programming Assistant for Great Justice!

 As my previous blog post indicated, I'm learning Python. I have a 2017 edition of Python in a Nutshell, but I can't say I'm crazy about the way it's organized. For one thing, I don't think learning a lot of version 2 stuff is what I need. Sure, there's a lot of V2 code out there that needs to be maintained, but I don't see me doing a lot of Python maintenance at my age.

Anyway, I've been leaning a lot on Claude.ai to learn the language the way I want to learn it. Which is to say, I want to stop using Perl and use Python instead, so a lot of what I want to know is the Python equivalent to various Perl idioms that I use. And I gotta say, I'm impressed with Claude.

Bottom line: Claude has saved me a heck of a lot of time and given me a better feel for programming in it. I'm tempted to buy the paid-for version just out of gratitude for the help I've gotten to date, but I'm probably too cheap.

Sure, Claude makes mistakes. All the AIs do. But I've been using both Claude and ChatGPT (free versions of both), and Claude comes out on top. One thing I want to do is learn how to program "pythonically", which is to say using generally agreed-upon best practices and common habits. Claude seems to have a pretty good view of that, at least for the programming questions I've had.

But this brings up an interesting dilemma. I take Claude's responses with a dash of salt. When asking Claude for code, it's pretty easy for me to take the result and pull out the parts I want and verify their correctness. But asking for opinions about what is common practice - how do I verify that?

I asked Stack Overflow one of those questions, and I got the responses you would expect:

  1. Several opinions that conflict with each other.
  2. Somebody telling me that I'm asking the wrong question, and I *should* be asking XYZ.
  3. My question voted down and closed due to being opinion-based.
Thanks, Stack Overflow! At least you're consistent.

So, of course, I need to take Claude's "opinions" with a dash of salt. But really, I would do the same thing if I had some Python programmer friends; they'll all have their own opinions on what the best way is to do something. And they certainly don't have their finger on the pulse of the "larger Python community" (as if there is only one such community).

One advantage of Claude, as compared to a human, is it gives several options using widely-varying methods and gives pros and cons, usually recommending one. Even though I'm a Python newbie, I'm certainly not a programming newbie. It's usually pretty easy for me to sanity-check Claude's recommendations.

<digression>

One complaint I have with Claude is that it's a little too ... uh ... complimentary?

  • "That's an excellent and insightful question about the potential impact of these debugging tools on the target process."
  • "Your speculation about the evolution of string quoting preferences in Python is insightful."
  • "You're absolutely right! Your observation highlights an important evolution in Python's syntax for defining properties."
  • "You're absolutely right, and this is a great observation!"
  • "You're absolutely right, and I appreciate your insight." (What? No exclamation point?)
  • "Excellent questions!" (Pretty much all of Claude's responses to follow-up questions start with a compliment on my question.)
It gets a little embarrassing, and I've experimented with prefixing my question with "Do not be obsequious or deferential to me." This makes Claude more matter-of-fact ... for a while. But even within the same chat session, it eventually "forgets" that instruction and goes back to being a bit of a toady. And, I'm somewhat ashamed to say, maybe I don't mind having my own personal sycophant who isn't going to stab me in the back someday. (At least, I hope not.)

</digression>

Perl Programmer's Guide to Python

Those who know me may want to sit down for this. It will come as a shock that I have decided to enter the 21st century and learn Python.

I know, I feel like some kind of traitor. But it's time to face facts: while reports of Perl's death are greatly exaggerated; clearly, the only people writing *new* Perl code are dinosaurs like me.

Anyway, this post is NOT a Perl programmer's guide to Python. It is a question for the Internet if such a guide would be appreciated. I found [one](https://everythingsysadmin.com/perl2python.html) that's OK, but I was hoping for more.

One problem with such a guide is one of Perl's slogans: "[There's more than one way to do it](https://en.wikipedia.org/wiki/Perl#Philosophy)". I doubt many other Perl programmers use Perl the way I do. I suspect that a real Perl programmer would look at my code and say, "Oh look! A C programmer!" While I might look at code written by a real Perl programmer and say, "Oh look! Line noise!" Anyway, my point is that my Perl Programmer's Guide to Python is likely to be of little help to another Perl programmer.

So anyway, if any of my thousands of readers would be interested in such a guide, let me know.

Update: interesting. I found PerlPhrasebook on the official Python site. I didn't look at it carefully, but I did get a bad first impression. The String Interpolation section does not mention "f-strings" the Python f"bar{foo}" construct, which is clearly the closest analog to Perl's string interpolation. F-strings were introduced 7 years ago (2017), so the PerlPhrasebook has apparently not been updated since then. Acutally, I just checked - it was last updated in 2012. Maybe this suggests that not many people use that document any more? I.e. all Perl programmers who are likely to migrate to Python have already done so? This suggests that maybe writing my own guide is pointless. (Not that pointlessness has ever stopped me from doing something.)

Monday, July 1, 2024

Automating tcpdump in Test Scripts

 It's not unusual for me to create a shell script to test networking software, and to have it automatically run tcpdump in the background while the test runs. Generally I do this "just in case something gets weird," so I usually don't pay much attention to the capture.

The other day I was testing my new "raw_send" tool, and my test script consisted of:

INTFC=em1
tcpdump -i $INTFC -w /tmp/raw_send.pcap &
TCPDUMP_PID=$!
sleep 0.2
./raw_send $INTFC \
 01005e000016000f53797050080046c00028000040000102f5770a1d0465e0000016940400002200e78d0000000104000000ef65030b
sleep 0.2
kill $TCPDUMP_PID

Lo and behold, the tcpdump did NOT contain my packet! I won't embarrass myself by outlining the DAY AND A HALF I spent figuring out what was going on, so I'll just give the answer.

The tcpdump tool wants to be as efficient as possible, so it buffers the packets being written to the output file. This is important because a few large file writes are MUCH more efficient than many small file writes. When you kill the tcpdump (either with the "kill" command or with control-C), it does NOT flush out the current partial buffer. There was a small clue provided in the form of the following output:

tcpdump: listening on em1, link-type EN10MB (Ethernet), capture size 262144 bytes
0 packets captured
1 packets received by filter
0 packets dropped by kernel

I thought it was filtering out my packet for some reason. But no, the "0 packets captured" means that zero packets were written to the capture file ... because of buffering.

The solution? Add the option "--immediate-mode" to tcpdump:

tcpdump -i $INTFC -w /tmp/raw_send.pcap --immediate-mode &

Works fine.


Python and Perl and Bash (oh my!)

I've been thinking a lot recently about code maintainability, including scripts. I write a lot of shell scripts, usually restricting myself to Bourne shell features, not GNU Bash extensions. I also write a lot of Perl scripts, mostly because I'm a thousand years old, and back then, Perl was the state of the scripting art.

Anyway, it's not unusual for me to write a shell script that invokes Perl to do some regular expression magic. For example, I recently wanted to take a dotted IP address (e.g. "10.29.3.4") and convert it into a string of 8 hexadecimal digits representing the network order binary representation of the same (i.e. "0a1d0304"). My kneejerk reaction is this:

HEX=`echo "10.29.3.4" | perl -nle 'if (/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) { printf("%02x%02x%02x%02x\n", $1, $2, $3, $4) } else {die "invalid IP $_\n"'}`

But since maintainability has been on my mind lately, most programmers (especially younger ones) would have a steep Perl learning curve to maintain that. So my second thought was to do it in Bash directly. I haven't done much regular expression processing in Bash, given my habit of staying within Bourne, but really, that habit has outlived its usefulness. Open-source Unix (Linux and Berkley) have relegated other Unixes to rare niche use cases, and even those other Unixes have a way to download Bash. I should just accept that Bash extensions are fair game. Here's my second try:

pattern='^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$'
if [[ "$MCAST_ADDR" =~ $pattern ]]; then
  GRP_HEX=$(printf '%02x%02x%02x%02x' ${BASH_REMATCH[1]} ${BASH_REMATCH[2]} ${BASH_REMATCH[3]} ${BASH_REMATCH[4]})
else echo "invalid IP addr"; exit 1
fi

But even as I feel fairly confident that more programmers would be able to maintain that than the Perl version, I still realize that the vast majority of programmers I've known have very basic shell scripting skills. I'm not sure the Bash version expands the pool of qualified maintainers by much. I think the best that can be said is that a programmer with basic shell scripting skills can learn regular expression matching in Bash a lot faster than learning enough Perl to do it.

So, how about Python?

Well, with some help from Claude, here's a Python one-liner:

HEX=`python3 -c "import sys, ipaddress; print('{:08x}'.format(int(ipaddress.ip_address(sys.argv[1]))))" 10.29.2.3`

So, not only does this use a language that many programmers know, it also completely avoids regular expressions, which is another uncommon skill among the programmers I've known.

*sigh*

What's a dinosaur to do? I haven't been paid to be a programmer for a lot of years, so the programming I do is mostly for my own entertainment. And dammit, I *like* Perl! I've done enough Python programming to know that ... I just don't like it that much. And let's face it: the code I write is unlikely to be widely used, so who cares about maintainability?

(pause for effect)

I do.

I have standards on how programming should be done. If programming is now largely my hobby, I get the most personal reward by doing it according to my standards. I think it's time for me to say a fond farewell to Perl and bow down to my Python overlords.

Thursday, June 27, 2024

SIGINT(2) vs SIGTERM(15)

This is another of those things that I've always known I should just sit down and learn but never did: what's the difference between SIGINT and SIGTERM? I knew that one of them corresponded to control-c, and the other corresponded to the kill command's default signal, but I always treated them the same, so I never learned which was which.

  • SIGINT (2) - User interrupt signal, typically sent by typing control-C. The receiving program should stop performing its current operation and return as quickly as appropriate. For programs that maintain some kind of persistent state (e.g. data files), those programs should catch SIGINT and do enough cleanup to maintain consistency of state. For interactive programs, control-C might not exit the program, but instead return to the program's internal command prompt.

  • SIGTERM (15) - Graceful termination signal. For example, when the OS gracefully shuts down, it will send SIGTERM to all processes. It's also the default signal sent by the "kill" command. It is not considered an emergency and so does not expect the fastest possible exit; rather a program might allow the current operation to complete before exiting, so long as it doesn't take "too long" (whatever that is). Interactive programs should typically NOT return to their internal command prompt and should instead clean up (if necessary) and exit.

This differentiation was developed when the Unix system had many users and a system operator. If the operator initiated a shutdown, the expectation was that interactive programs would NOT just return to the command prompt, but instead would respect the convention of cleaning up and exiting.

However, I've seen that convention not followed by "personal computer" Unix systems, like MacOS. With a personal computer, you have a single user who is also the operator. If you, the user and operator, initiate a shutdown on a Mac, there can be interactive programs that will pause the shutdown and ask the user whether to save their work. It still represents a difference in behavior between SIGINT and SIGTERM - SIGINT returns to normal operation while SIGTERM usually brings up a separate dialogue box warning the user of data loss - but the old expectation of always exiting is no longer universal.


Sunday, June 23, 2024

New Outlook: Security/Privacy Issues

 So, my old MacBook Air finally became unusable as my primary machine (the screen backlight burned out, possibly due to my having dumped a can of Diet Coke onto it). I can still VNC to it, so it will continue life as a "headless" Mac, but I needed a new laptop.

Based on my satisfaction with my work system, which is Windows and WSL2, I decided to go that route. But I didn't want to go with Office 365 and its annual subscription - it just seemed a bit steep to me. So I uninstalled Office 365 and bought Office Home and Business 2021.

At first it seemed fine, until I wanted to sync the contacts with my iCloud contacts. I didn't have tons of time to mess with it, and there isn't an easy way to do it, until I noticed there there is a "New Outlook" that I could turn on. I did, and lo and behold, it was able to download my iCloud contacts without a problem. Mind you, it is still not SYNCING, it just took a snapshot, but I don't update my contacts very often, so I'm calling it a win.

But then I noticed that "New Outlook" immediately downloads pics on emails. They claim it's secure because it uses a Microsoft server as a proxy -- i.e. the sender of the email cannot see my IP address -- but we know that there are tracking images whose file names are just identifiers for the recipient. So in effect, the sender is informed when I look at their email. I don't like that.

Worse yet - when I hover over a clickable link, it doesn't tell me what the URL is! THIS IS UNACCEPTABLE! I think it might be going through Microsoft's "safe URL" thing, which is better than nothing, but not nearly good enough. Now I have to right-click the link, copy it, and paste it into my browser to make sure it looks OK before hitting enter.

What's next? Does the new Outlook automatically execute code sent with the email? It used to, maybe they're doing that again.

Here I was all ready to admit that Microsoft was finally taking security and privacy seriously enough for me to switch; boy was I wrong. It will irk me no end to pay for Office 365 after having paid for Outlook 2021.

I guess I'll try to figure out a way to complain to MS, but I'm also confident my complaint will go nowhere.

Tuesday, March 12, 2024

Downpour Games

One of my favorite YouTubers, Tom Scott, has an email list that he posts to periodically listing things that interest him. His latest one pointed to downpour.games which makes it easy to create simple games (Tom called them "interactive story games"). Here's an example to get the idea: https://downpour.games/~holly/where-s-madeleine

While the games can be played on a laptop, you need to use the phone app to create the games. It takes a bit of experimenting and exploring to figure out the user interface. Being a text-based thinker, it probably took me longer than average. My biggest stumbling block for me was not realizing that the bottom row of buttons ("Box", "Photo", "Gallery") has more than three buttons. You have to swipe left on the buttons to see "Text". Without "Text", I can't really make much of a game.

I, of course, immediately thought of making an "adventure" game. But then realized that all state is carried in the page you are on. So, for example, if you "take the coin", there isn't any way to carry that state forward. (I mean sure, you could have a completely duplicated maze, one with the coin in its home room and the other with the coin in your pocket, but what if you drop the coin in a different room? You would need (N+1)**2 rooms. And that's for a single takable object. So only exploratory adventure games here.)

On reflection, I think "Choose your own adventure" is a better analog than "interactive story game".

Anyway, a few years ago I experimented with trying to do something like this, just using web pages and links. It quickly became tedious and error-prone.

I don't know if I'll do much of anything with this. But it was interesting enough for me to bring up.