Exercise 3: An Empty Message Is a Real, Distinct Message — Possible Solution ==================================================================== THE TEST ------------------------------ programs[sender.pid] = [('send', b''), ('send', b'REAL')] programs[receiver.pid] = [('receive',), ('receive',)] RESULT ------------------------------ sent: b'' (an empty 'ping') then b'REAL' received, in order: [b'', b'REAL'] The received_log has exactly 2 entries. The first is genuinely b'' -- not skipped, not merged into the second message, not silently dropped. WHY THIS WORKS CORRECTLY IN A MESSAGE QUEUE ------------------------------ try_send(b'') still goes through the exact same real sequence as sending any other message: acquire an empty permit, acquire the queue mutex, self.messages.append(b'') (appending the empty bytes object itself, a real, distinct Python value), release the mutex, release a full permit. The queue's own bookkeeping (the semaphore counts, the deque's own length) treats an empty message exactly the same as any other message -- it's one more real entry in the queue, full stop. try_receive() later pops it off and returns it, completely unaware (and not needing to be aware) that its own content happens to be zero bytes long. WHY A RAW PIPE CANNOT EXPRESS THIS SAME SCENARIO ------------------------------ A pipe has no concept of "message" at all -- it's purely a stream of individual bytes. Writing an empty message via a pipe means writing zero bytes, which is indistinguishable from not writing anything. There's no signal, no marker, no side effect whatsoever that a "send" of an empty message ever happened -- a reader watching the pipe's own byte stream has no way to detect that an empty message was sent versus that nothing was ever sent at all, since both produce the exact same observable outcome: zero new bytes appearing on the pipe. The very thing a message queue can represent directly (a real, present-but-empty message) simply has no encoding at all in a plain byte stream. WHY THIS MATTERS ------------------------------ This is a genuinely practical distinction in real IPC design -- an empty message is often used deliberately as a "ping," a heartbeat, or a signal meaning "something happened, no additional data needed." Being unable to represent that cleanly on a pipe is exactly why real systems that need this kind of signal either use a message-queue-like primitive, or invent an out-of-band convention on top of a pipe (e.g. writing a single sentinel byte to MEAN "empty message," which is really just length-prefixing again, and inherits Exercise 1's own multi-writer fragility). WHY THIS WORKS AS AN ANSWER ------------------------------ Explicitly counting the received_log's own length (2, not 1) rather than just checking its contents confirms the empty message was genuinely RECEIVED as its own event, not merely that b'' happens to be present somewhere in the result -- which is the precise claim this exercise is testing.