(FX: Flashback wibbly wobbly transition...)
So, as a teenager, I started working on ARGON, a distributed operating system. At the time, the CPU cost of encrypting traffic could be a significant matter when communicating over untrusted networks, so I'd worked out a protocol whereby network communications between clusters could negotiate to find the lowest-cost encryption scheme that both parties considered acceptable for the sensitivity of the data being transmitted: more sensitive data would require more secure protocols, which presumably excluded cheaper ones.
But I wanted to do something similar for communications within a cluster; I started with the same idea - finding the cheapest algorithm considered secure enough for the communication at hand. This could be simplified, as all nodes within a cluster share the same configuration, so both will agree on the same list of encryption systems, with the same security and costliness scores; so no negotiation is required - the sender can work out what algorithm to use, and be confident that the recipient will come to the same conclusion.
However, it pained me that highly sensitive data would be encrypted with expensive algorithms, even between machines connected by a trusted network - maybe even right next to each other, connected by a dedicated cable. I wanted a way to be able to, through configuration, tell the cluster that certain links between nodes in the cluster are trusted up to a certain level of sensitivity. Connections at that sensitivity level or below can use those links without needing encryption; anything above would use a suitably trusted algorithm.
Read more »
Ok, this is an interesting tale I've retold in person a few times. So I've decided to write it up for the world to see.
The scene: My student flat, 1998. Seven of us are living there, and we're all nerds so there's lots of computers. The world of networked multi-player games is exploding, and we want to play.
So, we buy some network cards, and go to Maplin for some coax cable, BNC connectors and terminators, and start to set up a
10BASE2 LAN.
But one of the computers can't talk to the others. What's going on?
Read more »
Continuing my previous series of blog posts about interesting things I've worked on in my career (an analytical database engine and a transactional database engine), I thought it'd be interesting to talk about something I worked on that's less groundbreaking technology, but interesting in other ways.
Read more »
So, if you look at a recent Scheme standard such as R7RS, you'll see that the body of a lambda
expression is defined as <definition>* <expression>* <tail expression>
; zero or more internal definitions, zero or more expressions evaluated purely for their side-effects and the results discarded, and a tail expression whose evaluation result is the "return value" of the resulting procedure.
I used to find myself using the internal definitions as a kind of let*
, writing procedures like so:
(lambda (foo)
(define a ...some expression involving foo...)
(define b ...some expression involving a and/or foo...)
...some final expression involving all three...)
But the nested defines looked wrong to me, and if I was to follow the specification exactly, I couldn't intersperse side-effecting expressions such as logging or assertions amongst them. And handling exceptional cases with if
involved having to create nested blocks with begin
.
For many cases, and-let*
was my salvation; it works like let*
, creating a series of definitions that are inside the lexical scope of all previous definitions, but also aborting the chain if any definition expression returns #f
. It also lets you have expressions in the chain that are just there as guard conditions; if they return #f
then the chain is aborted there and #f
returned, but otherwise the result isn't bound to anything. I would sometimes embed debug logging and asserts as side-effects within expressions that returned #t
to avoid aborting the chain, but that was ugly:
(and-let* ((a ...some expression...)
(_1 (begin (printf "DEBUG\n") #t))
(_2 (begin (assert (odd? a)) #t)))
...)
And sometimes #f
values are meaningful to me and shouldn't abort the whole thing. So I often end up writing code like this:
(let* ((a ...)
(b ...))
(printf "DEBUG\n")
(assert ...)
(if ...
(let* ((c ...)
(d ...))
...)
...))
And the indentation slowly creeps across the page...
However, I think I have a much neater solution!
Read more »
So, for Christmas, I got a receipt printer. It's a Jepod JP-5890K, the important specifications of which being:
- Mains powered
- USB connectivity (appears as a standard USB printer)
- 58mm wide thermal paper rolls (widely available, cheap)
- 384 dot horizontal resolution
- No automatic cutter, you need to tear the paper off yourself
- Costs less than £30
I asked for this thing because I noticed I was using a lot of Post-It notes to basically copy stuff down off the screen, and automating that seemed fun.
Read more »