<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0">
 <channel>
  <title>Fragments: Posts tagged 'computer'</title>
  <description>Fragments: Posts tagged 'computer'</description>
  <link>https://www.tfeb.org/fragments/tags/computer.html</link>
  <lastBuildDate>Thu, 19 Feb 2026 18:10:58 UT</lastBuildDate>
  <pubDate>Thu, 19 Feb 2026 18:10:58 UT</pubDate>
  <ttl>1800</ttl>
  <item>
   <title>Zeno's paradox</title>
   <link>https://www.tfeb.org/fragments/2026/02/19/zeno-s-paradox/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2026-02-19-zeno-s-paradox</guid>
   <pubDate>Thu, 19 Feb 2026 18:10:58 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Or, the bullshit singularity.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;For more than half a century, commercial nuclear fusion power has been thirty years away.&lt;/p&gt;

&lt;p&gt;Today there is a new prediction: artificial general intelligence is two years away. It was two years away last year, it&amp;rsquo;s two years away this year and it will be two years away next year.&lt;/p&gt;

&lt;p&gt;This is the bullshit singularity: hyperbolic predictions of an imagined future technological revolution have ever shorter timescales, asymptotically approaching but never quite reaching zero. The revolution refuses to arrive: all that changes is the speed at which the bullshitters whirl their arms and the pitch of their voices.&lt;/p&gt;</description></item>
  <item>
   <title>Practice</title>
   <link>https://www.tfeb.org/fragments/2026/01/29/practice/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2026-01-29-practice</guid>
   <pubDate>Thu, 29 Jan 2026 12:19:39 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Or: do not outsource your mind.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;So, let&amp;rsquo;s skip over the economic and social problems with LLMs. This is ignoring the blue whale in the room, but there&amp;rsquo;s no purpose in discussing them with someone who likely thinks the whale is their friend. Hint: it&amp;rsquo;s not your friend.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s just talk about how this plays out in practical terms.&lt;/p&gt;

&lt;p&gt;Here are two true stories.&lt;/p&gt;

&lt;p&gt;More than fifty years ago a teacher told me that I would be a mathematician. And it turns out they had a point: I was good at maths and good at physics. Really good. I make no claim to be a genius, but I was &lt;em&gt;definitely&lt;/em&gt; good enough to have had a career as an academic mathematical physicist.&lt;/p&gt;

&lt;p&gt;But I am also lazy as fuck. And because I was so good I found I could just not put in the hours of practice other people needed to do, and while away the hours listening to music and getting stoned and talking to girls.&lt;/p&gt;

&lt;p&gt;And I have not had a career as an academic mathematician or physicist, because it all came back to bite me when I was 23: practising is not optional, not for anyone. Not for a genius and certainly not for me. I got half way through a PhD but I just couldn&amp;rsquo;t cope, because GR turns out to be too hard unless you really know the ropes of the maths behind it, and you get to know those ropes only by spending thousands of hours on them: there is no shortcut, not for me, not for anyone.&lt;/p&gt;

&lt;p&gt;Twenty years ago, and again 15 years ago I wrote two large, complicated programs in Perl: one of them was still in use until very recently and may still be. I was really good at Perl. Today I barely understand it, and certainly could not understand the things I wrote two decades ago. I could get good at it again given a year and motivation, sure, but I&amp;rsquo;m not good now.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the thing: practice counts. There&amp;rsquo;s a really compelling argument that the difference between &amp;lsquo;a genius&amp;rsquo; and an ordinary person is that the genius has the ability to practise, really a lot. More than that: &lt;em&gt;recent&lt;/em&gt; practice counts: I practised writing Perl really a lot up until about 15 years ago. I could, if I wanted to, become good at it again, but I am not good at it now, because all that practice was too long ago.&lt;/p&gt;

&lt;p&gt;So how does the LLM thing pan out? It pans out with humans who are no longer practising programming and so &lt;em&gt;are no longer very good at programming&lt;/em&gt; checking code written by a machine which they should not trust, but which they do for the reasons I said I would not discuss above. In due course it is going to pan out with humans &lt;em&gt;who never got to be competent at all&lt;/em&gt; using code written by a machine that they no longer understand why they should not trust. Worse than that: the people who could have become good if they practised won&amp;rsquo;t even enter the field, because people like that don&amp;rsquo;t want to be drones, and don&amp;rsquo;t need to become one. It pans out with LLMs seeing more and more code written by LLMs, and less and less written by humans, with the resulting model collapse we&amp;rsquo;re already seeing.&lt;/p&gt;

&lt;p&gt;Welcome to the dystopia you are so eagerly building for us all. I hope you enjoy it.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;This originated as a reddit comment. And it&amp;rsquo;s OK: I had a relapse but I&amp;rsquo;m all better now. Reddit is still a stinking swamp inhabited mostly by fools and trolls. Nobody gains anything by writing comments there.&lt;/p&gt;</description></item>
  <item>
   <title>How to orphan an online account</title>
   <link>https://www.tfeb.org/fragments/2025/10/21/how-to-orphan-an-online-account/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2025-10-21-how-to-orphan-an-online-account</guid>
   <pubDate>Tue, 21 Oct 2025 08:35:28 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Here is a way of ensuring it is, at least, very hard to recover an account you&amp;rsquo;ve used on some social media platform where either you want the old content to remain publicly visible or the platform doesn&amp;rsquo;t let you delete accounts in any reasonable way.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;So, you want to walk away from whichever tentacle of the creeping undead horror that the internet has become in 2025 has engulfed you. But you either want to leave the things you said in place as some kind of terrible warning to those who might come after you, or for some entirely obvious reason the nazi plutocrats who now rule the world want to make it very hard to erase your account.&lt;/p&gt;

&lt;p&gt;Good. But you are scared that you might weaken: the addiction is never cured, only in remission. Here is what I do to make sure it is extremely hard to relapse&lt;sup&gt;&lt;a href="#2025-10-21-how-to-orphan-an-online-account-footnote-1-definition" name="2025-10-21-how-to-orphan-an-online-account-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;Make an ephemeral email address. There are lots of places which let you create such addresses which forward to your real address. It is critical that you can &lt;em&gt;delete&lt;/em&gt; such an address on demand, and that the addresses, once deleted, cannot ever be recreated. Depending on how things work it may also matter that you can send mail &lt;em&gt;from&lt;/em&gt; this address.&lt;/li&gt;
 &lt;li&gt;Change the email address associated with the account to this ephemeral address. Go through any round-trip requirements to verify that the address is yours.&lt;/li&gt;
 &lt;li&gt;Change or remove any other contact details. If the account requires you to round-trip these you&amp;rsquo;ll need, for instance, a burner SIM for a phone number. If you have to use other fake details don&amp;rsquo;t write them down.&lt;/li&gt;
 &lt;li&gt;Change the password on the account to a long, random string. You can use &lt;a href="https://tfeb.org/fragments/documentation/#xkcd-936-random-passphrases" title="xkcd 936"&gt;my tool&lt;/a&gt;, but there are many others available. &lt;em&gt;Do not use a passphrase&lt;/em&gt; as you might remember it, and &lt;em&gt;do not write the password down&lt;/em&gt;.&lt;/li&gt;
 &lt;li&gt;Delete the ephemeral address, and destroy the SIM card if you had to use one.&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;You are done.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2025-10-21-how-to-orphan-an-online-account-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;Note that this approach is meant to make it hard for &lt;em&gt;you&lt;/em&gt; to recover the account: it doesn&amp;rsquo;t do anything much to make it harder for the account to be traced back to you: this is about recovery from addiction, not privacy.&amp;nbsp;&lt;a href="#2025-10-21-how-to-orphan-an-online-account-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>The glorious AI future</title>
   <link>https://www.tfeb.org/fragments/2025/08/22/the-glorious-ai-future/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2025-08-22-the-glorious-ai-future</guid>
   <pubDate>Fri, 22 Aug 2025 14:47:11 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;is not as glorious as you probably think.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;Let&amp;rsquo;s outline the glorious AI future that our politicians are so enthusiastic about.&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;In the near (how near?) future AI systems will really be intelligent.&lt;/li&gt;
 &lt;li&gt;They will also be cheap and so become pervasive: everybody will have an AI assistant, or perhaps large numbers of them.&lt;/li&gt;
 &lt;li&gt;This glorious future is worth almost any sacrifice: the carbon emissions from the vast machines we need to create it will somehow be solved by 
  &lt;s&gt;magic&lt;/s&gt; unspecified technology developed by the AIs of the future, and the sacrifice of all our intellectual property to the 
  &lt;s&gt;soul-harvesting parasites&lt;/s&gt; splendid AI will enrich us all.&lt;/li&gt;
 &lt;li&gt;Outsourcing our thinking to AI 
  &lt;s&gt;will turn us into the Eloi&lt;/s&gt; free us to live fulfilling lives of some unspecified kind.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;This, of course, is all hype and lies. The &amp;lsquo;AI&amp;rsquo; systems we have almost certainly aren&amp;rsquo;t a path to intelligence of any kind. The most likely use they have is the use they&amp;rsquo;re being put to now: weaponized disinformation machines. Even without intelligence or any real possibility of reaching it they are busily destroying our ability to think.&lt;/p&gt;

&lt;p&gt;But let&amp;rsquo;s assume the glorious AI future happens. Let&amp;rsquo;s assume that it&amp;rsquo;s not just a vast speculative bubble to make some plutocrats even more pluto, and that we will have access to real, cheap, machine intelligence in a few years. Let&amp;rsquo;s ignore the possibility that these intelligent machines decide to eliminate or enslave us, which is inconvenient to the politicians.&lt;/p&gt;

&lt;p&gt;So: there are intelligent machines. The next question to ask is: are these machines &lt;em&gt;conscious&lt;/em&gt;? This is something philosophers like to bullshit about at great length. But I am not a philosopher, so I&amp;rsquo;ll ask a simpler question: can you propose a test which will empirically tell whether these machine intelligences are conscious&lt;sup&gt;&lt;a href="#2025-08-22-the-glorious-ai-future-footnote-1-definition" name="2025-08-22-the-glorious-ai-future-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;? If it helps, try to think of an empirical test which will tell you if &lt;em&gt;other humans&lt;/em&gt; are conscious. Go ahead, I&amp;rsquo;ll wait.&lt;/p&gt;

&lt;p&gt;You can&amp;rsquo;t, because there is no such test, for humans or machines. That being so, the only safe assumption to make is that yes, they are conscious. In other words the safe assumption is that they are &lt;em&gt;people&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So, the glorious AI future is that we will all have intelligent machine assistants which we must assume are conscious and so are people. These people are bound to do our bidding.&lt;/p&gt;

&lt;p&gt;There is a word for that: slavery. The glorious AI future is slavery.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2025-08-22-the-glorious-ai-future-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;No, not the Turing test: if it&amp;rsquo;s not obvious to you that it&amp;rsquo;s junk and always has been then you need to think harder about it.&amp;nbsp;&lt;a href="#2025-08-22-the-glorious-ai-future-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>The zombie internet apocalypse</title>
   <link>https://www.tfeb.org/fragments/2024/10/18/the-zombie-internet-apocalypse/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2024-10-18-the-zombie-internet-apocalypse</guid>
   <pubDate>Fri, 18 Oct 2024 09:24:34 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Dead_Internet_theory" title="Dead internet theory"&gt;dead internet theory&lt;/a&gt; is a conspiracy theory, which in itself is enough reason to doubt it. Like many fashionable conspiracy theories it originated in regions of the internet frequented by people with really unpleasant views, which is another.&lt;/p&gt;

&lt;p&gt;But.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;The theory really says two things:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;almost everything on the internet is now produced by machines, not humans;&lt;/li&gt;
 &lt;li&gt;this is being intentionally engineered by shadowy elites for reasons.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;The second of these is the usual paranoid conspiracy nonsense. The first is a lot more interesting. In fact you can say something even stronger than the second thing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The zombie internet theory.&lt;/strong&gt; A large and increasing amount of the content on the internet is produced &lt;em&gt;and consumed&lt;/em&gt; by machines, not humans.&lt;/p&gt;

&lt;p&gt;This is interesting because it&amp;rsquo;s testable, because when you do test it you find it appears to be true, because it&amp;rsquo;s easy to see why it is happening and finally because of where it probably leads.&lt;/p&gt;

&lt;p&gt;You don&amp;rsquo;t have to look far to see that quite strange things are happening. Facebook is full of posts containing repetitive and obviously machine-generated images, with tens of thousands of likes. Internet searches, especially for common topics, turn up increasing amounts of repetitive trash which I used to think was generated by people being paid by the word in low-wage economies but is probably now also generated by machine. When you read this stuff you realise pretty quickly that they don&amp;rsquo;t have an answer to what you&amp;rsquo;re looking for (or if they do, they&amp;rsquo;ve stolen it from somewhere else) and that the real purpose of the whole thing is simply to make you spend time reading it.&lt;/p&gt;

&lt;p&gt;And the amount of this junk is increasing rapidly: I&amp;rsquo;m fussy about the correct use of the term &amp;lsquo;exponentially&amp;rsquo;, but it may be increasing exponentially. And exponential processes are things you shouldn&amp;rsquo;t ignore.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s pretty easy to see what is enabling this: the big neural-network systems people now call AI have made it incredibly cheap to generate huge amounts of this content. And other similar systems are busy posing as humans and commenting on it, liking it or whatever.&lt;/p&gt;

&lt;p&gt;These systems are passing the Turing test: they&amp;rsquo;re persuading people that they&amp;rsquo;re humans. But, well, it&amp;rsquo;s arguable that &lt;a href="https://en.wikipedia.org/wiki/ELIZA" title="ELIZA"&gt;ELIZA&lt;/a&gt; passed the Turing test: it isn&amp;rsquo;t, it turns out, a very interesting test. These systems, despite all the breathless hype, are not actually intelligent. The current AI bubble is just that, and I suspect it&amp;rsquo;s mostly driven by the thing that drives most bubbles: a group of people extracting money from the gullible while pretending to believe, or actually believing, in some absurd story. We&amp;rsquo;re not all going to be destroyed by some superintelligent AI. Better hope your pension fund hasn&amp;rsquo;t invested too heavily in the bubble. But that&amp;rsquo;s not the subject of this post.&lt;/p&gt;

&lt;p&gt;A more interesting question is &lt;em&gt;why&lt;/em&gt; is this happening? There are two obvious reasons: propaganda and money.&lt;/p&gt;

&lt;p&gt;Everyone, by now, knows about Russian troll farms and other similar things. These were once, probably, made up of people whose job was to troll. Now they&amp;rsquo;re machines whose job is to troll. And the machines don&amp;rsquo;t eat or sleep so they can troll a whole lot more than the people could. That&amp;rsquo;s not going to end well, but it is also not the subject of this post.&lt;/p&gt;

&lt;p&gt;What about money? Well, money &lt;em&gt;is&lt;/em&gt; the subject of this post. It&amp;rsquo;s about money because the internet is built on advertising: Google isn&amp;rsquo;t a search engine company, it&amp;rsquo;s an ad broker; Facebook isn&amp;rsquo;t a social media company, it&amp;rsquo;s an ad broker; Twitter isn&amp;rsquo;t whatever Musk wants it to be, it&amp;rsquo;s a dying ad broker. And the way these companies get their customers, the advertisers, to pay them is by counting how many times humans look at the adverts they&amp;rsquo;ve placed together with some estimate as to how likely those humans are to buy things as a result. That&amp;rsquo;s why they need to harvest the souls of their users: so they can present the adverts to them which are most likely to make them spend money on the products being advertised. And some of the money they take from advertisers goes to the people creating the content, or some of them, as an incentive to keep creating content.&lt;/p&gt;

&lt;p&gt;So what&amp;rsquo;s happened is that, firstly, people have realised that machine-generated content means that humans spend more time looking at advertising. They probably spend less time on each individual bit of machine-generated junk, but they have to wade through far more of it to get to what they&amp;rsquo;re actually after than they did before it existed. And the people behind the machine-generated content get paid by the ad broker. And it&amp;rsquo;s very, very cheap to make so the amount of it is exploding.&lt;/p&gt;

&lt;p&gt;The ad brokers don&amp;rsquo;t care about this first thing at all. In fact they like it: they don&amp;rsquo;t care if the internet is &lt;a href="https://doctorow.medium.com/social-quitting-1ce85b67b456" title="Social Quitting"&gt;enshittified&lt;/a&gt; for the mere users, so long as the money keeps pouring out of it.&lt;/p&gt;

&lt;p&gt;But &lt;em&gt;secondly&lt;/em&gt; people have realised that it doesn&amp;rsquo;t have to be a human who looks at the adverts: it can be another machine. So long as the machine can persuade the advertising system that it&amp;rsquo;s a human the advertisers pay for the view and the people behind the content get paid. If it can persuade the advertising system that it&amp;rsquo;s a human who is likely to end up buying whatever is being advertised the people behind the content get paid even more. So they spend time making the machines seem like they&amp;rsquo;re humans who are likely to buy things, and so we have a tide of machine-generated content getting tens of thousands of likes from other machines. Content made by zombies being viewed by other zombies.&lt;/p&gt;

&lt;p&gt;Superficially the second trick might seem to be in the ad brokers&amp;rsquo; interests too: there are more views of the advertising from &amp;lsquo;humans&amp;rsquo; and even from &amp;lsquo;humans who are likely to buy the thing being advertised to them&amp;rsquo;.&lt;/p&gt;

&lt;p&gt;But it is not in their interests, or not in the long term. Machines don&amp;rsquo;t buy things, after all, so the advertisers are throwing their money away. The whole vast pyramid that is the internet in 2024 rests on a foundation of the money made by advertisers who sell actual products to humans. Unless the advertisements they place pay for themselves in increased sales they will stop advertising in those places. And the pyramid will fall.&lt;/p&gt;

&lt;p&gt;So they care, or should care, very much about the second thing: if advertisers stop paying them the ad brokers are in trouble. They&amp;rsquo;re in worse trouble because their current market capitalisations are so inflated: when the bottom falls out it has a long way to fall.&lt;/p&gt;

&lt;p&gt;So I am sure the ad brokers have been working very hard to detect when a machine, rather than a human, sees an advertisement. But these are machines which are passing the Turing test: they&amp;rsquo;re fooling &lt;em&gt;humans&lt;/em&gt; that they&amp;rsquo;re human, so I&amp;rsquo;m pretty sure they&amp;rsquo;re going to be able to fool other machines. And the ad brokers have already enshittified their services so much that real humans are beginning to leaving in large numbers: they&amp;rsquo;re in a bad place.&lt;/p&gt;

&lt;p&gt;I think the zombie internet apocalypse is coming. If I was an investor I&amp;rsquo;d be shorting the ad brokers.&lt;/p&gt;</description></item>
  <item>
   <title>Numerical prediction</title>
   <link>https://www.tfeb.org/fragments/2023/07/28/numerical-prediction/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2023-07-28-numerical-prediction</guid>
   <pubDate>Fri, 28 Jul 2023 10:39:12 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;In late 2018, when I still worked at the Met Office, I sent a document to some people there which explained why I thought AI would come to dominate weather forecasting, and why weather forecasting organisations should be looking at AI, urgently. Today, the 28th of July 2023, there is &lt;a href="https://www.economist.com/leaders/2023/07/27/how-ai-could-save-thousands-of-lives-through-weather-forecasting"&gt;a leader on the subject in &lt;em&gt;The Economist&lt;/em&gt;&lt;/a&gt; as well as &lt;a href="https://www.economist.com/science-and-technology/2023/07/26/how-to-better-forecast-the-weather"&gt;an extended article in its Science and Technology section&lt;/a&gt;.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;h2 id="2018"&gt;2018&lt;/h2&gt;

&lt;p&gt;&lt;a href="/texts/2023/numerical-prediction.pdf"&gt;Here&lt;/a&gt;&lt;sup&gt;&lt;a href="#2023-07-28-numerical-prediction-footnote-1-definition" name="2023-07-28-numerical-prediction-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt; is the document I wrote in 2018: if it was ever sensitive I don&amp;rsquo;t think it is now. Here are some excerpts from it&lt;sup&gt;&lt;a href="#2023-07-28-numerical-prediction-footnote-2-definition" name="2023-07-28-numerical-prediction-footnote-2-return"&gt;2&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;Neural networks are likely to provide better weather forecasts in due course than current numerical models. If this is true then weather forecasting organisations that don’t use them will be replaced by ones that do. Even though this only may be true, weather forecasting organisations should be investigating these techniques, today.&lt;/p&gt;
 &lt;p&gt;[&amp;hellip;]&lt;/p&gt;
 &lt;p&gt;[&amp;hellip;] NN models are likely to be highly successful for weather prediction. However they will not be trivial to design and deploy: cargo cult NN approaches are not going to work.&lt;/p&gt;
 &lt;p&gt;If NN models are successful then they will largely displace hand-crafted physics-based models (GCM models such as UM&lt;sup&gt;&lt;a href="#2023-07-28-numerical-prediction-footnote-3-definition" name="2023-07-28-numerical-prediction-footnote-3-return"&gt;3&lt;/a&gt;&lt;/sup&gt;). Weather forecasting is a &lt;em&gt;service&lt;/em&gt;, and consumers of the service care only about how good the forecasts are rather than how they are produced.&lt;/p&gt;
 &lt;p&gt;If this happens then organisations involved in weather forecasting, such as the Met Office, will need to adopt NN models or cease to exist: NNs are an &lt;em&gt;existential threat&lt;/em&gt; to weather forecasting organisations.&lt;/p&gt;
 &lt;p&gt;This means that such organisations should be investigating NN models very seriously &lt;em&gt;now&lt;/em&gt; so that, in the likely case that they are successful, they are not left behind.&lt;/p&gt;
 &lt;p&gt;[&amp;hellip;]&lt;/p&gt;
 &lt;p&gt;The traditional approach [to weather forecasting] is to understand the physics and write a system which numerically solves the equations to a lesser or greater degree of accuracy. This has been pretty successful of course.&lt;/p&gt;
 &lt;p&gt;An alternative approach is to not do that at all, but rather build a system which can, itself, &lt;em&gt;learn&lt;/em&gt; to simulate the weather: a system which can be trained to simulate the weather, in other words, based on observations. As far as I&amp;rsquo;m aware such an approach has not been tried on any significant scale.&lt;/p&gt;
 &lt;p&gt;[&amp;hellip;]&lt;/p&gt;
 &lt;p&gt;&lt;strong&gt;There is copious training data.&lt;/strong&gt; There is obviously a really huge amount of data which can be used to drive a model, which NNs love. But NN models need &lt;em&gt;training&lt;/em&gt; data in general: they need to be told how well they did so they can correct their weights. And weather is almost the best example it&amp;rsquo;s possible to think of of this: if we want to predict, say, rainfall in 24 hours time, then, if we wait 24 hours, we know how much rain actually fell, and we can use that data to teach the model how do to better. &lt;em&gt;And this is true for everything, all the time&lt;/em&gt;: every time the model makes &lt;em&gt;any&lt;/em&gt; prediction about the state at some future time then, at that future time, we know what the state actually is and can use that information to train the model. This is the sort of situation NN people dream about.&lt;/p&gt;
 &lt;p&gt;[&amp;hellip;]&lt;/p&gt;
 &lt;p&gt;[&amp;hellip;] Hand-crafted models are more likely to remain sane than NN models in the early stages. There&amp;rsquo;s no rule that says that an NN won&amp;rsquo;t get some mad idea into its head and start, occasionally, making predictions which are completely physically insane.&lt;/p&gt;
 &lt;p&gt;[&amp;hellip;]&lt;/p&gt;
 &lt;p&gt;While NN models are an almost perfect fit for weather forecasting they are, perhaps surprisingly, a terrible fit for climate modelling. This is for two reasons.&lt;/p&gt;
 &lt;p&gt;&lt;strong&gt;Sparseness of training data.&lt;/strong&gt; NNs are likely to work for weather prediction because the training data is so copious: if you want to predict the weather a given time ahead then you simply predict, wait until that amount of time has elapsed and you have training data, and then you iterate this process. You can&amp;rsquo;t do that for climate: if you want to predict the climate a century ahead you can neither wait for a century for the training data nor can you iterate the process.&lt;/p&gt;
 &lt;p&gt;&lt;strong&gt;Opacity of NN models.&lt;/strong&gt; Even if climate modelling by an NN is technically practical it&amp;rsquo;s an absolutely terrible answer to the questions people actually want to answer. If I run some NN model and it predicts 4 degrees of warming by 2100 the first thing people will ask is &amp;lsquo;why does it predict that?&amp;rsquo;. And the best answer to that question is &amp;lsquo;because some opaque blob of weights which neither I nor any human understands told me that&amp;rsquo;, which is a &lt;em&gt;terrible&lt;/em&gt; answer: it&amp;rsquo;s essentially the same as &amp;lsquo;a voice in my head told me&amp;rsquo;. Given the political sensitivity of climate modelling this is not going to be an answer anyone will accept, and nor should they.&lt;/p&gt;
 &lt;p&gt;So climate modelling is a really good example of a place where a transparent physics-based model is the only reasonable answer. And that&amp;rsquo;s ultimately because the people who are interested in climate ere &lt;em&gt;not&lt;/em&gt; just interested in a statistically-good prediction (whatever that even means in this case): they&amp;rsquo;re interested in &lt;em&gt;why&lt;/em&gt; the prediction is what it is. Climate modelling requires hand-crafted physics-based models, and there&amp;rsquo;s no way around that.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2 id="2023"&gt;2023&lt;/h2&gt;

&lt;p&gt;Here is an excerpt from &lt;a href="https://www.economist.com/leaders/2023/07/27/how-ai-could-save-thousands-of-lives-through-weather-forecasting"&gt;&lt;em&gt;The Economist&lt;/em&gt;&amp;rsquo;s leader&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;The application of machine learning and other forms of artificial intelligence (AI) will improve things further. The supercomputers used for NWP calculate the next days’ weather on the basis of current conditions, the laws of physics and various rules of thumb; doing so at a high resolution eats up calculations by the trillion with ridiculous ease. Now machine-learning systems trained simply on past weather data can more or less match their forecasts, at least in some respects. If advances in AI elsewhere are any guide, that is only the beginning.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Well, I am not some unique genius: many people could, and probably did, see what was coming when I wrote the 2018 document. I predicted that neural network approaches would come to dominate weather forecasting, and it looks like they will.&lt;/p&gt;

&lt;p&gt;But what I also realised remains, I think, important, and is not addressed at all in the articles in &lt;em&gt;The Economist&lt;/em&gt;. And that is this:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;AI, in the form of neural networks, is &lt;em&gt;not&lt;/em&gt; a suitable approach to climate prediction both because the training data is inadequate, but more importantly because it is critical that climate models not only predict the climate but allow people to understand &lt;em&gt;why&lt;/em&gt; they are predicting what they predict, rather than simply being an opaque blob;&lt;/li&gt;
 &lt;li&gt;currently climate models, at least in the Met Office and I am sure elsewhere, are to a great extent parasitic on weather models, sharing a great deal of of their code with those models.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;This means that if weather forecasting becomes dominated by opaque NN models, climate modellers will have to bear the entire cost of funding development of their models. Chances are they can&amp;rsquo;t do that.&lt;/p&gt;

&lt;p&gt;An even worse outcome would be that climate modellers leap into using opaque NN models without thinking through what this means. This would hand the climate denialists who increasingly dominate the politics of the UK a weapon which they would certainly not hesitate to use.&lt;/p&gt;

&lt;p&gt;When I sent the 2018 document to people in the Met Office I did not even receive an acknowledgement: I am quite sure nobody read it. I think this says a great deal about the nature of organisations like the Met Office.&lt;/p&gt;

&lt;p&gt;Despite how the all this might read, I&amp;rsquo;m not at all embittered by this: if I cared about the Met Office in 2018 I certainly don&amp;rsquo;t now, four years later. If anything, I&amp;rsquo;m rather pleased that what I thought, in 2018, would happen does indeed seem to ba happening. Most importantly I want the other thing I realised in 2018 &amp;mdash; that climate modelling &lt;em&gt;isn&amp;rsquo;t&lt;/em&gt; well-suited to NN approaches and that organisations which do both weather and climate modelling need to worry about this as NN approaches to weather forecasting eat physics-based approaches alive &amp;mdash; to exist in some form that is accessible to people. That&amp;rsquo;s why this article exists.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2023-07-28-numerical-prediction-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;The location of this document might change. &lt;a href="https://www.tfeb.org/fragments/2023/07/28/numerical-prediction/"&gt;This post itself&lt;/a&gt; is a better link to remember as I will update the pointer if I move the document.&amp;nbsp;&lt;a href="#2023-07-28-numerical-prediction-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2023-07-28-numerical-prediction-footnote-2-definition" class="footnote-definition"&gt;
   &lt;p&gt;Note that I used the term &amp;lsquo;neural network&amp;rsquo;, abbreviated to &amp;lsquo;NN&amp;rsquo; in the document, as I did not then (and do not now) want to lazily consider neural networks to be the same thing as AI.&amp;nbsp;&lt;a href="#2023-07-28-numerical-prediction-footnote-2-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2023-07-28-numerical-prediction-footnote-3-definition" class="footnote-definition"&gt;
   &lt;p&gt;UM, the Unified Model, was the model the Met Office used for both weather and climate modelling ain 2018.&amp;nbsp;&lt;a href="#2023-07-28-numerical-prediction-footnote-3-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Closed as duplicate considered harmful</title>
   <link>https://www.tfeb.org/fragments/2022/12/05/closed-as-duplicate-considered-harmful/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2022-12-05-closed-as-duplicate-considered-harmful</guid>
   <pubDate>Mon, 05 Dec 2022 16:10:07 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;The various &lt;a href="https://stackexchange.com/"&gt;Stack Exchange&lt;/a&gt; sites, and specifically &lt;a href="https://stackoverflow.com/questions/tagged/lisp"&gt;Stack Overflow&lt;/a&gt;, seem to be some of the best places for getting reasonable answers to questions on a wide range of topics from competent people. They would be a lot better if they were not so obsessed about closing duplicates.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;Closing duplicates seems like a good idea: having a single, canonical, question on a given topic with a single, canonical, answer seems like a good thing. It&amp;rsquo;s not.&lt;/p&gt;

&lt;p&gt;The reason it&amp;rsquo;s not is that it makes two false assumptions:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;that a given question has a single best answer;&lt;/li&gt;
 &lt;li&gt;that this answer does not change over time.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Neither of these assumptions is true for a large number of interesting questions.&lt;/p&gt;

&lt;p&gt;Questions can have several good answers. I have at least three introductory books on &lt;a href="https://en.m.wikipedia.org/wiki/Mathematical_analysis" title="analysis"&gt;analysis&lt;/a&gt;, and not because I didn&amp;rsquo;t find the good one on the first try: I have several because they give different perspectives &amp;mdash; different answers, in the sense of Stack Exchange &amp;mdash; to various aspects of the subject. I have several books on introductory quantum mechanics, several books on introductory general relativity, and so it goes on. It is, simply, a delusion that there exists a single most helpful answer to many questions: pretending that there is stupidly limiting.&lt;/p&gt;

&lt;p&gt;And what constitutes a good answer can change over time. If you asked, for instance, what a macro was in Lisp and what macros are good for, you would have got very different answers in 1982 than in 2022&lt;sup&gt;&lt;a href="#2022-12-05-closed-as-duplicate-considered-harmful-footnote-1-definition" name="2022-12-05-closed-as-duplicate-considered-harmful-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;. The same is true for many other subjects: human knowledge is not static.&lt;/p&gt;

&lt;p&gt;All of this is made worse as only the person asking a question can accept an answer: they may not do so at all or, worse, they may be asking in bad faith and accept wrong or misleading answers (yes, this happens in various Stack Exchanges).&lt;/p&gt;

&lt;p&gt;The true Stack Exchange believer will now explain in great detail&lt;sup&gt;&lt;a href="#2022-12-05-closed-as-duplicate-considered-harmful-footnote-2-definition" name="2022-12-05-closed-as-duplicate-considered-harmful-footnote-2-return"&gt;2&lt;/a&gt;&lt;/sup&gt; why none of this matters: people should just spend their time adding improved answers to questions which already have accepted answers rather than to new questions which will be closed as duplicates. Because, of course, the accepted answer will not be the one almost everyone looks at, and even if they don&amp;rsquo;t care about increasing their karma on Stack Exchange, they will be very happy to write answers that, in the real world, almost nobody will ever look at.&lt;/p&gt;

&lt;p&gt;Yeah, right.&lt;/p&gt;

&lt;p&gt;This is such a shame: Stack Exchange is a good thing, but it&amp;rsquo;s seriously damaged by this unnescessary problem. The answer is not simply to allow unrestricted duplicates, but to wait for a bit and see if a question which is, or is nearly, a duplicate has attracted new and interesting answers, and to not close it as a duplicate in that case. This would not be hard to do.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2022-12-05-closed-as-duplicate-considered-harmful-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;And even in 2022 you will get answers from people who seem not to have learned anything since 1982.&amp;nbsp;&lt;a href="#2022-12-05-closed-as-duplicate-considered-harmful-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2022-12-05-closed-as-duplicate-considered-harmful-footnote-2-definition" class="footnote-definition"&gt;
   &lt;p&gt;Please, don&amp;rsquo;t: I don&amp;rsquo;t have a Stack Exchange account any more and, even if I did, I would not be interested.&amp;nbsp;&lt;a href="#2022-12-05-closed-as-duplicate-considered-harmful-footnote-2-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Vector supercomputers</title>
   <link>https://www.tfeb.org/fragments/2021/12/30/vector-supercomputers/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2021-12-30-vector-supercomputers</guid>
   <pubDate>Thu, 30 Dec 2021 12:20:51 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;There are apocryphal reports that Apple M1 systems are not as fast as people have been led to believe for general-purpose programs. That&amp;rsquo;s unsurprising.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;I think what&amp;rsquo;s happened is that vector supercomputers have secretly won, and with them come all their performance weirdnesses that make a lot of code really suck: no-one wanted to run anything other than rather specialised programs on a Cray 1 or any of its descendants because it was just not very fast for that. Vector supercomputers were great at numerical loops over large arrays, but they were absolutely terrible at code which had to make lots of actual decisions.&lt;/p&gt;

&lt;p&gt;So now we&amp;rsquo;re seeing machines which are optimised to be extremely good at mashing arrays of numbers, and much less good at general computation. Of course, unlike the 1970s &amp;amp; 80s machines &amp;lsquo;much less good&amp;rsquo; is &amp;lsquo;quite good enough&amp;rsquo; in almost all cases.&lt;/p&gt;

&lt;p&gt;And they&amp;rsquo;ve won, really, because we&amp;rsquo;re in the middle of another AI hype-cycle: the last hype cycle gave us all sorts of weird hardware like Lisp machines, graph-reduction machines and so on: this one, which is built, really, on programs which ought to be written in Fortran, is giving us special-purpose array-mashing machines &amp;mdash; vector supercomputers, in other words &amp;mdash; which are really good at all the annoying machine-learning things our computers now insist on foisting on us.&lt;/p&gt;

&lt;p&gt;Well, this AI hype cycle will be like all the other AI hype cycles: despite the idiot boosters who have conveniently forgotten what happened last time and all the times before that, we are not anywhere near some kind of strong AI based on machine learning. Already you can see this: whatever language-learning system we&amp;rsquo;re all meant to worship at the feet of has now been trained on &lt;em&gt;all the natural language that exists on the internet&lt;/em&gt;, in order to produce results which are not, in fact, acceptable. And there&amp;rsquo;s nowhere to go from here: there is no more training data.&lt;/p&gt;

&lt;p&gt;It remains to be seen whether array-mashing machines outlive the hype that gave rise to them: there are good uses for systems like this, just as there are good uses for machine learning, but when the bubble bursts it may yet take them with it.&lt;/p&gt;</description></item>
  <item>
   <title>The proper use of macros in Lisp</title>
   <link>https://www.tfeb.org/fragments/2021/11/11/the-proper-use-of-macros-in-lisp/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2021-11-11-the-proper-use-of-macros-in-lisp</guid>
   <pubDate>Thu, 11 Nov 2021 14:32:11 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;People learning Lisp often try to learn how to write macros by taking an existing function they have written and turning it into a macro. This is a mistake: macros and functions serve different purposes and it is almost never useful to turn functions into macros, or macros into functions.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;Let&amp;rsquo;s say you are learning Common Lisp&lt;sup&gt;&lt;a href="#2021-11-11-the-proper-use-of-macros-in-lisp-footnote-1-definition" name="2021-11-11-the-proper-use-of-macros-in-lisp-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;, and you have written a fairly obvious factorial function based on the natural mathematical definition: if \(n \in \mathbb{N}\), then&lt;/p&gt;

&lt;p&gt;\[
n! = 
\begin{cases}
 1 &amp;amp;n \le 1\\
 n \times (n - 1)! &amp;amp;n &amp;gt; 1
\end{cases}
\]&lt;/p&gt;

&lt;p&gt;So this gives you a fairly obvious recursive definition of &lt;code&gt;factorial&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(defun factorial (n)
  (if (&amp;lt;= n 1)
      1
    (* n (factorial (1- n )))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And so, you think you want to learn about macros so can you write &lt;code&gt;factorial&lt;/code&gt; as a macro? And you might end up with something like this:&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(defmacro factorial (n)
  `(if (&amp;lt;= ,n 1)
      1
    (* ,n (factorial ,(1- n )))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And this superficially seems as if it works:&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;&amp;gt; (factorial 10)
3628800&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But it doesn&amp;rsquo;t, in fact, work:&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;&amp;gt; (let ((x 3))
    (factorial x))

Error: In 1- of (x) arguments should be of type number.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Why doesn&amp;rsquo;t this work and can it be fixed so it does? If it can&amp;rsquo;t what has gone wrong and how are macros meant to work and what are they useful for?&lt;/p&gt;

&lt;p&gt;It can&amp;rsquo;t be fixed so that it works. trying to rewrite functions as macros is a bad idea, and if you want to learn what is interesting about macros you should not start there.&lt;/p&gt;

&lt;p&gt;To understand why this is true you need to understand what macros actually &lt;em&gt;are&lt;/em&gt; in Lisp.&lt;/p&gt;

&lt;h2 id="what-macros-are-a-first-look"&gt;What macros are: a first look&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A macro is a function whose domain and range is &lt;em&gt;syntax&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Macros &lt;em&gt;are&lt;/em&gt; functions (quite explicitly so in CL: you can get at the function of a macro with &lt;code&gt;macro-function&lt;/code&gt;, and this is something you can happily call the way you would call any other function), but they are functions whose domain and range is &lt;em&gt;syntax&lt;/em&gt;. A macro is a function whose argument is a language whose syntax includes the macro and whose value, when called on an instance of that language, is a language whose syntax &lt;em&gt;doesn&amp;rsquo;t&lt;/em&gt; include the macro. It may work recursively: its value may be a language which includes the same macro but in some simpler way, such that the process will terminate at some point.&lt;/p&gt;

&lt;p&gt;So the job of macros is to provide a family of extended languages built on some core Lisp which has no remaining macros, only functions and function application, special operators &amp;amp; special forms involving them and literals. One of those languages is the language we call Common Lisp, but the macros written by people serve to extend this language into a multitude of variants.&lt;/p&gt;

&lt;p&gt;As an example of this I often write in a language which is like CL, but is extended by the presence of a number of extra constructs, one of which is called ITERATE (but it predates the well-known one and is not at all the same):&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(iterate next ((x 1))
 (if (&amp;lt; x 10)
     (next (1+ x))
   x)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;is equivalent to&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(labels ((next (x)
          (if (&amp;lt; x 10)
              (next (1+ x))
            x)))
 (next 1))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once upon a time when I first wrote &lt;code&gt;iterate&lt;/code&gt;, it used to manually optimize the recursive calls to jumps in some cases, because the Symbolics I wrote it on didn&amp;rsquo;t have tail-call elimination. That&amp;rsquo;s a non-problem in LispWorks&lt;sup&gt;&lt;a href="#2021-11-11-the-proper-use-of-macros-in-lisp-footnote-2-definition" name="2021-11-11-the-proper-use-of-macros-in-lisp-footnote-2-return"&gt;2&lt;/a&gt;&lt;/sup&gt;. Anyone familiar with Scheme will recognise &lt;code&gt;iterate&lt;/code&gt; as named &lt;code&gt;let&lt;/code&gt;, which is where it came from (once, I think, it was known as &lt;code&gt;nlet&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;iterate&lt;/code&gt; is implemented by a function which maps from the language which includes it to a language which doesn&amp;rsquo;t include it, by mapping the syntax as above.&lt;/p&gt;

&lt;p&gt;So compare this with a factorial function: factorial is a function whose domain is natural numbers and whose range is also natural numbers, and it has an obvious recursive definition. Well, natural numbers are part of the syntax of Lisp, but they&amp;rsquo;re a tiny part of it. So implementing factorial as a macro is, really, a hopeless task. What should&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(factorial (+ x y (f z)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Actually do when considered as a mapping between languages? Assuming you are using the recursive definition of the factorial function then the answer is it can&amp;rsquo;t map to anything useful at all: a function which implements that recursive definition simply has to be called at run time. The very best you could do would seem to be this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun fact (n)
 (if (&amp;lt; n 3)
     n
   (* n (fact (1- n)))))

(defmacro factorial (expression)
 `(fact ,expression))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And that&amp;rsquo;s not a useful macro (but see below).&lt;/p&gt;

&lt;p&gt;So the answer is, again, that macros are functions which map between &lt;em&gt;languages&lt;/em&gt; and they are useful where you want a new &lt;em&gt;language&lt;/em&gt;: not just the same language with extra functions in it, but a language with new control constructs or something like that. If you are writing functions whose range is something which is not the syntax of a language built on Common Lisp, &lt;em&gt;don&amp;rsquo;t write macros&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id="what-macros-are-a-second-look"&gt;What macros are: a second look&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Macroexpansion is compilation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A function whose domain is one language and whose range is another is a &lt;em&gt;compiler&lt;/em&gt; for the language of the domain, especially when that language is somehow richer than the language of the range, which is the case for macros.&lt;/p&gt;

&lt;p&gt;But it&amp;rsquo;s a simplification to say that &lt;em&gt;macros&lt;/em&gt; are this function: they&amp;rsquo;re not, they&amp;rsquo;re only part of it. The actual function which maps between the two languages is made up of macros &lt;em&gt;and the macroexpander provided by CL itself&lt;/em&gt;. The macroexpander is what arranges for the functions defined by macros to be called in the right places, and also it is the thing which arranges for various recursive macros to actually make up a recurscive function. So it&amp;rsquo;s important to understand that the macroexpander is a critical part of the process: macros on their own only provide part of it.&lt;/p&gt;

&lt;h2 id="an-example-two-versions-of-a-recursive-macro"&gt;An example: two versions of a recursive macro&lt;/h2&gt;

&lt;p&gt;People often say that you should not write recursive macros, but this prohibition on recursive macros is pretty specious: they&amp;rsquo;re just fine. Consider a language which only has &lt;code&gt;lambda&lt;/code&gt; and doesn&amp;rsquo;t have &lt;code&gt;let&lt;/code&gt;. Well, we can write a simple version of &lt;code&gt;let&lt;/code&gt;, which I&amp;rsquo;ll call &lt;code&gt;bind&lt;/code&gt; as a macro: a function which takes this new language and turns it into the more basic one. Here&amp;rsquo;s that macro:&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(defmacro bind ((&amp;amp;rest bindings) &amp;amp;body forms)
 `((lambda ,(mapcar #'first bindings) ,@forms)
   ,@(mapcar #'second bindings)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;&amp;gt; (bind ((x 1) (y 2))
    (+ x y))              
(bind ((x 1) (y 2)) (+ x y))
 -&amp;gt; ((lambda (x y) (+ x y)) 1 2)
3&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(These example expansions come via use of my &lt;a href="https://tfeb.github.io/tfeb-lisp-hax/#tracing-macroexpansion-trace-macroexpand"&gt;trace-macroexpand package&lt;/a&gt;, available in a good Lisp near you: see appendix for configuration).&lt;/p&gt;

&lt;p&gt;So now we have a language with a binding form which is more convenient than &lt;code&gt;lambda&lt;/code&gt;. But maybe we want to be able to bind sequentially? Well, we can write a &lt;code&gt;let*&lt;/code&gt; version, called &lt;code&gt;bind*&lt;/code&gt;, which looks like this&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(defmacro bind* ((&amp;amp;rest bindings) &amp;amp;body forms)
 (if (null (rest bindings))
     `(bind ,bindings ,@forms)
   `(bind (,(first bindings))
      (bind* ,(rest bindings) ,@forms))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And you can see how this works: it checks if there&amp;rsquo;s just one binding in which case it&amp;rsquo;s just &lt;code&gt;bind&lt;/code&gt;, and if there&amp;rsquo;s more than one it peels off the first and then expands into a &lt;code&gt;bind*&lt;/code&gt; form for the rest. And you can see this working (here both &lt;code&gt;bind&lt;/code&gt; and &lt;code&gt;bind*&lt;/code&gt; are being traced):&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;&amp;gt; (bind* ((x 1) (y (+ x 2)))
    (+ x y))
(bind* ((x 1) (y (+ x 2))) (+ x y))
 -&amp;gt; (bind ((x 1)) (bind* ((y (+ x 2))) (+ x y)))
(bind ((x 1)) (bind* ((y (+ x 2))) (+ x y)))
 -&amp;gt; ((lambda (x) (bind* ((y (+ x 2))) (+ x y))) 1)
(bind* ((y (+ x 2))) (+ x y))
 -&amp;gt; (bind ((y (+ x 2))) (+ x y))
(bind ((y (+ x 2))) (+ x y))
 -&amp;gt; ((lambda (y) (+ x y)) (+ x 2))
(bind* ((y (+ x 2))) (+ x y))
 -&amp;gt; (bind ((y (+ x 2))) (+ x y))
(bind ((y (+ x 2))) (+ x y))
 -&amp;gt; ((lambda (y) (+ x y)) (+ x 2))
4&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see that, in this implementation, which is LW again, some of the forms are expanded more than once: that&amp;rsquo;s not uncommon in interpreted code: since macros should generally be functions (so, not have side-effects) it does not matter that they may be expanded multiple times. Compilation will expand macros and then compile the result, so all the overhead of macroexpansion happend ahead of run-time:&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt; (defun foo (x)
   (bind* ((y (1+ x)) (z (1+ y)))
     (+ y z)))
foo

&amp;gt; (compile *)
(bind* ((y (1+ x)) (z (1+ y))) (+ y z))
 -&amp;gt; (bind ((y (1+ x))) (bind* ((z (1+ y))) (+ y z)))
(bind ((y (1+ x))) (bind* ((z (1+ y))) (+ y z)))
 -&amp;gt; ((lambda (y) (bind* ((z (1+ y))) (+ y z))) (1+ x))
(bind* ((z (1+ y))) (+ y z))
 -&amp;gt; (bind ((z (1+ y))) (+ y z))
(bind ((z (1+ y))) (+ y z))
 -&amp;gt; ((lambda (z) (+ y z)) (1+ y))
foo
nil
nil

&amp;gt; (foo 3)
9&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There&amp;rsquo;s nothing wrong with macros like this, which expand into simpler versions of themselves. You just have to make sure that the recursive expansion process is producing successively simpler bits of syntax and has a well-defined termination condition.&lt;/p&gt;

&lt;p&gt;Macros like this are often called &amp;lsquo;recursive&amp;rsquo; but they&amp;rsquo;re actually not: the function associated with &lt;code&gt;bind*&lt;/code&gt; does not call itself. What &lt;em&gt;is&lt;/em&gt; recursive is the function implicitly defined by the combination of the macro function and the macroexpander: the &lt;code&gt;bind*&lt;/code&gt; function simply expands into a bit of syntax which it knows will cause the macroexpander to call it again.&lt;/p&gt;

&lt;p&gt;It is possible to write &lt;code&gt;bind*&lt;/code&gt; such that the macro function &lt;em&gt;itself&lt;/em&gt; is recursive:&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(defmacro bind* ((&amp;amp;rest bindings) &amp;amp;body forms)
  (labels ((expand-bind (btail)
             (if (null (rest btail))
                 `(bind ,btail
                    ,@forms)
               `(bind (,(first btail))
                  ,(expand-bind (rest btail))))))
    (expand-bind bindings)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now compiling &lt;code&gt;foo&lt;/code&gt; again results in this output from tracing macroexpansion:&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(bind* ((y (1+ x)) (z (1+ y))) (+ y z))
 -&amp;gt; (bind ((y (1+ x))) (bind ((z (1+ y))) (+ y z)))
(bind ((y (1+ x))) (bind ((z (1+ y))) (+ y z)))
 -&amp;gt; ((lambda (y) (bind ((z (1+ y))) (+ y z))) (1+ x))
(bind ((z (1+ y))) (+ y z))
 -&amp;gt; ((lambda (z) (+ y z)) (1+ y))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see that now all the recursion happens within the macro function for &lt;code&gt;bind*&lt;/code&gt; itself: the macroexpander calls &lt;code&gt;bind*&lt;/code&gt;&amp;rsquo;s macro function just once.&lt;/p&gt;

&lt;p&gt;While it&amp;rsquo;s possible to write macros like this second version of &lt;code&gt;bind*&lt;/code&gt;, it is normally easier to write the first version and to allow the combination of the macroexpander and the macro function to implement the recursive expansion.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id="two-historical-uses-for-macros"&gt;Two historical uses for macros&lt;/h2&gt;

&lt;p&gt;There are two uses for macros &amp;mdash; both now historical &amp;mdash; where they &lt;em&gt;were&lt;/em&gt; used where functions would be more natural.&lt;/p&gt;

&lt;p&gt;The first of these is &lt;em&gt;function inlining&lt;/em&gt;, where you want to avoid the overhead of calling a small function many times. This overhead was a lot on computers made of cardboard, as all computers were, and also if the stack got too deep the cardboard would tear and this was bad. It makes no real sense to inline a recursive function such as the above &lt;code&gt;factorial&lt;/code&gt;: how would the inlining process terminate? But you could rewrite a factorial function to be explicitly iterative:&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(defun factorial (n)
 (do* ((k 1 (1+ k))
       (f k (* f k)))
      ((&amp;gt;= k n) f)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now, if you have very many calls to &lt;code&gt;factorial&lt;/code&gt;, you wanted to optimise the function call overhead away, &lt;em&gt;and it was 1975&lt;/em&gt;, you might write this:&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(defmacro factorial (n)
 `(let ((nv ,n))
    (do* ((k 1 (1+ k))
          (f k (* f k)))
         ((&amp;gt;= k nv) f))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And this has the effect of replacing &lt;code&gt;(factorial n)&lt;/code&gt; by an expression which will compute the factorial of &lt;code&gt;n&lt;/code&gt;. The cost of that is that &lt;code&gt;(funcall #'factorial n)&lt;/code&gt; is not going to work, and &lt;code&gt;(funcall (macro-function 'factorial) ...)&lt;/code&gt; is never what you want.&lt;/p&gt;

&lt;p&gt;Well, that&amp;rsquo;s what you did in 1975, because Lisp compilers were made out of the things people found down the sides of sofas. Now it&amp;rsquo;s no longer 1975 and you just tell the compiler that you want it to inline the function, please:&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(declaim (inline factorial))
(defun factorial (n) ...)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and it will do that for you. So this use of macros is now purely historicl.&lt;/p&gt;

&lt;p&gt;The second reason for macros where you really want functions is computing things at compile time. Let&amp;rsquo;s say you have lots of expressions like &lt;code&gt;(factorial 32)&lt;/code&gt; in your code. Well, you could do this:&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(defmacro factorial (expression)
 (typecase expression
   ((integer 0)
    (factorial/fn expression))
   (number
    (error "factorial of non-natural literal ~S" expression))
   (t
    `(factorial/fn ,expression))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So the &lt;code&gt;factorial&lt;/code&gt; macro checks to see if its argument is a literal natural number and will compute the factorial of it at macroexpansion time (so, at compile time or just before compile time). So a function like&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(defun foo ()
 (factorial 32))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;will now compile to simply return &lt;code&gt;263130836933693530167218012160000000&lt;/code&gt;. And, even better, there&amp;rsquo;s some compile-time error checking: code which is, say, &lt;code&gt;(factorial 12.3)&lt;/code&gt; will cause a compile-time error.&lt;/p&gt;

&lt;p&gt;Well, again, this is what you would do if it was 1975. It&amp;rsquo;s not 1975 any more, and CL has a special tool for dealing with just this problem: compiler macros.&lt;/p&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(defun factorial (n)
 (do* ((k 1 (1+ k))
       (f k (* f k)))
      ((&amp;gt;= k n) f)))

(define-compiler-macro factorial (&amp;amp;whole form n)
 (typecase n
   ((integer 0)
    (factorial n))
   (number
    (error "literal number is not a natural: ~S" n))
   (t form)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now &lt;code&gt;factorial&lt;/code&gt; is a function and works the way you expect &amp;mdash; &lt;code&gt;(funcall #'factoial ...)&lt;/code&gt; will work fine. But the compiler knows that if it comes across &lt;code&gt;(factorial ...)&lt;/code&gt; then it should give the compiler macro for &lt;code&gt;factorial&lt;/code&gt; a chance to say what this expression should actually be. And the compiler macro does an explicit check for the argument being a literal natural number, and if it is computes the factorial at compile time, and the same check for a literal number which is not a natural, and finally just says &amp;rsquo;I don&amp;rsquo;t know, call the function&amp;rsquo;. Note that the compiler macro itself calls &lt;code&gt;factorial&lt;/code&gt;, but since the argument isn&amp;rsquo;t a literal there&amp;rsquo;s no recursive doom.&lt;/p&gt;

&lt;p&gt;So this takes care of the other antique use of macros where you would expect functions. And of course you can combine this with inlining and it will all work fine: you can write functions which will handle special cases via compiler macros and will otherwise be inlined.&lt;/p&gt;

&lt;p&gt;That leaves macros serving the purpose they are actually useful for: building languages.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id="appendix-setting-up-trace-macroexpand"&gt;Appendix: setting up &lt;code&gt;trace-macroexpand&lt;/code&gt;&lt;/h2&gt;

&lt;pre class="brush: lisp"&gt;&lt;code&gt;(use-package :org.tfeb.hax.trace-macroexpand)

;;; Don't restrict print length or level when tracing
(setf *trace-macroexpand-print-level* nil
      *trace-macroexpand-print-length* nil)

;;; Enable tracing
(trace-macroexpand)

;;; Trace the macros you want to look at ...
(trace-macro ...)

;;; ... and ntrace them
(untrace-macro ...)&lt;/code&gt;&lt;/pre&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2021-11-11-the-proper-use-of-macros-in-lisp-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;All the examples in this article are in Common Lisp except where otherwise specified. Other Lisps have similar considerations, although macros in Scheme are not explicitly functions in the way they are in CL.&amp;nbsp;&lt;a href="#2021-11-11-the-proper-use-of-macros-in-lisp-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-11-11-the-proper-use-of-macros-in-lisp-footnote-2-definition" class="footnote-definition"&gt;
   &lt;p&gt;This article originated as a message on the &lt;code&gt;lisp-hug&lt;/code&gt; mailing list for &lt;a href="http://www.lispworks.com/"&gt;LispWorks&lt;/a&gt; users. References to &amp;lsquo;LW&amp;rsquo; mean LispWorks, although everything here should apply to any modern CL. (In terms of tail call elimination I would define a CL which does not eliminate tail self-calls in almost all cases under reasonable optimization settings as pre-modern: I don&amp;rsquo;t use such implementations.)&amp;nbsp;&lt;a href="#2021-11-11-the-proper-use-of-macros-in-lisp-footnote-2-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>The best Lisp</title>
   <link>https://www.tfeb.org/fragments/2021/11/03/the-best-lisp/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2021-11-03-the-best-lisp</guid>
   <pubDate>Wed, 03 Nov 2021 12:03:44 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;People sometimes ask &lt;a href="https://www.reddit.com/r/lisp/comments/qlcza4/best_lisp_dialect/"&gt;which is the best Lisp dialect&lt;/a&gt;? That&amp;rsquo;s a category error, and here&amp;rsquo;s why.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;Programming in Lisp &amp;mdash; any Lisp &amp;mdash; is about &lt;em&gt;building languages&lt;/em&gt;: in Lisp the way you solve a problem is by building a language &amp;mdash; a jargon, or a dialect if you like &amp;mdash; to talk about the problem and then solving the problem in that language. Lisps are, quite explicitly, language-building languages.&lt;/p&gt;

&lt;p&gt;This is, in fact, how people solve large problems in &lt;em&gt;all&lt;/em&gt; programming languages: &lt;a href="https://en.wikipedia.org/wiki/Greenspun's_tenth_rule" title="Greenspun's tenth rule"&gt;Greenspun&amp;rsquo;s tenth rule&lt;/a&gt; isn&amp;rsquo;t really a statement about Common Lisp, it&amp;rsquo;s a statement that all sufficiently large software systems end up having some hacked-together, informally-specified, half-working &lt;em&gt;language&lt;/em&gt; in which the problem is actually solved. Often people won&amp;rsquo;t understand that the thing they&amp;rsquo;ve built is in fact a language, but that&amp;rsquo;s what it is. Everyone who has worked on large-scale software will have come across these things: often they are very horrible, and involve much use of language-in-a-string&lt;sup&gt;&lt;a href="#2021-11-03-the-best-lisp-footnote-1-definition" name="2021-11-03-the-best-lisp-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;The Lisp difference is two things: when you start solving a problem in Lisp, you &lt;em&gt;know&lt;/em&gt;, quite explicitly, that this is what you are going to do; and the language has wonderful tools which let you incrementally build a series of lightweight languages, ending up with one or more languages in which to solve the problem.&lt;/p&gt;

&lt;p&gt;So, after that preface, why is this question the wrong one to ask? Well, if you are going to program in Lisp you are going to be building languages, and you want those languages not to be awful. Lisp makes it it far easier to build languages which are not awful, but it doesn&amp;rsquo;t prevent you doing so if you want to. And again, anyone who has dealt with enough languages built on Lisps will have come across some which are, in fact, awful.&lt;/p&gt;

&lt;p&gt;If you are going to build languages then you need to understand how languages work &amp;mdash; what makes a language habitable to its human users (the computer does not care with very few exceptions). That means you will need to be a &lt;em&gt;linguist&lt;/em&gt;. So the question then is: how do you become a linguist? Well, we know the answer to that, because there are lots of linguists and lots of courses on linguistics. You might say that, well, those people study &lt;em&gt;natural&lt;/em&gt; languages, but that&amp;rsquo;s irrelevant: natural languages have been under evolutionary pressure for a very long time and they&amp;rsquo;re really &lt;em&gt;good&lt;/em&gt; for what they&amp;rsquo;re designed for (which is not the same as what programming languages are designed for, but the users &amp;mdash; humans &amp;mdash; are the same).&lt;/p&gt;

&lt;p&gt;So, do you become a linguist by learning French? Or German? Or Latin? Or Cuzco Quechua? No, you don&amp;rsquo;t. You become a linguist by learning enough about enough languages that you can understand how languages work. A linguist isn&amp;rsquo;t someone who speaks French really well: they&amp;rsquo;re someone who understands that French is a Romance language, that German isn&amp;rsquo;t but has many Romance loan words, that English is closer to German than it is French but got a vast injection of Norman French, which in turn wasn&amp;rsquo;t that close to modern French, that Swiss German has cross-serial dependencies but Hochdeutsch does not and what that means, and so on. A linguist is someone who understands things about the &lt;em&gt;structure&lt;/em&gt; of languages: what do you see, what do you never see, how do different languages do equivalent things? And so on.&lt;/p&gt;

&lt;p&gt;The way you become a linguist is not by picking a language and learning it: it&amp;rsquo;s by looking at lots of languages enough to understand how they work.&lt;/p&gt;

&lt;p&gt;If you want to learn to program in Lisp, you will need to become a linguist. The very best way to ensure you fail at that is to pick a &amp;lsquo;best&amp;rsquo; Lisp and learn that. There is no best Lisp, and in order to program well in &lt;em&gt;any&lt;/em&gt; Lisp you must be exposed to as many Lisps and as many other languages as possible.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;If you think there&amp;rsquo;s a distinction between a &amp;lsquo;dialect&amp;rsquo;, a &amp;lsquo;jargon&amp;rsquo; and a &amp;lsquo;language&amp;rsquo; then I have news for you: there is. A language is a dialect with a standards committee. (This is stolen from a quote due to Max Weinrich that all linguists know:&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;אַ שפּראַך איז אַ דיאַלעקט מיט אַן אַרמיי און פֿלאָט&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;a shprakh iz a dyalekt mit an armey un flot.)&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2021-11-03-the-best-lisp-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;&amp;lsquo;Language-in-a-string&amp;rsquo; is where a programming language has another programming language embedded in strings in the outer language. Sometimes programs in that inner programming language will be made up by string concatenation in the outer language. Sometimes that inner language will, in turn, have languages embedded in its strings. It&amp;rsquo;s a terrible, terrible thing.&amp;nbsp;&lt;a href="#2021-11-03-the-best-lisp-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Computer insecurity</title>
   <link>https://www.tfeb.org/fragments/2021/09/27/computer-insecurity/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2021-09-27-computer-insecurity</guid>
   <pubDate>Mon, 27 Sep 2021 15:35:02 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Making computer systems secure is very difficult. The consequences of insecure systems are already extremely serious and will be catastrophic in future if they are not already. Malignant people, often sponsored by malignant states, are actively attacking computer systems and have had considerable success doing so.&lt;/p&gt;

&lt;p&gt;So it is surprising that companies whose stated aims are to increase security are effectively working to make their customers&amp;rsquo; systems less secure.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;h2 id="managing-large-complex-computing-installations"&gt;Managing large, complex computing installations&lt;/h2&gt;

&lt;p&gt;For any large, complex computing installation&lt;sup&gt;&lt;a href="#2021-09-27-computer-insecurity-footnote-1-definition" name="2021-09-27-computer-insecurity-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;, simply &lt;em&gt;managing&lt;/em&gt; it is a problem. The way of managing a small installation &amp;mdash; having someone (part of) whose job is to look after the installation &amp;mdash; has terrible scaling problems: if your installation has a million OS instances, then keeping them up to date might involve a hundred thousand people. And if you could afford that many people you still haven&amp;rsquo;t solved the problem: with a large number of people whose job is to look after parts of the installation there is a vanishingly tiny chance that they will do so consistently.&lt;/p&gt;

&lt;p&gt;For systems which are merely &lt;em&gt;large&lt;/em&gt; this problem can be made a lot simpler: for such a system the number of components is far larger than the number of tasks the system performs, so there are many components for each task. These components can then be forced to be identical (or identical-enough). The failure of single components simply lowers the capacity of the system in almost all cases. There are still scaling problems &amp;mdash; for a system with a huge amount of hardware, hardware failure rates will mean that more of the hardware fails and needs to be replaced, requiring people to actually do the replacement &amp;mdash; but much of the management of such a system scales much less than linearly with its size. Finding problems which both can be solved by systems which are merely large and from which money can be made is what made the giant internet companies so rich, of course&lt;sup&gt;&lt;a href="#2021-09-27-computer-insecurity-footnote-2-definition" name="2021-09-27-computer-insecurity-footnote-2-return"&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;For systems which are both large and complex the problem is far harder: because such a system is performing a large number of distinct tasks managing it necessarily requires people with expertise in all these tasks, and there are only so many things a person can be good at. Because of this, running such a system is never really scalable. But, if you can isolate various layers of the system &amp;mdash; the computing and storage hardware, the operating system, the software platform on which applications live, and so on &amp;mdash; then you can make &lt;em&gt;those&lt;/em&gt; parts of the system into something which is merely large, and you &lt;em&gt;can&lt;/em&gt; manage those in a way which will scale.&lt;/p&gt;

&lt;p&gt;This, of course, is exactly what everyone with a large, complex computing installation is trying to do.&lt;/p&gt;

&lt;h3 id="single-points-of-control"&gt;Single points of control&lt;/h3&gt;

&lt;p&gt;The trick to managing a large installation, or the parts of a large, complex installation which can be made merely large, is to have &lt;em&gt;single points of control&lt;/em&gt;. For instance, if I want to deploy some update to a very large number of machines, I very definitely don&amp;rsquo;t want to have to access each machine individually to do that: instead I need to have some single point of control from where I can say &amp;lsquo;deploy this update to this set of machines&amp;rsquo; and that will just happen, and I&amp;rsquo;ll get some kind of report about which machines it worked on and so on.&lt;/p&gt;

&lt;p&gt;Making the management of large installations scalable requires these single points of control. They may not be rooms full of dials and flashing lights in hollowed-out volcanos staffed by people in white coats, where occasional klaxons sound (although, of course, they should be), but they have to exist, somewhere: it must be the case that changes to the system can be made in one place, or a very small number of places, and take effect over the whole system. There&amp;rsquo;s no other way to do this.&lt;/p&gt;

&lt;h3 id="a-security-problem"&gt;A security problem&lt;/h3&gt;

&lt;p&gt;Single points of control present a quite considerable security problem. They are necessary so that the system can be managed efficiently, but it doesn&amp;rsquo;t say anywhere that the changes made from such a single point of control are &lt;em&gt;good&lt;/em&gt; changes. So two things are extremely important:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;all the single points of control need to be known about and their number should be kept as small as possible;&lt;/li&gt;
 &lt;li&gt;all the single points of control must be very carefully managed, with extensive controls over access, carefully managed logs and so forth.&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;I suspect most organisations fail at both of these, unfortunately: they neither keep a careful catalogue of the single points of control and nor do they control access to them carefully enough. This essay, however, is not about how to deal with this problem except in one respect.&lt;/p&gt;

&lt;h3 id="transitive-closure"&gt;Transitive closure&lt;/h3&gt;

&lt;p&gt;To understand what the single points of control are you need to understand the notion of &lt;em&gt;transitive closure&lt;/em&gt;. This is pretty simple, fortunately: if a system \(a\) controls a system \(b\), and system \(b\) controls systems \(c, d, \ldots\), then, by transitive closure, system \(a\) controls all of systems \(c, d, \ldots\). And similarly, if \(d\) controls \(g\), then \(a\) also controls \(g\). What this means is that, in order to understand what the single points of control are, you need to construct graphs&lt;sup&gt;&lt;a href="#2021-09-27-computer-insecurity-footnote-3-definition" name="2021-09-27-computer-insecurity-footnote-3-return"&gt;3&lt;/a&gt;&lt;/sup&gt; of the transitive closure of control. This is not hard to do, but it &lt;em&gt;is&lt;/em&gt; quite hard for people to remember these graphs: they really need to exist in some explicit form. Doing this is also a good exercise in making sure you actually do think hard about what the nodes in the graph are: what &lt;em&gt;are&lt;/em&gt; the things which grant control over some system, and how are they being managed.&lt;/p&gt;

&lt;p&gt;An important thing about this transitive closure of control is that everything gets more sensitive as you go up the graph&lt;sup&gt;&lt;a href="#2021-09-27-computer-insecurity-footnote-4-definition" name="2021-09-27-computer-insecurity-footnote-4-return"&gt;4&lt;/a&gt;&lt;/sup&gt;: the higher nodes in the graph control more lower nodes, and often very many more lower nodes. If the graph is a tree with a constant branching factor then the number of nodes controlled goes up like \(n!\) as you get higher in the tree, and that&amp;rsquo;s fast: it&amp;rsquo;s tempting to say it goes up exponentially, but it doesn&amp;rsquo;t: it goes up much faster than that.&lt;/p&gt;

&lt;p&gt;All of this means that for large installations the points of control near the top of the tree are &lt;em&gt;extremely&lt;/em&gt; sensitive: they need to be very tightly controlled indeed. It would be foolish, wouldn&amp;rsquo;t it, to allow third-parties to manage these points of control?&lt;/p&gt;

&lt;h3 id="were-all-fools"&gt;We&amp;rsquo;re all fools&lt;/h3&gt;

&lt;p&gt;Of course, we all do exactly that, all the time. We all run software we have neither written nor exhaustively checked&lt;sup&gt;&lt;a href="#2021-09-27-computer-insecurity-footnote-5-definition" name="2021-09-27-computer-insecurity-footnote-5-return"&gt;5&lt;/a&gt;&lt;/sup&gt;, on hardware we don&amp;rsquo;t really understand, for instance, and thus outsource our security to the people who write this software and make this hardware. And most of the time it&amp;rsquo;s OK. Most of the time. Sometimes bad things are found in the software or the hardware and we have to rush around to deal with them. Well, not so much &amp;lsquo;sometimes&amp;rsquo; as &amp;lsquo;quite often&amp;rsquo; in fact.&lt;/p&gt;

&lt;p&gt;But we don&amp;rsquo;t really have much choice about this: in theory we could build our own hardware and write our own software to run on it as people did in the 1940s and 1950s, but in practice that&amp;rsquo;s absurdly impractical.&lt;/p&gt;

&lt;p&gt;But that&amp;rsquo;s not where it ends, of course. We now all love our cloud computing: running our software on top of platforms and hardware managed by other people, and keeping our data on their storage systems. Because of course no-one could ever compromise one of these suppliers of computing resources without us realising, quietly changing the cloud platform so it recorded interesting things about what we&amp;rsquo;re doing. And of course these, very large, computing infrastructures are not managed in turn from single points of control which now, by transitive closure, have control over the computing infrastructures of a huge number of organisations. Oh, wait.&lt;/p&gt;

&lt;p&gt;Well this, too, seems to have worked out reasonably well. So far. And this essay is not about the risks of cloud computing.&lt;/p&gt;

&lt;h3 id="some-more-than-others"&gt;Some more than others&lt;/h3&gt;

&lt;p&gt;There are things we can do to control the risks we all take. For instance, when dealing with software we haven&amp;rsquo;t written or checked in detail, we can carefully run it first in a controlled, isolated environment to try and assess any problems with it. This doesn&amp;rsquo;t &lt;em&gt;ensure&lt;/em&gt; safety &amp;mdash; nothing can do that &amp;mdash; but it does mean that we have at least some chance of finding out if the new software is broken or malignant.&lt;/p&gt;

&lt;p&gt;What we should not be doing is blindly accepting and deploying updates to software into an environment we care about. And we should very, very definitely not be doing that when that software has access to control our systems. If we were to do that, then, by the time we know that the people we&amp;rsquo;re getting the software from have been compromised, or were perhaps always malignant, it&amp;rsquo;s far too late: the damage is done. And, worse, we probably will never know what the damage that has been done is.&lt;/p&gt;

&lt;h3 id="a-target-painted-on-our-backs"&gt;A target painted on our backs&lt;/h3&gt;

&lt;p&gt;Points of control which are both far up the graph and well-known have targets painted on their backs. If Dr Evil, President Evil or General Secretary Evil decides that they&amp;rsquo;d like to compromise a large number of organisations, the things they are going to go for are the points of control which are far up the graph. And they&amp;rsquo;ll be willing to put a great deal of time, skill and money into this.&lt;/p&gt;

&lt;p&gt;Points of control which are far up the graph are, as a result, all but certain to be attacked, and all but certain to be attacked by people with effectively unbounded resources. The only safe assumption to make is that these points of control &lt;em&gt;will&lt;/em&gt; be compromised in due course: assuming otherwise is hopelessly naïve.&lt;/p&gt;

&lt;p&gt;So you should be very, very careful to test anything you get from such places &amp;mdash; especially software, which is far more mutable than hardware. And, if you are in charge of one of these places you should certainly not be suggesting that anyone blindly take your updates: that would be extremely irresponsible.&lt;/p&gt;

&lt;p&gt;And yet this is exactly what happens: we are all actively encouraged to blindly trust software we receive from organisations with targets painted on their backs.&lt;/p&gt;

&lt;p&gt;And that&amp;rsquo;s what this essay is about.&lt;/p&gt;

&lt;h2 id="insecurity-solutions"&gt;Insecurity solutions&lt;/h2&gt;

&lt;p&gt;There are many good choices here, but I’ll just pick one: Qualys.&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;The Qualys Cloud Platform and its powerful Cloud Agent provide organizations with a single IT, security and compliance solution &amp;mdash; from prevention to detection to response! &amp;mdash;&lt;a href="https://qualys.com/" title="Qualys"&gt;Qualys&lt;/a&gt;&lt;sup&gt;&lt;a href="#2021-09-27-computer-insecurity-footnote-6-definition" name="2021-09-27-computer-insecurity-footnote-6-return"&gt;6&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;That sounds good, right? Except, wait: they&amp;rsquo;re providing &lt;em&gt;security&lt;/em&gt; solutions. It&amp;rsquo;s in the nature of such solutions that they both need to be updated very frequently as new threats appear and require privileged access to systems. It almost certainly is not possible to do the kind of staged test and deploy I suggested above for software like this: if there&amp;rsquo;s a new compromise you want to know about it &lt;em&gt;now&lt;/em&gt;, not in two weeks. Instead you really need to just accept updates from Qualys as and when they appear or, perhaps worse, allow them to pull data from your systems to check &amp;lsquo;in the cloud&amp;rsquo; where you do not have control over the security of that data. That means that, if you are using Qualys tools on live systems, Qualys are a single point of control for you.&lt;/p&gt;

&lt;p&gt;Qualys&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;has over 10,300 customers in more than 130 countries, including a majority of the Forbes Global 100. &amp;mdash; &lt;a href="https://en.m.wikipedia.org/wiki/Qualys" title="Wikipedia: Qualys"&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;That means that they&amp;rsquo;re a single point of control for a large number of very high-value targets for President Evil: Qualys have a target painted on their back, are illuminated by bright searchlights and are surrounded by flashing neon arrows pointing at the target.&lt;/p&gt;

&lt;p&gt;So, well, they&amp;rsquo;ll know about this, won&amp;rsquo;t they? And although they can&amp;rsquo;t avoid being a target to some extent&lt;sup&gt;&lt;a href="#2021-09-27-computer-insecurity-footnote-7-definition" name="2021-09-27-computer-insecurity-footnote-7-return"&gt;7&lt;/a&gt;&lt;/sup&gt;, they certainly will be addressing these problems to reduce the risk somehow, won&amp;rsquo;t they? Certainly they will have many documents and guides describing how to minimise the inevitable risk associated with using their products.&lt;/p&gt;

&lt;p&gt;Not so much.&lt;/p&gt;

&lt;h3 id="how-to-lose-friends-and-alienate-people"&gt;How to lose friends and alienate people&lt;/h3&gt;

&lt;p&gt;Start from &lt;a href="https://www.qualys.com/documentation" title="Qualys documentation"&gt;&lt;code&gt;https://www.qualys.com/documentation&lt;/code&gt;&lt;/a&gt;, then &amp;lsquo;Cloud Platform&amp;rsquo; / &amp;lsquo;Scan authentication&amp;rsquo; / &amp;lsquo;Unix record&amp;rsquo; / &amp;lsquo;online help&amp;rsquo; / &amp;lsquo;What credentials should I use?&amp;rsquo; / &amp;lsquo;Learn more&amp;rsquo; and you should find a link entitled &amp;rsquo;*NIX Authenticated Scan Process and Commands&amp;rsquo; whose target is &lt;a href="https://success.qualys.com/discussions/s/article/000006220"&gt;&lt;code&gt;https://success.qualys.com/discussions/s/article/000006220&lt;/code&gt;&lt;/a&gt;&lt;sup&gt;&lt;a href="#2021-09-27-computer-insecurity-footnote-8-definition" name="2021-09-27-computer-insecurity-footnote-8-return"&gt;8&lt;/a&gt;&lt;/sup&gt;, from which&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;When Qualys performs an authenticated scan against a *nix system with a properly configured authentication record we will create an ssh session using the credentials in the authentication record, check the effective UID (level of access), execute &amp;ldquo;sudo su -&amp;rdquo; (or other root delegation command configured in the record), re-check effective UID to ensure the elevation worked, then begin our checks.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;sudo su -&lt;/code&gt; means ‘become &lt;code&gt;root&lt;/code&gt; and spawn a shell’. Or, in other words, gain completely unconstrained access to the system with the highest possible level of privilege. Further down the same page you&amp;rsquo;ll find this:&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;First, customers should be strongly discouraged from placing granular controls around the Qualys service account because of the reasons stated above. [&amp;hellip;] Even if it were possible to publish this list, it would likely take a lot of effort to maintain its currency.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;In other words: &amp;lsquo;don&amp;rsquo;t use fine-grained control to limit what our tool can do, because maintaining the list of commands it might run would be a lot of work for us.&amp;rsquo;&lt;/p&gt;

&lt;p&gt;Yet further down the page is:&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;Below is a list of commands that a Qualys service account might run during a scan. Remember not every command is run every time, and *nix distributions differ. This list of commands is neither comprehensive nor actively maintained.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;This is followed by a list of commands which includes &lt;code&gt;awk&lt;/code&gt;(equivalent to uncontrolled &lt;code&gt;root&lt;/code&gt; access), &lt;code&gt;firefox&lt;/code&gt; (WTF?), &lt;code&gt;java&lt;/code&gt; (&lt;code&gt;root&lt;/code&gt; access again) and just a huge number of other commands all of which imply unconstrained root access.&lt;/p&gt;

&lt;p&gt;That page also links to &lt;a href="https://success.qualys.com/discussions/s/article/000006228"&gt;&lt;code&gt;https://success.qualys.com/discussions/s/article/000006228&lt;/code&gt;&lt;/a&gt;&lt;sup&gt;&lt;a href="#2021-09-27-computer-insecurity-footnote-9-definition" name="2021-09-27-computer-insecurity-footnote-9-return"&gt;9&lt;/a&gt;&lt;/sup&gt;. Which contains this obvious falsehood:&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;In a nutshell, all of our data point detections are scripts that need to be run as root. Running them as a non-root user would, in most cases, result in permission errors which cannot be distinguished from other error sources. That would result in incorrect data being returned by the scanner, which is why we do not support this. There is no way to make non-root scanning work reliably with a scanning model based on shell commands or shell scripts.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;It also contains this lovely example of why &lt;code&gt;sudo&lt;/code&gt; is no good:&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;&lt;code&gt;sudo /usr/bin/find . -maxdepth 0 -name . -exec /bin/sh -c "su -" ";" -quit&lt;/code&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;This is truly magnificent: anyone who has looked after &lt;code&gt;sudo&lt;/code&gt; configuration will know, immediately that &lt;em&gt;this is why you don&amp;rsquo;t allow unconstrained &lt;code&gt;find&lt;/code&gt; in the commands you allow to be run&lt;/em&gt;. But apparently the people at Qualys don&amp;rsquo;t understand that.&lt;/p&gt;

&lt;h3 id="the-terrifying-conclusion"&gt;The terrifying conclusion&lt;/h3&gt;

&lt;p&gt;It is hard to read this material without coming to the conclusion that the people writing it &amp;mdash; the people on whom you are relying to check your systems for security &amp;mdash; do not care about the security of their customers’ systems if that security might cause momentary inconvenience for them. Worse, it is hard to read this material without coming to the conclusion that the people writing it do not &lt;em&gt;understand&lt;/em&gt; the security architecture of *nix systems&lt;sup&gt;&lt;a href="#2021-09-27-computer-insecurity-footnote-10-definition" name="2021-09-27-computer-insecurity-footnote-10-return"&gt;10&lt;/a&gt;&lt;/sup&gt; at all.&lt;/p&gt;

&lt;h3 id="but-they-have-no-choice"&gt;But they have no choice&lt;/h3&gt;

&lt;p&gt;Well, the people who wrote the documents excerpted above are certainly patronising, and they also seem alarmingly incompetent. But, surely, the problem is real: I can poke fun at them all I like but that doesn’t actually help anything, does it?&lt;/p&gt;

&lt;p&gt;This is a security scanner and this means that the things it is checking for change very fast: people who write malware do not give warning of what they are going to do in advance and do not make it easy to know when they are attacking you. When a new attack becomes known about it needs to be checked for &lt;em&gt;right away&lt;/em&gt;. And since the nature of the attack can’t be known in advance, the techniques needed to check for it can’t be known in advance, which means both that you will need to allow the scanner to run programs it has just fetched from Qualys, and also that those programs must be able to use all the facilities of the system, at the highest privilege level, to do there work. There’s just no way around this, is there?&lt;/p&gt;

&lt;p&gt;And, despite what might appear from reading the above material, we therefore have to assume that everyone at Qualys knows they an enormously attractive target for President Evil and that their security is thus impeccable: we have no choice.&lt;/p&gt;

&lt;h3 id="one-of-many"&gt;One of many&lt;/h3&gt;

&lt;p&gt;And Qualys are just one of many: I have picked on them only because I had to pick on someone. As another example, there’s a company &amp;mdash; a very famous company with a three-letter name &amp;mdash; who sell a product which, if you install it according to their recommendations, requires you to grant unconstrained &lt;code&gt;root&lt;/code&gt; access via &lt;code&gt;sudo&lt;/code&gt; to an entire directory containing a huge number of shell scripts some of which are tens of thousands of lines long, and some of which &lt;em&gt;write other shell scripts&lt;/em&gt;. The chances of that system not containing security problems are close to zero. But again, we have to trust them, even though the evidence that they don’t even understand what security means is overwhelming: after all they do have a three-letter name.&lt;/p&gt;

&lt;p&gt;And this is everywhere you look: we are trusting the security of our systems to people who do not appear to understand what security means.&lt;/p&gt;

&lt;h2 id="supply-chain"&gt;Supply chain&lt;/h2&gt;

&lt;p&gt;Isn’t this all just a bit alarmist? It’s all very well for me to go on about single points of control and companies with targets painted on their backs, but surely nothing bad ever really happens?&lt;/p&gt;

&lt;p&gt;If you think that, then you haven’t been paying attention.&lt;/p&gt;

&lt;h3 id="solarwinds"&gt;SolarWinds&lt;/h3&gt;

&lt;p&gt;SolarWinds are a company which write network-management tools used by many other companies, government organisations and others. One of their products is called Orion, which is used by &lt;a href="https://en.wikipedia.org/wiki/SolarWinds" title="SolarWinds (Wikipedia)"&gt;about 33,000 public and private-sector organisations&lt;/a&gt;. Most or all of those organisations download updates to the product either automatically or semi-automatically. This makes SolarWinds a very attractive target. Starting before October 2019 SolarWinds were compromised and in particular the build system for Orion was compromised in such a way that releases of the product contained malicious code. Between, perhaps, March and December 2020 the attackers used these compromised updates, together with other compromises to attack &lt;a href="https://en.wikipedia.org/wiki/2020_United_States_federal_government_data_breach" title="SolarWinds attack, Wikipedia"&gt;at least 200 organisations&lt;/a&gt;, including multiple parts of the US federal government, NATO, the UK government, the European parliament, Microsoft and many others. A good description of this attack can be found &lt;a href="https://www.lawfareblog.com/solarwinds-and-holiday-bear-campaign-case-study-classroom" title="SolarWinds and the Holiday Bear Campaign, Lawfare"&gt;here&lt;/a&gt;. The people who did the attack were the Russian Foreign Intelligence Service, Sluzbha Vneshney Razvedki&lt;sup&gt;&lt;a href="#2021-09-27-computer-insecurity-footnote-11-definition" name="2021-09-27-computer-insecurity-footnote-11-return"&gt;11&lt;/a&gt;&lt;/sup&gt;. I don’t know what the results of this attack were, and perhaps no-one outside Russia knows what was taken and what will be done with it. It is certainly very safe to say that the results were extremely severe, if not catastrophic.&lt;/p&gt;

&lt;p&gt;It’s worth noting that the result of the build system for Orion being compromised was that the compromised releases &lt;em&gt;were properly digitally signed&lt;/em&gt;: it is &lt;em&gt;not safe&lt;/em&gt; to rely on digital signatures to prove that software has not been compromised in the case where the organisation signing the software has been compromised.&lt;/p&gt;

&lt;h3 id="qualys-again"&gt;Qualys again&lt;/h3&gt;

&lt;p&gt;in early 2021 &lt;a href="https://www.theregister.com/2021/03/03/qualys_ransomware_clop_gang/" title="Qualys ransomware"&gt;there was a security breach at Qualys&lt;/a&gt;. It seems that this breach didn&amp;rsquo;t compromise their security tools: they got away with it, this time.&lt;/p&gt;

&lt;h3 id="this-is-not-the-end"&gt;This is not the end&lt;/h3&gt;

&lt;p&gt;These are both &lt;a href="https://en.wikipedia.org/wiki/Supply_chain_attack" title="Supply chain attack, Wikipedia"&gt;supply chain attacks&lt;/a&gt;: many others have happened, and without doubt many more will happen. In the context of this essay, supply chain attacks are a result of having single points of control for security management which are outside an organisation and which serve many organisations, making them interesting to attackers with large resources.&lt;/p&gt;

&lt;p&gt;But what can we do? It is inevitable that these organisations will be attacked, and almost inevitable that they will be compromised. In many cases we can mitigate the risk by having a fairly long test and deployment cycle and hoping that either we find the problems or that others do before we start relying on the tool. For security scanners we can’t do that, because we can’t afford to wait. We have to trust suppliers of security products, and we have to allow them to run privileged code on our systems which we can not check because the alternative of not checking for security compromises is even worse.&lt;/p&gt;

&lt;p&gt;We have to trust them because, in fact, we have no other choice.&lt;/p&gt;

&lt;h2 id="is-this-the-end"&gt;Is this the end?&lt;/h2&gt;

&lt;p&gt;So, this seems like an insoluble problem, doesn&amp;rsquo;t it? A security scanner has terrifying properties, by its nature:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;it must be updated very frequently, far too frequently to perform safety checks;&lt;/li&gt;
 &lt;li&gt;it must have privileged access to live systems.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;There&amp;rsquo;s just no way around that, is there? And of course, President Evil knows this too: the organisations providing these tools make &lt;em&gt;extremely&lt;/em&gt; good targets because the nature of the tools means both that any compromise is very serious and compromises are very hard to detect. And there is therefore no way around the fact that the suppliers of these tools will be targets for President Evil, will, in due course, be compromised, and all is therefore lost.&lt;/p&gt;

&lt;p&gt;Well, perhaps not. Perhaps it is possible to reduce the risk.&lt;/p&gt;

&lt;h3 id="a-sketch"&gt;A sketch&lt;/h3&gt;

&lt;p&gt;The problem to solve is that a security scanner must be updated very frequently and must run with high privilege. Suppliers of such tools, even if they are competent which is not always clear, are extremely valuable targets for attackers with very large resources and thus are almost certain to be compromised. So running these scanners on live systems needs to be avoided, even though the scanners need access to the live systems to run.&lt;/p&gt;

&lt;p&gt;Well, there’s a way around that. If you could make an identical copy of any system then you could scan the &lt;em&gt;copy&lt;/em&gt;. If the machine has a vulnerability, so will the copy. If the &lt;em&gt;scanner&lt;/em&gt; is compromised then it will attack only the copy, which doesn’t matter, since it’s only a copy, which will be destroyed immediately after being scanned.&lt;/p&gt;

&lt;p&gt;It is more complicated than that, of course: the copy needs actually to be running as lots of things will almost certainly only really show up when a system is running (what network ports does it have open, for instance). So the copy needs to be more than just a blob of data: it needs to be a real thing running programs. And the copy has to think it’s &lt;em&gt;not&lt;/em&gt; a copy: enough of the world around it needs to be faked up so it thinks it’s doing real work. But all of this world must be &lt;em&gt;fake&lt;/em&gt; &amp;mdash; under no circumstances should the copy be able to see real data or talk to real live systems. Finally, the scanner needs to be very restricted in the data it can upload: since the whole point is that we don’t trust the scanner we can’t allow it to ship all the data on the system to who-knows-where when it’s been compromised. Ideally the scanner should return a single bit: is the thing it is scanning compromised? If it is then this tells us to look more closely at it, for instance by looking at a report stashed locally on the copy.&lt;/p&gt;

&lt;p&gt;Doing this is not simple to arrange, but it is perfectly possible. Here are some objections with answers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But, cloning systems like this is hard, isn’t it?&lt;/strong&gt; Not really. For a start, if the systems concerned are virtualised then pretty much all serious hypervisors support making snapshots and clones of the virtual machines they’re running, and moving those snapshots and clones between different physical hardware. If the systems &lt;em&gt;aren’t&lt;/em&gt; virtualised then things are harder, but this kind of ‘make a carbon copy of a system’ is what you should already be doing for backup and disaster recovery (DR). Some people, apparently, maintain DR systems by &lt;em&gt;manually&lt;/em&gt; keeping them up to date with the live systems. If you are doing that, stop: create the DR systems by cloning the live systems. If you don’t have a good approach to cloning do it by restoring backups. If you can’t restore your backups (or you aren’t making backups) then you are already dead, so nothing matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But, this means doubling the size of the environment, doesn’t it?&lt;/strong&gt; No: you only need enough extra computational resources to scan each little chunk of your environment, since you can reuse them. But, you &lt;em&gt;already&lt;/em&gt; need enough extra resources to support DR: just use those!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But, this will be hard to set up, won’t it?&lt;/strong&gt; Yes, it will require a fair amount of work. But if you don’t do this, or something like it, then within the next few years your systems (almost certainly) &lt;em&gt;will&lt;/em&gt; be compromised and your data (almost certainly) &lt;em&gt;will&lt;/em&gt; leak to bad people as a result. So the question is: is the cost of that higher, or lower, than the cost of this, or something like it?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But, the things that do the cloning can be attacked, can’t they?&lt;/strong&gt; Yes, they can. But these tools are a tiny fragment of your infrastructure. They are, in fact, a single point of control, and one you have to be very, very careful about. This sketch doesn’t &lt;em&gt;remove&lt;/em&gt; the problem since nothing can do that: it just makes it much less severe and much better controlled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But, lots of details are missing, aren’t they?&lt;/strong&gt; Yes. This is a sketch, written by some person on the internet: it’s not a complete solution. (If you want a complete solution pay me lots of money and I&amp;rsquo;ll make you one.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But, you haven’t thought of this thing, and that thing, and &amp;hellip;, have you?&lt;/strong&gt; No. It’s a &lt;em&gt;sketch&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id="because-we-want-to"&gt;Because we want to&lt;/h2&gt;

&lt;p&gt;Solving these problems, in the sense of making them much less likely to happen and the consequences when they do happen much less bad, is not easy. But it is &lt;em&gt;possible&lt;/em&gt;, as the sketch in the previous section shows. &lt;em&gt;Not&lt;/em&gt; solving them means that, almost certainly, in the next few years a catastrophe will happen. I said at the beginning of the essay&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt; it is surprising that companies whose stated aims are to increase security are effectively working to make their customers&amp;rsquo; systems less secure.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;But it isn’t, not really: it is depressing, but not really surprising, because the entire history of computing has been made up of people avoiding solving problems through laziness, lack of imagination, or the desire to make a quick buck.&lt;/p&gt;

&lt;p&gt;I think that should stop. Solving these problems will be hard, but we can solve them if we only want to.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id="appendix-large-complex-computing-installations"&gt;Appendix: &amp;lsquo;large, complex computing installations&amp;rsquo;&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;ve used this term above without ever really defining it. Defining it is not entirely easy, and the meanings of definitions change over time: once an IBM System/360 Model 70 might have been thought of as a very large computing installation, but today it would be a very small one other than, perhaps, physically.&lt;/p&gt;

&lt;p&gt;Every time I want to write about large computing installations I find I don&amp;rsquo;t know the right words any more: is a large computing installation one with many systems, or is it one large system? What, anyway, is a &amp;lsquo;system&amp;rsquo;? Once everyone knew what it meant: the system was the departmental VAX, and later there were several systems which were the VAX (still creaking along on life-support) and a bunch of Suns, some of which were workstations and some of which were fileservers.&lt;/p&gt;

&lt;p&gt;But that meaning has dissolved away. For a while it was safe to talk about &amp;lsquo;servers&amp;rsquo;: everyone knew that a server was something that lived in a rack along with other servers&lt;sup&gt;&lt;a href="#2021-09-27-computer-insecurity-footnote-12-definition" name="2021-09-27-computer-insecurity-footnote-12-return"&gt;12&lt;/a&gt;&lt;/sup&gt;. But that in turn has dissolved away as the relationship between physical hardware and the programs that run on it becomes more complicated and often more remote.&lt;/p&gt;

&lt;p&gt;So what, today, are the right words? What is a large installation and what a small one? Here&amp;rsquo;s my attempt at a definition.&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;An installation is &lt;strong&gt;large&lt;/strong&gt; if it has a very large number of truly concurrent threads of control. &amp;lsquo;Truly concurrent&amp;rsquo; means &amp;lsquo;supported by hardware&amp;rsquo;, and what is meant by &amp;lsquo;very large&amp;rsquo; will increase over time: at the time of writing (mid 2021) this probably means at the very least tens of thousands.&lt;/li&gt;
 &lt;li&gt;An installation is &lt;strong&gt;complex&lt;/strong&gt; if it is performing a large number of conceptually distinct tasks. Again the definition of what is a large number may change over time although it will probably increase more slowly than the number of threads of control.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;This definition, for instance, would make many HPC systems large, but not complex: although they have large number of independent threads of control, they probably run a rather small number of different programs, and perhaps only one (probably several copies of that one, of course). It&amp;rsquo;s possible for a system to be complex, but not large, although unusual.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m not sure if this definition is adequate, but I think it will serve here.&lt;/p&gt;

&lt;p&gt;In the main text I use &amp;lsquo;installation&amp;rsquo; and &amp;lsquo;system&amp;rsquo; interchangeably: I should probably only use &amp;lsquo;installation&amp;rsquo; but I don&amp;rsquo;t. When I talk about an individual computer in a large installation I&amp;rsquo;ve tried to say &amp;lsquo;machine&amp;rsquo;.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2021-09-27-computer-insecurity-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;See appendix.&amp;nbsp;&lt;a href="#2021-09-27-computer-insecurity-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-09-27-computer-insecurity-footnote-2-definition" class="footnote-definition"&gt;
   &lt;p&gt;Once upon a time I worked for a then-famous company which sold holidays over the internet. We used to sneer at Amazon for picking a simple problem &amp;mdash; mostly selling books, then &amp;mdash; to solve: books just sit in a warehouse waiting to be bought, for decades if need be, while everyone wants a different holiday and holidays have very definite sell-by dates. One day I realised that what Amazon had done &amp;mdash; picking a simple, scalable problem to solve &amp;mdash; was &lt;em&gt;smart&lt;/em&gt;, and what we were trying to do was not smart and that was why they were going to get rich and we weren&amp;rsquo;t. I didn&amp;rsquo;t get rich, and I don&amp;rsquo;t know if that company even still exists.&amp;nbsp;&lt;a href="#2021-09-27-computer-insecurity-footnote-2-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-09-27-computer-insecurity-footnote-3-definition" class="footnote-definition"&gt;
   &lt;p&gt;A &lt;em&gt;graph&lt;/em&gt; here is not a &lt;em&gt;plot&lt;/em&gt;: it’s a drawing of some kind of network consisting of nodes (points of control, for instance) and arcs between those nodes which may or may not have arrows on them indicating direction: if a controls b then there will be a node for a, a node for b and an arrow from a to be indicating control.&amp;nbsp;&lt;a href="#2021-09-27-computer-insecurity-footnote-3-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-09-27-computer-insecurity-footnote-4-definition" class="footnote-definition"&gt;
   &lt;p&gt;By &amp;lsquo;up&amp;rsquo; I mean in the direction of &amp;lsquo;is controlled by&amp;rsquo; while &amp;lsquo;down&amp;rsquo; means in the direction of &amp;lsquo;has control over&amp;rsquo;.&amp;nbsp;&lt;a href="#2021-09-27-computer-insecurity-footnote-4-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-09-27-computer-insecurity-footnote-5-definition" class="footnote-definition"&gt;
   &lt;p&gt;Of course &lt;a href="http://www.lel.ed.ac.uk/~gpullum/loopsnoop.html" title="Scooping the loop snooper"&gt;we &lt;em&gt;can’t&lt;/em&gt; exhaustively check software&lt;/a&gt; in any case, but we can do a lot better than ‘not checking it at all’.&amp;nbsp;&lt;a href="#2021-09-27-computer-insecurity-footnote-5-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-09-27-computer-insecurity-footnote-6-definition" class="footnote-definition"&gt;
   &lt;p&gt;All the text in this essay was extracted from the linked sources in early September, 2021. Things may have changed since then, but the what is here was there then. I have marked elisions with &amp;rsquo;[&amp;hellip;]&amp;rsquo;.&amp;nbsp;&lt;a href="#2021-09-27-computer-insecurity-footnote-6-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-09-27-computer-insecurity-footnote-7-definition" class="footnote-definition"&gt;
   &lt;p&gt;For instance, if Qualys can be compromised in such a way that their tools fail to report other compromises, then this would allow those other compromises to propagate undetected, even if the tools provided by Qualys are not themselves doing direct harm.&amp;nbsp;&lt;a href="#2021-09-27-computer-insecurity-footnote-7-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-09-27-computer-insecurity-footnote-8-definition" class="footnote-definition"&gt;
   &lt;p&gt;This may formerly have been &lt;code&gt;https://qualys-secure.force.com/discussions/s/article/000006220&lt;/code&gt;.&amp;nbsp;&lt;a href="#2021-09-27-computer-insecurity-footnote-8-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-09-27-computer-insecurity-footnote-9-definition" class="footnote-definition"&gt;
   &lt;p&gt;May formerly have been &lt;a href="https://qualys-secure.force.com/discussions/s/article/000006228"&gt;&lt;code&gt;https://qualys-secure.force.com/discussions/s/article/000006228&lt;/code&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="#2021-09-27-computer-insecurity-footnote-9-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-09-27-computer-insecurity-footnote-10-definition" class="footnote-definition"&gt;
   &lt;p&gt;To be fair, ‘the security architecture of *nix systems’ does give the impression that there is one &amp;mdash; that it is something made of marble and stainless steel rather than partly-dissolved mud bricks and rotting straw.&amp;nbsp;&lt;a href="#2021-09-27-computer-insecurity-footnote-10-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-09-27-computer-insecurity-footnote-11-definition" class="footnote-definition"&gt;
   &lt;p&gt;In other words, this time it was indeed President Evil.&amp;nbsp;&lt;a href="#2021-09-27-computer-insecurity-footnote-11-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-09-27-computer-insecurity-footnote-12-definition" class="footnote-definition"&gt;
   &lt;p&gt;Some very large or very old servers might have been whole racks, or even several.&amp;nbsp;&lt;a href="#2021-09-27-computer-insecurity-footnote-12-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Useful idiots</title>
   <link>https://www.tfeb.org/fragments/2021/04/09/useful-idiots/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2021-04-09-useful-idiots</guid>
   <pubDate>Fri, 09 Apr 2021 13:24:38 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;The authors of the Signal messaging system are acting as useful idiots for state security and police services: while they are almost certainly not working for them or funded by them, what they are doing is extremely convenient for them.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;There is a &lt;a href="https://yasha.substack.com/p/signal-is-a-government-op-85e"&gt;conspiracy theory&lt;/a&gt; that &lt;a href="https://signal.org/"&gt;Signal&lt;/a&gt; is in fact created by some state security service: this is pretty obviously silly. Instead, I think that the people who create and endorse Signal are acting as &lt;em&gt;useful idiots&lt;/em&gt; for various state security and police services.&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;useful idiot&lt;/strong&gt;, noun
  &lt;br /&gt;a naive or credulous person who can be manipulated or exploited to advance a cause or political agenda&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2 id="the-art-of-the-possible"&gt;The art of the possible&lt;/h2&gt;

&lt;p&gt;The people who work for state security and police services, unlike their political masters, understand cryptography. And in particular they understand that the mathematics of cryptography makes it effectively impossible to stop people from using cryptographic communication systems which can not usefully be broken. The only ways this could be prevented would be either to forbid people access to general-purpose computers, which is not practical, or to ensure that all such computers are compromised at a low level which is also not practical&lt;sup&gt;&lt;a href="#2021-04-09-useful-idiots-footnote-1-definition" name="2021-04-09-useful-idiots-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;In other words they understand that people will be able to communicate with each other in such a way that this communication can not be overheard in bulk, and that there is nothing they can do about that.&lt;/p&gt;

&lt;p&gt;What they &lt;em&gt;can&lt;/em&gt; do is to compromise &lt;em&gt;individual&lt;/em&gt; communication links: once they&amp;rsquo;ve worked out that, for instance, two people who are of great interest to them are talking to each other they can work to compromise the systems that these people are using to communicate &amp;mdash; installing things like key-loggers, rootkits or both, which will sniff the communications before they are encrypted. Doing this is a lot of work and probably requires a significant amount of traditional tradecraft: by far the easiest way to do it will be by gaining physical access to the devices they want to compromise and doing so without arousing suspicion, for instance.&lt;/p&gt;

&lt;p&gt;Their difficulty, then, is filtering the people that they want to overhear sufficiently badly from the huge mass of people that they don&amp;rsquo;t care about. This is where Signal comes in.&lt;/p&gt;

&lt;h2 id="useful-idiots"&gt;Useful idiots&lt;/h2&gt;

&lt;p&gt;Signal is a tool which allows encrypted communication between individuals and groups. There is no reason to believe that this communication can be broken.&lt;/p&gt;

&lt;p&gt;But Signal has been &lt;a href="https://www.tfeb.org/fragments/2021/01/16/what-s-wrong-with-signal-s-contact-discovery/" title="What's wrong with Signal's contact discovery"&gt;designed in such a way that it is inherently unsafe&lt;/a&gt;: it uses phone numbers for identifiers and its contact discovery works in such a way that anyone who knows &lt;em&gt;your&lt;/em&gt; phone number can know if you are a Signal user, whether or not you know &lt;em&gt;their&lt;/em&gt; phone number. This approach means that if you have Signal installed then you will get a notification whenever anyone who is in your phonebook installs Signal, &lt;em&gt;whether or not you are in their phonebook&lt;/em&gt;. This was done intentionally, and presumably as an attempt to drive growth in users with the eventual aim of making money from the large userbase.&lt;/p&gt;

&lt;p&gt;This makes Signal a seriously bad choice for, for instance, people who are suffering abuse or being stalked. The moment you install Signal in order to talk to someone who might help you, the person you are being abused by or who is stalking you can know this, and you won&amp;rsquo;t know that they know.&lt;/p&gt;

&lt;p&gt;On the other hand this is very convenient for state security and police services. They don&amp;rsquo;t care about the cryptographic security because they know that people can use tools which they can&amp;rsquo;t attack. But finding someone&amp;rsquo;s phone number (all someone&amp;rsquo;s phone numbers) is a pretty easy thing to do if you&amp;rsquo;re a state security or police service, and Signal&amp;rsquo;s contact discovery then means that they can silently trawl through people they might be interested in and work out who has Signal installed.&lt;/p&gt;

&lt;p&gt;What this means is that, assuming Signal tends to be used by people who really do have something to hide&lt;sup&gt;&lt;a href="#2021-04-09-useful-idiots-footnote-2-definition" name="2021-04-09-useful-idiots-footnote-2-return"&gt;2&lt;/a&gt;&lt;/sup&gt; it works as a filter which allows state security and police services to identify people who are likely to be of interest to them from larger lists of people.&lt;/p&gt;

&lt;h2 id="the-coronation-of-the-idiots"&gt;The coronation of the idiots&lt;/h2&gt;

&lt;p&gt;Until recently it has been rather unclear how Signal&amp;rsquo;s authors intend to use the product to attempt to make themselves very rich. Well, they&amp;rsquo;ve just answered that question: they are going to &lt;a href="https://signal.org/blog/help-us-test-payments-in-signal/" title="glue a cryptocurrency into it"&gt;glue a cryptocurrency into it&lt;/a&gt;, so it will be possible to make anonymous payments to and from Signal. Conveniently &lt;a href="https://www.stephendiehl.com/blog/signal.html" title="Moxie Marlinspike / MobileCoin"&gt;Signal&amp;rsquo;s authors have an ownership stake in the cryptocurrency involved&lt;/a&gt;: something which should not be very surprising&lt;sup&gt;&lt;a href="#2021-04-09-useful-idiots-footnote-3-definition" name="2021-04-09-useful-idiots-footnote-3-return"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;So Signal&amp;rsquo;s authors have now revealed their proposed solution to their underpants gnome problem: they intend to make money from Signal by making money from the transactions people make using it. &lt;a href="https://www.schneier.com/blog/archives/2021/04/wtf-signal-adds-cryptocurrency-support.html" title="Bruce Schneier, another useful idiot"&gt;Lots of people&lt;/a&gt; have been saying that this is a bad idea: why entangle a messaging system with a payment system? Well, they&amp;rsquo;re just not thinking very hard about this because the answer is terribly simple: they are being entangled so Signal&amp;rsquo;s authors can make money.&lt;/p&gt;

&lt;p&gt;So, what kind of person would be particularly interested in a tool which allows encrypted communication (with disappearing messages, even), and allows anonymous, secure payments? People who deal in illegal goods would be. If you&amp;rsquo;re dealing in illegal drugs, or illegal pornography, or anything similar, Signal will soon look like a tool designed especially for you.&lt;/p&gt;

&lt;p&gt;But, really, it turns out to have been designed for someone else. If you are a state security or police service, soon you will be able to look at a list of people who you suspect may be dealing in illegal goods, use Signal&amp;rsquo;s contact discovery to find the people who have it installed, and now you have a shorter list of people who are much more likely to be of interest to you.&lt;/p&gt;

&lt;p&gt;Signal is the tool that state security or police services would have built, but they didn&amp;rsquo;t have to do so: some useful idiots built it for them.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2021-04-09-useful-idiots-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;It is, inevitably, the subject of other conspiracy theories.&amp;nbsp;&lt;a href="#2021-04-09-useful-idiots-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-04-09-useful-idiots-footnote-2-definition" class="footnote-definition"&gt;
   &lt;p&gt;Rather than the sort of people who wear &amp;lsquo;tactical&amp;rsquo; watches so they can pretend they are in the special forces.&amp;nbsp;&lt;a href="#2021-04-09-useful-idiots-footnote-2-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-04-09-useful-idiots-footnote-3-definition" class="footnote-definition"&gt;
   &lt;p&gt;It does at least appear that &lt;a href="https://www.mobilecoin.com/" title="MobileCoin"&gt;MobileCoin&lt;/a&gt;, the cryptocurrency Signal will use, does not use Bitcoin&amp;rsquo;s &amp;lsquo;proof of work&amp;rsquo; approach which is currently causing significant carbon emissions.&amp;nbsp;&lt;a href="#2021-04-09-useful-idiots-footnote-3-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>How the backtrace was conquered</title>
   <link>https://www.tfeb.org/fragments/2021/03/26/how-the-backtrace-was-conquered/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2021-03-26-how-the-backtrace-was-conquered</guid>
   <pubDate>Fri, 26 Mar 2021 11:37:22 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;&lt;strong&gt;Once upon a time&lt;/strong&gt;, when the world was younger, a young and rather foolish physics student used to debug his FORTRAN programs using printed backtraces.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;And I do mean printed backtraces: when the machine crashed the chain printer attached to it would vomit out many sheets of paper which had procedure names and line numbers on them. And, after restarting the machine so the next user could make it crash in their turn he would take this printout and take his printout of his program and compare the line numbers: looking at the code, trying to work out what had gone wrong and marking corrections in pencil. He spent many hours late at night in this way.&lt;/p&gt;

&lt;p&gt;Later on, this same student (now a maths student) discovered a wonderful thing: a programming language called Lisp in which you could write programs to solve complex algebra problems which were of interest in his field. And although, in theory, if you had the kind of computer which maths departments could not afford, Lisp was an &lt;em&gt;interactive&lt;/em&gt; language, this was not true in practice if all you had was the kind of computer that was all a maths department could afford. So things went on much as before: he would make some changes to his program, set up the equations it was going to try to solve, and then, late at night when there were no other users to inconvenience, set it off running. In the morning there might occasionally be a solution, and even more occasionally a solution which was useful. But more often there would be only the corpse of the program in the form of an elaborate backtrace after it had been mortally wounded by some fierce bug (error handling was a thing not yet thought of, at leasy by the student). This time, though, the backtrace would be in a log file from the run.&lt;/p&gt;

&lt;p&gt;And the student made another discovery: there was a certain text editing environment used by some far-off people who had access to much bigger and better computers, and this editing environment purported to support Lisp programming rather well: certainly better than the rudimentary editor he used then. And he managed to get a copy of this environment (legend has it it was version 17.64) on a tape from someone, and he managed to make it run, just, on the maths department&amp;rsquo;s machine. And he taught it enough about the Lisp dialect he was using that it was indeed helpful, if often annoying to other users as it took rather a lot of the capacity of the machine to support it. And everything was a little better.&lt;/p&gt;

&lt;p&gt;And this text editing system came with a rather wonderful tool: a program whose name may have been &amp;lsquo;tags&amp;rsquo; which would, for the languages it understood, make a file which mapped between definition names and their locations in the filesystem. And he modified this tags program to understand the dialect of Lisp he was using as well. Very wonderfully, the system would also cope with the case where the definition had moved, which it almost always had, and which made things like line and column numbers so brittle and useless (source control might have been invented by then, but the student knew nothing of that). This, of course, was the one of the primitive ancestors of the automatic systems which will find definitions of symbols that any reputable editor, and even some that are perhaps a little less than reputable, now has.&lt;/p&gt;

&lt;p&gt;And now, when he came in in the morning to find a new backtrace from the previous night&amp;rsquo;s run, he would edit this backtrace in the editing system and find interesting lines in it, at which he would type the very wonderful &amp;lsquo;meta-dot&amp;rsquo; or, as he knew it (not being blessed with a keyboard with a meta key), &amp;lsquo;escape dot&amp;rsquo; command. And the disk light would come on for a little, and then he would be looking at the definition he was interested in.&lt;/p&gt;

&lt;p&gt;Thus was the backtrace conquered. And from that day to this it has never dared raise its head again in polite company, but instead lurks, unheeded except by the few who now remember it, in the darker corners of the system. As for the student, well, no-one now remembers him at all.&lt;/p&gt;</description></item>
  <item>
   <title>What's wrong with Signal's contact discovery</title>
   <link>https://www.tfeb.org/fragments/2021/01/16/what-s-wrong-with-signal-s-contact-discovery/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2021-01-16-what-s-wrong-with-signal-s-contact-discovery</guid>
   <pubDate>Sat, 16 Jan 2021 11:35:36 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;After WhatsApp&amp;rsquo;s threatened change to their terms of service, which may allow them to leak information to Facebook, many people are moving to Signal, a tool which purports to be more secure. If you want security which is not at least partly theatrical you should not use Signal.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;h2 id="whatsapp"&gt;WhatsApp&lt;/h2&gt;

&lt;p&gt;On or about the 6th of January 2021, &lt;a href="https://www.bbc.co.uk/news/technology-55573149" title="terms of service"&gt;WhatsApp users were required to agree to new terms of service&lt;/a&gt; or to stop using the service by the 8th of February. These terms of service were at best confusing, but given that WhatsApp is owned by Facebook, a company whose entire business model is selling its users&amp;rsquo; souls to its customers and which has been heavily implicated in that other thing that happened on the 6th of January 2021, the conclusion was not likely to be good.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m glad to say this seems to have been a disaster for WhatsApp: so many users changed to &lt;a href="https://signal.org/" title="Signal"&gt;Signal&lt;/a&gt; &amp;mdash; an app which sells itself as being more secure &amp;mdash; that it &lt;a href="https://www.bbc.co.uk/news/technology-55684595" title="Signal falls over"&gt;fell&lt;/a&gt; &lt;a href="https://www.theregister.com/2021/01/15/signal_app_down/" title="Signal falls over"&gt;over&lt;/a&gt; under the load for a while on the 15th of January. People are apparently &lt;a href="https://www.bbc.co.uk/news/technology-55634139" title="flocking to rival platforms"&gt;leaving WhatsApp in droves&lt;/a&gt;, and moving to Signal and other platforms.&lt;/p&gt;

&lt;p&gt;WhatsApp / Facebook were so alarmed by this that they&amp;rsquo;ve both issued a number of &lt;a href="https://www.theverge.com/2021/1/12/22226792/whatsapp-privacy-policy-response-signal-telegram-controversy-clarification" title="clarifications"&gt;clarifications&lt;/a&gt;, &lt;a href="https://www.bbc.co.uk/news/technology-55683745" title="delayed the implementation date"&gt;delayed the implementation date until the 15th of May&lt;/a&gt; &amp;mdash; probably in the hope that people will have forgotten by then &amp;mdash; and made clear that the changes &lt;a href="https://twitter.com/markscott82/status/1346817693375229952" title="not in Europe"&gt;do not apply in Europe&lt;/a&gt;, where there are reasonable privacy laws, and not even, yet, in the UK which has not yet completed its transition to Boris Johnson&amp;rsquo;s hereditary feudal fiefdom.&lt;/p&gt;

&lt;p&gt;So that&amp;rsquo;s, perhaps, good, right? Lots of people were driven to Signal which is ever so much more secure and written and run by very nice people who understand and care about security.&lt;/p&gt;

&lt;h2 id="signal"&gt;Signal&lt;/h2&gt;

&lt;p&gt;Well, the people who wrote Signal and run its infrastructure care about their users&amp;rsquo; security only as far as it suits them. Yes, they make &lt;a href="https://signal.org/#signal" title="a great deal of noise"&gt;a great deal of noise&lt;/a&gt; about how secure and safe it is: their website is covered in quotes from people like Edward Snowden and Bruce Schneier and generally makes a very big deal about the security of the platform. If you don&amp;rsquo;t read what they write quite carefully you could be forgiven for thinking that Signal was completely safe, and completely private.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s not. And it&amp;rsquo;s not safe &lt;em&gt;by design&lt;/em&gt;: the Signal people know it is not safe, &lt;em&gt;and they don&amp;rsquo;t care&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id="signals-contact-discovery"&gt;Signal&amp;rsquo;s contact discovery&lt;/h2&gt;

&lt;p&gt;Here is a sketch of how contact discovery works in Signal. If you are a Signal user you have some identity on the system, and that identity is derived from your phone number. In particular, if you know the phone number you can work out the identity&lt;sup&gt;&lt;a href="#2021-01-16-what-s-wrong-with-signal-s-contact-discovery-footnote-1-definition" name="2021-01-16-what-s-wrong-with-signal-s-contact-discovery-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;. If you allow Signal access to your contacts (which it will ask you for), then every once in a while it will work out something equivalent to identities corresponding to your contacts, upload them, ephemerally, to Signal&amp;rsquo;s infrastructure, and compute the intersection. Once it&amp;rsquo;s done that, you know which of your contacts have Signal.&lt;/p&gt;

&lt;p&gt;There are several obvious problems with this approach. The most obvious of these is that if any of the data on your contacts leaks, even in encrypted form &amp;mdash; if someone attacks Signal&amp;rsquo;s infrastructure, or if Signal themselves are not trustworthy, say &amp;mdash; then it is, obviously, a bad thing. And Signal have gone to heroic lengths to protect against this. Here is their initial outline of what it does (the following text comes from the link below):&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;Private contact discovery using SGX is fairly simple at a high level:&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;Run a contact discovery service in a secure SGX enclave.&lt;/li&gt;
  &lt;li&gt;Clients that wish to perform contact discovery negotiate a secure connection over the network all the way through the remote OS to the enclave.&lt;/li&gt;
  &lt;li&gt;Clients perform remote attestation to ensure that the code which is running in the enclave is the same as the expected published open source code.&lt;/li&gt;
  &lt;li&gt;Clients transmit the encrypted identifiers from their address book to the enclave.&lt;/li&gt;
  &lt;li&gt;The enclave looks up a client’s contacts in the set of all registered users and encrypts the results back to the client.&lt;/li&gt;&lt;/ol&gt;&lt;/blockquote&gt;

&lt;p&gt;There is &lt;a href="https://signal.org/blog/private-contact-discovery/" title="Signal's private contact discovery"&gt;much more description&lt;/a&gt; of this. And it&amp;rsquo;s all fine: it really does go to very great lengths to make it very hard for Signal themselves or any other malicious actor who might be able to compromise their systems to gain access to your contacts, and still less to your messages. And that&amp;rsquo;s all very wonderful.&lt;/p&gt;

&lt;p&gt;Now you&amp;rsquo;re probably expecting me to spout some conspiracy theory about how the SGX enclaves themselves have been compromised at the hardware level by some state-level entity, possibly with a three-letter name, so everything is worthless. Well, there have been rumours that that sort of thing has happened, certainly. But, well, they probably haven&amp;rsquo;t happened: the conspiracy theories probably are just conspiracy theories as they usually are. Even if they have happened, defending against state-level entities, with or without three-letter names, is generally futile: if these people are interested enough in what&amp;rsquo;s on your phone they probably will find out, either by fancy technology or by more traditional techniques, possibly involving a rubber hose.&lt;/p&gt;

&lt;p&gt;No, that&amp;rsquo;s not the problem. The problem is laughably simpler than that.&lt;/p&gt;

&lt;h2 id="alice-and-elizabeth"&gt;Alice and Elizabeth&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s imagine two people: Alice and Elizabeth, her partner. Alice is physically violent towards Elizabeth who lives in serious fear of her, is regularly being beaten by her and is terrified that worse things will happen soon. Elizabeth desperately wants and needs to escape from the relationship before something really bad happens, but she doesn&amp;rsquo;t know how: she needs to talk to someone privately. Alice, needless to say, doesn&amp;rsquo;t want this to happen.&lt;/p&gt;

&lt;p&gt;Elizabeth realises that she can install Signal on her phone and then use it to communicate, privately, with people who might be able to help her &amp;mdash; the police, perhaps. She does so.&lt;/p&gt;

&lt;p&gt;Unbeknownst to her Alice already has Signal, perhaps on a phone the number of which Elizabeth does not know. Signal&amp;rsquo;s contact discovery promptly tells Alice that Elizabeth has installed Signal, and since she&amp;rsquo;s running it on a phone which doesn&amp;rsquo;t appear in Elizabeth&amp;rsquo;s contacts, Elizabeth doesn&amp;rsquo;t know this. And this story ends with Alice beating Elizabeth to death.&lt;/p&gt;

&lt;h2 id="vladimir-and-the-dissidents"&gt;Vladimir and the dissidents&lt;/h2&gt;

&lt;p&gt;Or let&amp;rsquo;s imagine Vladimir. Vladimir runs a country which was once, briefly, a democracy but now, once more and inevitably, is a kleptocracy and a police state. Many, many people in Vladimir&amp;rsquo;s country don&amp;rsquo;t like him: his problem is knowing which ones to have dealt with. Well this is easy. Vladimir extracts from the telephone companies the phone numbers of the people he&amp;rsquo;s interested in &amp;mdash; either with bribes or with pliers, it does not matter which. He then buys a burner phone, puts all these numbers in its contact list, and installs Signal. Now he knows which of his enemies have Signal, but since his burner phone is most certainly not in their contact lists they have no idea that he knows they have it and thus cannot run. Doors are knocked on at 3 in the morning, people vanish, their assets are acquired by Vladimir who uses them to build another vast, tasteless palace.&lt;/p&gt;

&lt;h2 id="unsafe-at-any-speed"&gt;Unsafe at any speed&lt;/h2&gt;

&lt;p&gt;What Signal have done is to produce a beautifully secure implementation of a contact discovery algorithm which is &lt;em&gt;designed to be unsafe&lt;/em&gt;, because it allows anyone who knows your phone number to know whether you have Signal, and if you don&amp;rsquo;t know &lt;em&gt;their&lt;/em&gt; phone number &amp;mdash; if they are, for instance, stalking you &amp;mdash; it will not, and &lt;em&gt;can not&lt;/em&gt;, tell you that they know this. The contact discovery algorithm is &lt;em&gt;designed&lt;/em&gt; to leak information.&lt;/p&gt;

&lt;p&gt;And they know this, and they don&amp;rsquo;t care. I&amp;rsquo;ll repeat that: they know that their product enables stalking, and they do not care about that.I don&amp;rsquo;t know why they made these choices, but I don&amp;rsquo;t expect the reasons are very good ones.&lt;/p&gt;

&lt;h2 id="some-ideas-which-are-mostly-useless"&gt;Some ideas which are mostly useless&lt;/h2&gt;

&lt;p&gt;It&amp;rsquo;s tempting to say that, well, the contact discovery algorithm should be &lt;em&gt;mutual&lt;/em&gt;: it should only tell me that you have Signal if both you are in my contacts list and I am in yours. That can&amp;rsquo;t work, because the only way to do this would be to allow my contact list (in encrypted form) to persist, indefinitely, on Signal&amp;rsquo;s infrastructure, which would leave it open to attack.&lt;/p&gt;

&lt;p&gt;Another approach would be to have a bit you could set on your identity which says &amp;lsquo;this identity should not partake in contact discovery&amp;rsquo;: if it was set then Signal would not allow either it to be discoverable or it to discover others, with the second restriction existing to prevent people deliberately setting it so they could stalk other people while not themselves being discoverable. This is closer to working: it protects against users of the service, but it does not protect against people who can acquire its data: they can simply strip the privacy bits from the identities they&amp;rsquo;ve captured and run contact discovery on their own copy of the infrastructure.&lt;/p&gt;

&lt;p&gt;Strangely, something which should make Signal&amp;rsquo;s stalking problem less serious is Facebook&amp;rsquo;s catastrophic misjudgement over WhatsApp&amp;rsquo;s privacy policy: large numbers of users have migrated from WhatsApp to Signal or, at least, have &lt;em&gt;installed&lt;/em&gt; Signal and thus now have identifiers in the system. Stalking someone by discovering they have Signal installed now tells you a lot less about them than it did previously. Of course Elizabeth has Signal, and Vladimir may discover that both his real and potential enemies also have it&lt;sup&gt;&lt;a href="#2021-01-16-what-s-wrong-with-signal-s-contact-discovery-footnote-2-definition" name="2021-01-16-what-s-wrong-with-signal-s-contact-discovery-footnote-2-return"&gt;2&lt;/a&gt;&lt;/sup&gt;. This makes things, at least, less bad, although it does not make them good.&lt;/p&gt;

&lt;h2 id="one-idea-which-is-not-useless"&gt;One idea which is not useless&lt;/h2&gt;

&lt;p&gt;The underlying problem is that Signal uses phone numbers as identifiers, where phone numbers are essentially public information. This enables stalking and worse.&lt;/p&gt;

&lt;p&gt;Well, instead, the system could use completely randomly created identifiers which were not tied in any way to phone numbers. This would make the users of the system completely anonymous: the only way you could discover someone&amp;rsquo;s identifier is if they gave it to you. For added value it might be made, optionally and not by default, possible to attach things like phone numbers and email addresses to the random identifiers, whereupon they &lt;em&gt;would&lt;/em&gt; be discoverable, by an algorithm essentially identical to Signal&amp;rsquo;s. Using such a system you could choose either to be completely undiscoverable or, and only if you wanted to be, to be more-or-less discoverable.&lt;/p&gt;

&lt;p&gt;That would be easy, wouldn&amp;rsquo;t it? The Signal people, who are clearly ever so smart, must have thought of that, and decided not to do it: I wonder why?&lt;/p&gt;

&lt;p&gt;Well, of course, other people &amp;mdash; people who &lt;em&gt;actually&lt;/em&gt; care about the safety of these sorts of systems &amp;mdash; have not only thought about doing it this way, they &lt;em&gt;have&lt;/em&gt; done it this way. &lt;a href="https://threema.ch/" title="Threema"&gt;Threema&lt;/a&gt; is one such app&lt;sup&gt;&lt;a href="#2021-01-16-what-s-wrong-with-signal-s-contact-discovery-footnote-3-definition" name="2021-01-16-what-s-wrong-with-signal-s-contact-discovery-footnote-3-return"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h2 id="the-theatre-of-the-absurd"&gt;The theatre of the absurd&lt;/h2&gt;

&lt;p&gt;Signal&amp;rsquo;s authors make a lot of noise about how secure it is. But they know it is, by design, not safe. If you care about safety you should use tools which really are safe rather than tools whose authors treat safety as a matter of theatre.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2021-01-16-what-s-wrong-with-signal-s-contact-discovery-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;Whether you can go the other way is not clear: ideally the answer would be &amp;lsquo;no&amp;rsquo; but the space of phone numbers is so small that it&amp;rsquo;s not completely implausible to simply search by brute-force to find out which identities correspond to which numbers if you have the computational resources to do so. However this does not matter here.&amp;nbsp;&lt;a href="#2021-01-16-what-s-wrong-with-signal-s-contact-discovery-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-01-16-what-s-wrong-with-signal-s-contact-discovery-footnote-2-definition" class="footnote-definition"&gt;
   &lt;p&gt;Vladimir is not the sort of person who has friends.&amp;nbsp;&lt;a href="#2021-01-16-what-s-wrong-with-signal-s-contact-discovery-footnote-2-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2021-01-16-what-s-wrong-with-signal-s-contact-discovery-footnote-3-definition" class="footnote-definition"&gt;
   &lt;p&gt;This article is not an advertisement for Threema: it just happens to be a system I know of which does this. I do not personally use it although it does appear to be very competently designed and implemnted by people who really do care about safety rather than are merely pretending to do so. I am sure there are other similar systems.&amp;nbsp;&lt;a href="#2021-01-16-what-s-wrong-with-signal-s-contact-discovery-footnote-3-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Generic interfaces in Racket</title>
   <link>https://www.tfeb.org/fragments/2021/01/08/generic-interfaces-in-racket/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2021-01-08-generic-interfaces-in-racket</guid>
   <pubDate>Fri, 08 Jan 2021 18:25:59 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Or: things you do to distract yourself from watching an attempted fascist coup.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;A thing that exists in many languages with a notion of a sequence of objects is a function variously known as &lt;code&gt;fold&lt;/code&gt; or &lt;code&gt;reduce&lt;/code&gt;: this takes another function of two arguments, some initial value, and walks along the sequence successively reducing it using the function. So, for instance:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;&lt;code&gt;(fold + 0 '(1 2 3))&lt;/code&gt; turns into &lt;code&gt;(fold + (+ 0 1) '(2 3))&lt;/code&gt; which turns into &amp;hellip;&lt;/li&gt;
 &lt;li&gt;&lt;code&gt;(fold + 1 '(2 3))&lt;/code&gt; turns into &lt;code&gt;(fold + (+ 1 2) '(3))&lt;/code&gt; which turns into &amp;hellip;&lt;/li&gt;
 &lt;li&gt;&lt;code&gt;(fold + 3 '(3))&lt;/code&gt; turns into &lt;code&gt;(fold + (+ 3 3) '())&lt;/code&gt; which turns into &amp;hellip;&lt;/li&gt;
 &lt;li&gt;&lt;code&gt;6&lt;/code&gt;.&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;It&amp;rsquo;s pretty easy to write a version of &lt;code&gt;fold&lt;/code&gt; for lists:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define (fold op initial l)
  (if (null? l)
      initial
      (fold op (op initial (first l)) (rest l))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Racket calls this (or a more careful version of this) &lt;code&gt;foldl&lt;/code&gt;: there is also &lt;code&gt;foldr&lt;/code&gt; which works from the other end of the list and is more expensive as a result.&lt;/p&gt;

&lt;p&gt;Well, one thing you might want to do is have a version of &lt;code&gt;fold&lt;/code&gt; which works on &lt;em&gt;trees&lt;/em&gt; rather than just lists. One definition of a tree is:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;it&amp;rsquo;s a collection of nodes;&lt;/li&gt;
 &lt;li&gt;nodes have values;&lt;/li&gt;
 &lt;li&gt;nodes have zero or more unique children, which are nodes.&lt;/li&gt;
 &lt;li&gt;no node is the descendant of more than one node;&lt;/li&gt;
 &lt;li&gt;there is exactly one root node which is the descendant of no other nodes.&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;A variant of this (which will matter below) is that the children of a node are either nodes or any other object, and there is some way of knowing if something is a node or not&lt;sup&gt;&lt;a href="#2021-01-08-generic-interfaces-in-racket-footnote-1-definition" name="2021-01-08-generic-interfaces-in-racket-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;You can obviously represent trees as conses, with the value of a cons being its car, and the children being its cdr. Whatever builds the tree needs to make sure that (3), (4) and (5) are true, or you get a more general graph structure.&lt;/p&gt;

&lt;p&gt;But you might want to have other sorts of trees, and you&amp;rsquo;d want the fold function not to care about what sort of tree it was processing: just that it was processing a tree. Indeed, it would be nice if it was possible to provide special implementations for, for instance, binary trees where rather than iterating over some sequence of children you&amp;rsquo;d know there were exactly two.&lt;/p&gt;

&lt;p&gt;So, I wondered if there was a nice way of expressing this in Racket and it turns out there mostly is. Racket has a notion of &lt;a href="https://docs.racket-lang.org/reference/struct-generics.html"&gt;generic interfaces&lt;/a&gt; which are really intended as a way for different &lt;a href="https://docs.racket-lang.org/reference/structures.html"&gt;structure types&lt;/a&gt; to provide common interfaces, I think. But it turns out they can be (ab?)used to do this, as well.&lt;/p&gt;

&lt;p&gt;Generic interfaces are not provided by &lt;code&gt;racket&lt;/code&gt; but by &lt;code&gt;racket/generic&lt;/code&gt;: everything below assumed &lt;code&gt;(require racket/generic)&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id="a-generic-treelike-interface"&gt;A generic &lt;code&gt;treelike&lt;/code&gt; interface&lt;/h2&gt;

&lt;p&gt;A treelike object supports two operations:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;&lt;code&gt;node-value&lt;/code&gt; returns the value of a node;&lt;/li&gt;
 &lt;li&gt;&lt;code&gt;node-children&lt;/code&gt; returns a list of the node&amp;rsquo;s children.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;The second of these is a bit nasty: it would be better perhaps to either provide an interface for mapping over a node&amp;rsquo;s children, or to return some general, possibly lazy, sequence of children. But this is just playing, so I don&amp;rsquo;t mind.&lt;/p&gt;

&lt;p&gt;Here is a definition of a generic &lt;code&gt;treelike&lt;/code&gt; interface, which includes default methods for lists:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-generics treelike
  ;; treelike objects have values and children
  (node-value treelike)
  (node-children treelike)
  #:fast-defaults
  (((λ (t)
      (and (cons? t) (list? t)))
    ;; non-null proper lists are trees: their value is their car;
    ;; their children are their cdr.
    (define node-value car)
    (define node-children cdr))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;This uses &lt;code&gt;#:fast-defaults&lt;/code&gt; instead of &lt;code&gt;#:defaults&lt;/code&gt;, which means that the dispatch to objects which satisfy &lt;code&gt;list?&lt;/code&gt; happens. This is fine in this case: lists are never going to be confused with any other tree type.&lt;/li&gt;
 &lt;li&gt;This relies on Racket&amp;rsquo;s (and Scheme&amp;rsquo;s?) &lt;code&gt;list?&lt;/code&gt; predicate returning true only for proper lists rather than CL&amp;rsquo;s cheap &lt;code&gt;listp&lt;/code&gt; which just returns true for anything which is either &lt;code&gt;nil&lt;/code&gt; or a cons.&lt;/li&gt;
 &lt;li&gt;There are lots of other options to &lt;code&gt;define-generics&lt;/code&gt; which I&amp;rsquo;m not using and many of which I don&amp;rsquo;t understand.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;With this definition:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (treelike? '())
#f
&amp;gt; (treelike? '(1 2 3))
#t
&amp;gt; (treelike? '(1 2 . 3))
#f
&amp;gt; (node-children '(1 2 3))
'(2 3)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, OK.&lt;/p&gt;

&lt;h2 id="a-treelike-binary-tree"&gt;A &lt;code&gt;treelike&lt;/code&gt; binary tree&lt;/h2&gt;

&lt;p&gt;We could then define a &lt;code&gt;binary-tree&lt;/code&gt; type which implements this generic interface:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(struct binary-tree (value left right)
  #:transparent
  #:methods gen:treelike
  ((define (node-value bt)
     (binary-tree-value bt))
   (define (node-children bt)
     (list (binary-tree-left bt)
           (binary-tree-right bt)))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;#:methods gen:treelike&lt;/code&gt; tells the structure we&amp;rsquo;re defining the methods needed for this thing to be a &lt;code&gt;treelike&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;And now we can check things:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (treelike? (binary-tree 1 2 3))
#t
&amp;gt; (node-value (binary-tree 1 2 3))
1
&amp;gt; (node-children (binary-tree 1 2 3))
'(2 3)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OK.&lt;/p&gt;

&lt;h2 id="two-attempts-at-a-generic-foldable-interface"&gt;Two attempts at a generic &lt;code&gt;foldable&lt;/code&gt; interface&lt;/h2&gt;

&lt;p&gt;So now I want to define another interface for things which can be folded. And the first thing I tried is this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-generics foldable
  ;; broken
  (fold operation initial foldable)
  #:defaults
  ((treelike?
    (define (fold op initial treelike)
      (let ([current (op initial (node-value treelike))]
            [children (node-children treelike)])
        (if (null? children)
            current
            (fold op (fold op current (first children))
                  (rest children))))))
   ((const true)
    (define (fold op initial any)
      (op initial any)))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So this tries to define a &lt;code&gt;fold&lt;/code&gt; generic function, which has two implementations: one for &lt;code&gt;treelike&lt;/code&gt; objects and one for &lt;em&gt;all other objects&lt;/em&gt;. So this means that &lt;em&gt;all&lt;/em&gt; objects are foldable, and, for instance &lt;code&gt;(fold + 0 1)&lt;/code&gt; simply turns into &lt;code&gt;(+ 0 1)&lt;/code&gt;. This is a bit odd but it simplifies the implementation of the interface for &lt;code&gt;treelike&lt;/code&gt; objects on the assumption that the children of nodes may not themselves be nodes (see above).&lt;/p&gt;

&lt;p&gt;There is another complexity: if the list of a &lt;code&gt;treelike&lt;/code&gt; node&amp;rsquo;s children isn&amp;rsquo;t null, then it&amp;rsquo;s a &lt;code&gt;treelike&lt;/code&gt;, so it can safely be recursed over rather than explicitly iterated over. This is a slightly questionable pun I think, but, well, I am a slightly questionable programmer.&lt;/p&gt;

&lt;p&gt;And this &amp;hellip; doesn&amp;rsquo;t work:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (fold + 0 '(1 2 3))
; node-value: contract violation:
; expected: treelike?
; given: 2
; argument position: 1st&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It took me a long time to understand this, and the answer is that the definitions of &lt;code&gt;fold&lt;/code&gt; inside the &lt;code&gt;define-generic&lt;/code&gt; form &lt;em&gt;aren&amp;rsquo;t adding methods to a generic function&lt;/em&gt;: what they are doing is defining a little local function, &lt;code&gt;fold&lt;/code&gt; which &lt;em&gt;then&lt;/em&gt; gets glued into the generic function. So references to &lt;code&gt;fold&lt;/code&gt; in the definition refer to the little local function. It is exactly as if you had done this, in fact:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-generics foldable
  ;; this is why it's broken
  (fold operation initial foldable)
  #:defaults
  ((treelike?
    (define fold
      (letrec ([fold (λ (op initial treelike)
                       (let ([current (op initial (node-value treelike))]
                             [children (node-children treelike)])
                         (if (null? children)
                             current
                             (fold op (fold op current (first children))
                                   (rest children)))))])
        fold)))
   ((const true)
    (define (fold op initial any)
      (op initial any)))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And you can see why this can&amp;rsquo;t work: the &lt;code&gt;fold&lt;/code&gt; bound by the &lt;code&gt;letrec&lt;/code&gt; calls itself rather than going through the generic dispatch.&lt;/p&gt;

&lt;p&gt;The way to fix this is to use the magic &lt;code&gt;define/generic&lt;/code&gt; form to get a copy of the generic function, and then call &lt;em&gt;that&lt;/em&gt;. This is syntactically horrid, but you can see why it is needed given the above. So a working version of this interface purports to be:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-generics foldable
  ;; not broken
  (fold operation initial foldable)
  #:defaults
  ((treelike?
    (define/generic fold/g fold)
    (define (fold op initial treelike)
      (let ([current (op initial (node-value treelike))]
            [children (node-children treelike)])
        (if (null? children)
            current
            (fold op (fold/g op current (first children))
                  (rest children))))))
   ((const true)
    (define (fold op initial any)
      (op initial any)))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And indeed it is not broken:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (fold + 0 '(1 2 3))
6&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and with some tracing added:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (fold + 0 '(1 2 3))
fold/treelike + 0 (1 2 3)
fold/any + 1 2
fold/treelike + 3 (3)
6&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="adding-a-special-case-to-fold-for-the-binary-tree"&gt;Adding a special case to &lt;code&gt;fold&lt;/code&gt; for the binary tree&lt;/h2&gt;

&lt;p&gt;So now, finally, we can add a special case to &lt;code&gt;fold&lt;/code&gt; to the binary tree defined above, rather than needlessly consing a list of children. We will need the same explicit-generic-function hack as before as the children of a binary tree may not be binary trees.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(struct binary-tree (value left right)
  #:transparent
  #:methods gen:treelike
  ((define (node-value bt)
     (binary-tree-value bt))
   (define (node-children bt)
     (list (binary-tree-left bt)
           (binary-tree-right bt))))
  #:methods gen:foldable
  ((define/generic fold/g fold)
   (define (fold op initial bt)
     (fold/g op
             (fold/g op (op initial (binary-tree-value bt))
                     (binary-tree-left bt))
             (binary-tree-right bt)))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (fold + 0 (binary-tree 1
                         (binary-tree 2 3 4)
                         (binary-tree 5 6 7)))
28&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and with some tracing&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (fold + 0 (binary-tree 1
                         (binary-tree 2 3 4)
                         (binary-tree 5 6 7)))
fold/bt + 0 #(struct:binary-tree 1 #(struct:binary-tree 2 3 4) #(struct:binary-tree 5 6 7))
fold/bt + 1 #(struct:binary-tree 2 3 4)
fold/any + 3 3
fold/any + 6 4
fold/bt + 10 #(struct:binary-tree 5 6 7)
fold/any + 15 6
fold/any + 21 7
28&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="missing-clos"&gt;Missing CLOS&lt;/h2&gt;

&lt;p&gt;In some ways this makes me miss CLOS: the explicit-generic-function hack is very annoying, single dispatch is annoying, not being able to define predicate-based methods separately from the &lt;code&gt;define-generics&lt;/code&gt; form is annoying. But on the other hand predicate-based dispatch is pretty cool.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2021-01-08-generic-interfaces-in-racket-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;Perhaps these should be called &amp;lsquo;sloppy trees&amp;rsquo; or something.&amp;nbsp;&lt;a href="#2021-01-08-generic-interfaces-in-racket-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Backup retention</title>
   <link>https://www.tfeb.org/fragments/2021/01/02/backup-retention/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2021-01-02-backup-retention</guid>
   <pubDate>Sat, 02 Jan 2021 17:33:01 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Or: should you keep that tape?&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;There is an interesting curve of backup retention.&lt;/p&gt;

&lt;p&gt;Initially, you should definitely keep them because they&amp;rsquo;re, well, backups that you might need to restore.&lt;/p&gt;

&lt;p&gt;Then there comes a time where you should almost certainly not keep them because they&amp;rsquo;re too old to be useful as backups.&lt;/p&gt;

&lt;p&gt;If they survive that they become, accidentally, archives: perhaps that tape sitting in some box has the only remaining copy of whatever-it-is. So don&amp;rsquo;t erase it.&lt;/p&gt;

&lt;p&gt;At the point where nothing will read the tape any more, well, whatever was on it is effectively gone now, so throw it away.&lt;/p&gt;

&lt;p&gt;At some point after that, one or both of two things happen: people become willing and able to do seriously heroic things to read really old media which might have the last remaining copy of something on it and/or the media itself becomes rare enough that it&amp;rsquo;s now a historical artifact worth preserving. The second thing can&amp;rsquo;t happen unless enough copies of the media get thrown away in earlier phases of the process: I don&amp;rsquo;t think minidiscs would be interesting historical artifacts (yet), but if I still had a Fuji Eagle I would definitely not throw it away.&lt;/p&gt;

&lt;p&gt;Later still it becomes possible to print, cheaply, replicas accurate at the atomic level of the thing, at which point its value should drop to the cost of making another clone, but in fact people start spending huge amounts of effort authenticating the original copy of the object which is held to be somehow ineffably different to all the perfect clones. At some point, people lose track: no-one now knows which the original &lt;em&gt;is&lt;/em&gt; any more, and since there is no physical distinction no-one ever will again. The people who have paid to have their copy authenticated as the original now spend much of their time arranging to have the other people who have done that assassinated.&lt;/p&gt;

&lt;p&gt;I forget which film this is.&lt;/p&gt;</description></item>
  <item>
   <title>MIME as a disease vector</title>
   <link>https://www.tfeb.org/fragments/2020/08/27/mime-as-a-disease-vector/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2020-08-27-mime-as-a-disease-vector</guid>
   <pubDate>Thu, 27 Aug 2020 10:34:35 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/MIME"&gt;MIME&lt;/a&gt;, the Multipurpose Internet Mail Extensions, seems like a good idea: what&amp;rsquo;s not to like about being able to send arbitrary data by email? In 1996, when I wrote the below, I didn&amp;rsquo;t think it was.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;Let&amp;rsquo;s say there are two computer system vendors:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;&lt;strong&gt;Vendor 1&lt;/strong&gt; provides a proprietary OS of high quality and high price, with good quality support. Is committed to &amp;lsquo;open systems; and publishes specifications of its interchange formats for mail, files and so forth. Its interchange formats may be &amp;rsquo;high value&amp;rsquo; &amp;mdash; text with logical rather than visual markup.&lt;/li&gt;
 &lt;li&gt;&lt;strong&gt;Vendor 2&lt;/strong&gt; provides a proprietary OS of lower quality but much lower price, with essentially no support. Is completely uninterested in open systems: does not publish its interchange formats, changes them frequently and incompatibly. Its interchange formats may also be &amp;lsquo;low value&amp;rsquo; &amp;mdash; for instance text with visual rather than logical markup.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Obviously one should buy systems from vendor 1: since purchase and vendor-support cost is rather small compared to the costs caused by low-quality systems this is clearly the right thing to do.&lt;/p&gt;

&lt;p&gt;Wrong. Circumstances can easily arise where buying from vendor 2 is the only viable option. This will increase greatly the cost of computing over what it &amp;lsquo;should be&amp;rsquo;, and will probably ensure that computing systems are of marginal benefit, if any. Even so it is necessary to buy these inferior systems.&lt;/p&gt;

&lt;p&gt;How does this happen? The key is data interchange. If the systems of vendor 2 become popular &amp;mdash; they are cheap, after all, and they will run on cheap hardware, so they are quite seductive to people who are not costing their systems thoroughly, as well as for home use &amp;mdash; and if people who have these systems once start interchanging data &amp;mdash; say mail messages using MIME &amp;mdash; with the owners of vendor 1 systems, then vendor 1 is doomed.&lt;/p&gt;

&lt;p&gt;Vendor 2 system owners will soon start getting mail in formats supported by vendor 1. But these are open standards: vendor 2 can implement displayer and editors for these formats. In fact it&amp;rsquo;s likely that free versions of these things sill become available. Owners of vendor 2 equipment are happy.&lt;/p&gt;

&lt;p&gt;Vendor 1 system owners will start getting mail in formats supported by vendor 2. These are closed, rapidly changing, formats. Vendor 1 has a problem: it has to reverse-engineer the format as it is closed, and as soon as it has done that, vendor 2 changes the format. Even if it can reverse-engineer the formats, the upward conversion from visual markup to logical markup is a hard problem which does not have a general solution.&lt;/p&gt;

&lt;p&gt;If vendor 2 systems are common, then it becomes commercially important to owners of vendor 1 equipment to be able to deal with vendor 2&amp;rsquo;s formats. But vendor 1 cannot keep up with the vendor 2 formats.&lt;/p&gt;

&lt;p&gt;The solution is to give up and buy from vendor 2 rather than vendor 1, and use vendor 2&amp;rsquo;s interchange standards. This will allow you to survive, since you can interchange data with other vendor 2 owners, but will mean that your computing systems are marginally useful, if at all:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;data is kept in low-value formats so you cannot reuse it;&lt;/li&gt;
 &lt;li&gt;formats change so old data cannot be used even in vendor 2 systems;&lt;/li&gt;
 &lt;li&gt;support costs go up as the lower-quality systems provided by vendor 2 break more often, and the poor or nonexistant support from vendor 2 forces local support at great cost.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Of course, vendor 2 needs to be able to force its data formats on people who have vendor 1 systems. This is now easy: computer networks and email are so prevalent that almost anyone has to be able to do interchange with almost anyone else. In particular MIME opens the door: if I&amp;rsquo;m on a vendor 1 machine, and vendor 1 has implemented MIME in its MUA (after all, vendor 1 is committed to open standards), then I will shortly find vendor 2 documents arriving in my mailbox, and shortly after that I will find myself buying a vendor 2 system.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s all a catastrophe.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I wrote this in early August 1996: the text above has been converted to markdown from its original HTML but is otherwise essentially unchanged from then. &amp;lsquo;Vendor 1&amp;rsquo; was Sun, and &amp;lsquo;vendor 2&amp;rsquo; was, of course, Microsoft, wth the low-value interchange format was Word.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t think I was completely right, but I was at least partly so: a lot of really terrible, very low-value data formats have become very prevalent, at least in part because MIME allows them to be easily transmitted.&lt;/p&gt;

&lt;p&gt;One thing I didn&amp;rsquo;t see coming (or saw coming but had not yet accepted) is that the disease spread by MIME would spread to even systems provided at very low or zero up-front cost, such as Linux: if you use OpenOffice or a derivative, you have been infected by the disease.&lt;/p&gt;

&lt;p&gt;Another thing that was not obvious was that some of the low-value formats would become effectively standardised, and so would be less toxic. &lt;a href="https://en.wikipedia.org/wiki/Rich_Text_Format"&gt;Rich Text Format&lt;/a&gt; is perhaps one good example, but even Word&amp;rsquo;s own native format may now be effectively a standard. This means that writing in these formats, while still very seriously limiting the value of your data, does not lock you in to a vendor as much as it once did.&lt;/p&gt;

&lt;p&gt;It is still, however, a catastrophe.&lt;/p&gt;</description></item>
  <item>
   <title>Do not use Duplicacy on macOS</title>
   <link>https://www.tfeb.org/fragments/2020/08/22/do-not-use-duplicacy-on-macs/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2020-08-22-do-not-use-duplicacy-on-macs</guid>
   <pubDate>Sat, 22 Aug 2020 10:17:02 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Duplicacy is a backup tool. It may possibly have good uses, but if you are using it on a Mac it is probably not actually making backups.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;h2 id="the-architecture-of-the-application"&gt;The architecture of the application&lt;/h2&gt;

&lt;p&gt;The Duplicacy application&lt;sup&gt;&lt;a href="#2020-08-22-do-not-use-duplicacy-on-macs-footnote-1-definition" name="2020-08-22-do-not-use-duplicacy-on-macs-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt; on the Mac presents itself as a little web server which you can then talk to (only via &lt;code&gt;localhost&lt;/code&gt;, which is good) to configure, run and monitor backups.&lt;/p&gt;

&lt;p&gt;What it does behind the scenes is more complicated. Other than some keychain entries (perhaps only one keychain entry) for a master password which is used to encrypt all the other sensitive data, all of its state lives in &lt;code&gt;~/.duplicacy-web&lt;/code&gt;. This includes all the configuration, logs and so on and, critically, an executable which is the actual program which runs backups, which lives in &lt;code&gt;~/.duplicacy-web/bin&lt;/code&gt; and has a name like &lt;code&gt;duplicacy_osx_x64_2.6.1&lt;/code&gt;. The application simply invokes this program to run backups for it. The application will also update this executable when it notices a new one.&lt;/p&gt;

&lt;p&gt;This itself is mildly terrifying: where did this executable come from? How safe is it? Can you be sure that the place it comes from will never be compromised? This executable is about to read all your files and copy them somewhere: you probably want to be a bit more sure about it than this.&lt;/p&gt;

&lt;p&gt;(This is very different than the case of updating the application itself: this is, or should be, something done under human control. At least in principle you can, and should, check that the thing you have just downloaded actually is what it says it is, and if you don&amp;rsquo;t, well, that&amp;rsquo;s a risk you are conciously taking.)&lt;/p&gt;

&lt;p&gt;It gets worse: the default configuration of the application will fetch the &lt;em&gt;latest&lt;/em&gt; executable, not a &lt;em&gt;stable&lt;/em&gt; one (however that is defined), thus maximising the chance that you will be running something that doesn&amp;rsquo;t work to do your backups, and also maximising the chance that you&amp;rsquo;ll get a compromised executable. If you are not frightened by now, you will be in a minute.&lt;/p&gt;

&lt;h2 id="the-annoyances-of-macos"&gt;The annoyances of macOS&lt;/h2&gt;

&lt;p&gt;From, I think, 10.14, macOS has developed a complicated and annoying protection system which is completely orthogonal to file permissions. I do not understand this system at all, but it essentially involves various policies about what programs can read and write to what. The intention seems to be that, for instance, some application you install should not be able to read or write personally-sensitive data without your explicit permission, &lt;em&gt;even if the filesystem or other permissions would allow it to do so&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&amp;lsquo;Personally-sensitive data&amp;rsquo; includes things like your email, your contacts, location information and so on. You can see these permissions in the &amp;lsquo;Privacy&amp;rsquo; pane of the &amp;lsquo;Security &amp;amp; Privacy&amp;rsquo; entry in &amp;lsquo;System Preferences&amp;rsquo; and presumably there is some configuration file somewhere which backs all this, and the &lt;code&gt;tccutil&lt;/code&gt; command can be useful as well. The protection system also controls various APIs, such as the one that provides location information.&lt;/p&gt;

&lt;p&gt;Although this system is irritating in the usual Apple way, I think it&amp;rsquo;s well-motivated: my email contains personally-sensitive data about me if no-one else, and I definitely don&amp;rsquo;t want some random program I run snooping on it, or finding out where I am, without explicitly asking me first.&lt;/p&gt;

&lt;p&gt;A place where this protection system really gets in the way is for backup tools. Backup tools &lt;em&gt;really need&lt;/em&gt; to be able to, well, make backups, and the most important things they need to back up are often the most sensitive. I &lt;em&gt;really want&lt;/em&gt; my backup program to be able to back up my email, for instance, as well as my calendar configuration and so on, and all the other stuff that the macOS protection mechanism would not normally let it read.&lt;/p&gt;

&lt;p&gt;So, Apple have thought of this. If you trust some application you can grant it &amp;lsquo;full disk access&amp;rsquo; which lets it read (and write, probably) the whole filesystem, only limited by filesystem permissions. This is exactly what you need for a backup program.&lt;/p&gt;

&lt;h2 id="the-first-disaster"&gt;The first disaster&lt;/h2&gt;

&lt;p&gt;So, obviously, when you get Duplicacy, you anoint it suitably in the Privacy pane so that it can have full disk access. (It does not tell you to do this, which is a bad sign in itself.)&lt;/p&gt;

&lt;p&gt;This doesn&amp;rsquo;t work. I think it doesn&amp;rsquo;t work because the program that is doing the backups is not the Duplicacy application, but this little executable which it downloaded. And, in fact, that&amp;rsquo;s a &lt;em&gt;good&lt;/em&gt; thing: I would really rather not allow an application to secretly download some executable which can read (and write) all my files and send them who-knows-where. It may be that the reason it does not work is that the executable is not signed, although it does appear to be signed, so I am not sure.&lt;/p&gt;

&lt;p&gt;In any case, what happens is that the executable fails to read sensitive data and thus fails to back it up. And it dutifully logs this, in &lt;code&gt;~/.duplicacy-web/logs/backup-*.log&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;2020-08-21 15:27:40.769 WARN LIST_FAILURE Failed to list subdirectory: open /Users/tfb/Library/Application Support/com.apple.TCC: operation not permitted
2020-08-21 15:27:40.955 WARN LIST_FAILURE Failed to list subdirectory: open /Users/tfb/Library/Calendars: operation not permitted
[...]
2020-08-21 15:27:43.830 WARN LIST_FAILURE Failed to list subdirectory: open /Users/tfb/Library/Containers/com.apple.mail: operation not permitted
[...]
2020-08-21 16:26:53.142 WARN BACKUP_SKIPPED 23 directories and 20 files were not included due to access errors&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In other words: the backup worked, partially, but it didn&amp;rsquo;t succeed in reading some of the the most critical data. If you need to restore from this backup, all your email will be gone.&lt;/p&gt;

&lt;p&gt;Well, perhaps you could suitably anoint the downloaded executable? You could do that, if you could work out how to get the Finder to let you see directories whose names have leading &lt;code&gt;.&lt;/code&gt;s, which is possible but fiddly. And it would work, for a while, until a new version with a new name appears, and then it will all break again and you&amp;rsquo;ll have to do it all again.&lt;/p&gt;

&lt;p&gt;So that&amp;rsquo;s a disaster. But it&amp;rsquo;s not the most serious one.&lt;/p&gt;

&lt;h2 id="the-second-disaster"&gt;The second disaster&lt;/h2&gt;

&lt;p&gt;So, you are configuring this thing via the web interface, like a good person. And you&amp;rsquo;ve thought to anoint the application so it can read everything, even though at no point did it tell you to do this (unlike other, competently-written, backup tools). And you run backups, and the executable dutifully logs that they failed. &lt;strong&gt;And there is no indication of this, at all in the web interface&lt;/strong&gt;, which simply tells you that the backup completed, by which it apparently means &amp;lsquo;the program ran, and after a while it stopped running, and that means everything must be OK&amp;rsquo;.&lt;/p&gt;

&lt;p&gt;In other words: if you are using a recent macOS, then Duplicacy is almost certainly not making good backups for you, and it is certainly not telling you about it when it does not.&lt;/p&gt;

&lt;h2 id="dont-use-duplicacy"&gt;Don&amp;rsquo;t use Duplicacy&lt;/h2&gt;

&lt;p&gt;I don&amp;rsquo;t understand how this happened other than that, very clearly, a lot of testing simply was never done. I do understand that it tells you something very, very bad about Duplicacy. I certainly would not, ever, use it on a Mac, and I find it so alarming that I would not in fact use it on any system at all.&lt;/p&gt;

&lt;p&gt;Backup tools need to work, because when you need them you &lt;em&gt;really&lt;/em&gt; need them. Duplicacy is &lt;em&gt;backup theatre&lt;/em&gt;: something that looks like a backup tool but in fact is not.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2020-08-22-do-not-use-duplicacy-on-macs-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;This refers to &amp;lsquo;Duplicacy Web Edition&amp;rsquo; &amp;mdash; there was an older GUI application which I don&amp;rsquo;t know anything about.&amp;nbsp;&lt;a href="#2020-08-22-do-not-use-duplicacy-on-macs-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>The glorious work of Dominic Cummings</title>
   <link>https://www.tfeb.org/fragments/2020/06/02/the-glorious-work-of-dominic-cummings/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2020-06-02-the-glorious-work-of-dominic-cummings</guid>
   <pubDate>Tue, 02 Jun 2020 16:59:52 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Or: the Cummings-Johnson effect.&lt;/p&gt;

&lt;p&gt;I thought it would be interesting to get an idea of how many people will die because Dominic Cummings thought it was fine to ignore the lockdown rules, and Boris Johnson agreed with him. So I wrote a program to explore this Cummings-Johnson effect.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;h2 id="all-the-reasons-you-had-to-die"&gt;All the reasons you had to die&lt;/h2&gt;

&lt;blockquote&gt;
 &lt;p&gt;&lt;em&gt;Jesus don&amp;rsquo;t want me for a sunbeam,&lt;/em&gt;
  &lt;br /&gt;&lt;em&gt;because sunbeams are not made like me,&lt;/em&gt;
  &lt;br /&gt;&lt;em&gt;and don&amp;rsquo;t expect me to cry,&lt;/em&gt;
  &lt;br /&gt;&lt;em&gt;for all the reasons you had to die,&lt;/em&gt;
  &lt;br /&gt;&lt;em&gt;don&amp;rsquo;t ever ask your love of me.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;There are two ways that what Cummings did in March 2020 will probably be killing people:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;he drove a long distance, presumably taking breaks&lt;sup&gt;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-1-definition" name="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;, while knowing he was infected with CV19;&lt;/li&gt;
 &lt;li&gt;now his actions are known, and now Johnson has supported them, other people&amp;rsquo;s behaviour will change.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;The first of these is likely to have killed people, and still be killing people, by spreading the virus: for instance to the toilets in service stations&lt;sup&gt;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-2-definition" name="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-2-return"&gt;2&lt;/a&gt;&lt;/sup&gt;. The second of these is likely to kill people, and perhaps has done so already, because now it is general knowledge that Cummings &amp;amp; Johnson think that lockdown rules are for other people &amp;mdash; for the little people, not people like them &amp;mdash; then they will take lockdown and social distancing less seriously, and people will die as a result of that.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s this second way that they are killing people that I looked at.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ths simulator described below is a toy&lt;/strong&gt;: it&amp;rsquo;s very much a physicist&amp;rsquo;s &amp;lsquo;spherical cow&amp;rsquo; model. It has no notion of locality for instance: infected individuals simply randomly pick other individuals to try to infect. The results it gives may be qualitatively reasonable, but if they are quantitively correct this is coincidence. The purpose of writing it, and of the runs described here, was simply to see if the Cummings-Johnson effect is visible, and to get some kind of qualitative estimate of how large it might be: if their actions will probably only kill only a few tens of people then they are doing no more harm than a common-or-garden mass murderers, while if their actions may kill thousands of people, then they&amp;rsquo;re working on a completely different scale.&lt;/p&gt;

&lt;p&gt;Epidemic models which are far better than this exist. For instance the &lt;a href="https://www.imperial.ac.uk/mrc-global-infectious-disease-analysis/"&gt;MRC Centre for Global Infectious Disease Analysis&lt;/a&gt; &amp;mdash; Professor Neil Ferguson&amp;rsquo;s group &amp;mdash; must have one. I would be very surprised if these people haven&amp;rsquo;t run much better versions of the scenarious I describe below. But the results of these runs don&amp;rsquo;t seem to have been published. This is sad but, perhaps, not surprising given what we know about Cummings &amp;amp; Johnson and their attitudes to facts which disagree with their fantasy worlds.&lt;/p&gt;

&lt;p&gt;Still: if there are results from better models I would very much like to know them.&lt;/p&gt;

&lt;h2 id="a-mindless-epidemic-simulator"&gt;A mindless epidemic simulator&lt;/h2&gt;

&lt;p&gt;I wrote a very simple-minded simulator: it is unlikely to be realistic, it&amp;rsquo;s really a toy model. The results are unlikely to be quantitively correct, but they may be qualitatively interesting. In the model individuals go through the standard three phases:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;initially they are uninfected &amp;amp; hence susceptible;&lt;/li&gt;
 &lt;li&gt;once they are infected they incubate the disease for \(t_l\) days, where \(t_l = 7\) in all the runs below&lt;/li&gt;
 &lt;li&gt;they are then infectious for \(t_i = 14\) days.&lt;/li&gt;
 &lt;li&gt;on each of these days, they randomly pick another individual, and if that individual is susceptible they infect them with a probability which is initially \(p_i = 0.14\).&lt;/li&gt;
 &lt;li&gt;at the end of the period they either die, with probability \(p_d = 0.01\), or they survive but become non-susceptible.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Additionally there may be a small &amp;lsquo;leakage&amp;rsquo;: every day, every susceptible person in the population can stand a small chance of becoming infected. This models the infection leaking in from abroad, for instance. In all the runs here the leakage \(p_l = 10^{-8}\).&lt;/p&gt;

&lt;p&gt;Finally the initial number of seeds can be set, the idea being to start the simulation after a good few people have become infected to avoid too much uncertainty in the trajectory of the epidemic. By default \(n_s = n_p/1000\), where \(n_s\) is the number of seeds and \(n_p\) is the population size.&lt;/p&gt;

&lt;p&gt;All of the parameters are adjustable as is how long to run for and what the stopping criteria are (with a leaky model things can keep on happening even after the number of infectious individuals reaches zero).&lt;/p&gt;

&lt;p&gt;It is straightforward to computee \(R_0\) for this model: a person is infectious for \(t_i\) days and each day they stand a \(p_i\) chance of infecting another person if no-one is yet infected, so&lt;/p&gt;

&lt;p&gt;\[
\begin{align}
  R_0 &amp;amp;= p_i t_i\\
      &amp;amp;= 0.14 \times 14\\
      &amp;amp;= 1.96
\end{align}
\]&lt;/p&gt;

&lt;p&gt;And then \(R\) declines over time as more people are removed from the population. When \(R &amp;lt; 1\) the epidemic dies out, more-or-less gradually, except for leaks causing occasional infections.&lt;/p&gt;

&lt;p&gt;Source code for this model is not currently available, although it may be in future.&lt;/p&gt;

&lt;h2 id="how-the-simulations-run"&gt;How the simulations run&lt;/h2&gt;

&lt;p&gt;All of \(t_l\), \(t_i\), \(p_i\), \(p_d\) and \(p_l\) can be adjusted during a run: the simulator is told to run for a few days, the values can then be adjusted and then it runs again for some given time. In practice the only parameter that I adjusted was \(p_i\): the probability of infection. Changing this during the run directly changes \(R_0\) and hence \(R\) and alters the course of the epidemic.&lt;/p&gt;

&lt;p&gt;There is nothing in the model which prevents any of these parameters being adjusted &lt;em&gt;dynamically&lt;/em&gt;, based on the current behaviour of the modelled epidemic. In fact I didn&amp;rsquo;t do that but instead set up &amp;lsquo;configuration sequences&amp;rsquo; which are sequences of configurations where the parameters (in practice, just \(p_i\), as well as some reporting parameters) are changed at fixed times, between which the model simply runs.&lt;/p&gt;

&lt;p&gt;Because there is inevitable variation between runs, the simulations get run several times, and the model also &lt;em&gt;forks&lt;/em&gt;: if I wanted to look at the effect of changing parameters on, say, \(d = 120\), a single simulation is run to \(d = 119\) and then multiple copies are run on from then. This means that any variation before \(d = 120\) is removed from the forks, since they all come from the same simulation run. This process can happen recursively if need be.&lt;/p&gt;

&lt;h2 id="some-example-runs"&gt;Some example runs&lt;/h2&gt;

&lt;p&gt;Here are some simple cases which show the behaviour of the model.&lt;/p&gt;

&lt;h3 id="abandoning-mitigation"&gt;Abandoning mitigation&lt;/h3&gt;

&lt;p&gt;Here is output for a model epidemic in which the mitigation is abandoned after 2 years:&lt;/p&gt;

&lt;div class="figure"&gt;&lt;img src="/fragments/img/2020/cummings-johnson/mitigated-giving-up-20200603-1M.svg" alt="Mitigated giving up after 2 years, cumulative deaths, population of 1 million" /&gt;
 &lt;p class="caption"&gt;Mitigated giving up after 2 years, cumulative deaths, population of 1 million&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;This is the output of a 4 year run for a population of a model with&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;\(n_p = 10^6\);&lt;/li&gt;
 &lt;li&gt;\(p_i = 0.14\) initially;&lt;/li&gt;
 &lt;li&gt;\(p_l = 10^{-8}\)&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;For the unmitigated forks, \(p_i\) remains at its initial value.&lt;/p&gt;

&lt;p&gt;For the completely mitigated forks&lt;/p&gt;

&lt;p&gt;\[
p_i = \begin{cases}
  0.14&amp;amp;d \lt 40\\
  0.06&amp;amp;120 \le d \lt 120\\
  0.08&amp;amp;120 \le d \lt 200\\
  0.06&amp;amp;d \ge 200
\end{cases}
\]&lt;/p&gt;

&lt;p&gt;For the &amp;lsquo;giving up&amp;rsquo; forks&lt;/p&gt;

&lt;p&gt;\[
p_i = \begin{cases}
  0.14&amp;amp;d &amp;lt; 40\\
  0.06&amp;amp;120 \le d \lt 20\\
  0.08&amp;amp;120 \le d \lt 200\\
  0.06&amp;amp;200 \le d \lt 730\\
  0.14&amp;amp;d \ge 730
\end{cases}
\]&lt;/p&gt;

&lt;p&gt;In other words what this is showing is a scenario where there is no vaccine, but mitigation is abandoned, after about 2 years. Because some leakage happens, at some point after the mitigation is abandoned the epidemic takes off again and a lot of people die. Exactly when it takes off depends on chance, but in all 5 runs here it&amp;rsquo;s within about a year and a half.&lt;/p&gt;

&lt;p&gt;Scaling the average results from this run to a population of 70 million&lt;sup&gt;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-3-definition" name="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-3-return"&gt;3&lt;/a&gt;&lt;/sup&gt; results in the following figures, all to 3 significant figures:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;551,000 deaths for the unmitigated epidemic;&lt;/li&gt;
 &lt;li&gt;40,300 deaths for the completely mitigated epidemic;&lt;/li&gt;
 &lt;li&gt;535,000 deaths for the epidemic in which mitigation is abandoned on day 730.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;For the mitigated epidemic this is somewhat lower than what the UK has so far seen, but it is in the right area: the model is clearly not hopeless. In later runs I adjusted the mitigation slightly to compensate for this (see below).&lt;/p&gt;

&lt;p&gt;What these results make clear is that, unless there is a vaccine&lt;sup&gt;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-3-definition" name="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-3-return"&gt;3&lt;/a&gt;&lt;/sup&gt;, mitigation has to continue essentially indefinitely, or the epidemic will take off again.&lt;/p&gt;

&lt;h3 id="chancy-runaways"&gt;Chancy runaways&lt;/h3&gt;

&lt;p&gt;Here are two runs which have an initial infected population, \(n_s = 0\): there are initially no infected people and the epidemic takes off due to leakage, with \(p_l = 10^{-8}\) as before.&lt;/p&gt;

&lt;p&gt;Firstly for a population of a million:&lt;/p&gt;

&lt;div class="figure"&gt;&lt;img src="/fragments/img/2020/cummings-johnson/chancy-runaway-20200602-1M-10ppb.svg" alt="Unmitigated, no seeds, cumulative deaths, population of 1 million, 10 runs" /&gt;
 &lt;p class="caption"&gt;Unmitigated, no seeds, cumulative deaths, population of 1 million, 10 runs&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;Well, you can see that the epidemic takes off again after less than two years in all cases.&lt;/p&gt;

&lt;p&gt;How likely this runaway is to happen in a given interval of time depends on the population size, as smaller populations experience fewer leakage events. Here is a run for a population of 10,000:&lt;/p&gt;

&lt;div class="figure"&gt;&lt;img src="/fragments/img/2020/cummings-johnson/chancy-runaway-20200602-10k-10ppb.svg" alt="Unmitigated, no seeds, cumulative deaths, population of 10k, 10 runs" /&gt;
 &lt;p class="caption"&gt;Unmitigated, no seeds, cumulative deaths, population of 10k, 10 runs&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;You can see that only one runaway happened in the three year simulation.&lt;/p&gt;

&lt;h2 id="the-cummings-johnson-effect"&gt;The Cummings-Johnson effect&lt;/h2&gt;

&lt;p&gt;To model this I started with an epidemic whose \(p_i\) values are initially:&lt;/p&gt;

&lt;p&gt;\[
p_i = \begin{cases}
  0.14&amp;amp;d &amp;lt; 40\\
  0.06&amp;amp;40 \le d &amp;lt;120\\
  0.08&amp;amp;120 \le d &amp;lt; 200\\
  0.06&amp;amp;200 \le d &amp;lt; 300\\
  0.08&amp;amp;300 \le d &amp;lt; 600\\
  0.07&amp;amp;d \ge 600
\end{cases}
\]&lt;/p&gt;

&lt;p&gt;All of the models run for 3 years, or 1095 days, and in addition the unmitigated epidemic is always plotted&lt;sup&gt;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-4-definition" name="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-4-return"&gt;4&lt;/a&gt;&lt;/sup&gt;. Each model ran 5 times and quoted figures are averages, scaled to a population of 70 million, to 3 significant figures&lt;/p&gt;

&lt;h3 id="cummings-johnson-on-day-120"&gt;Cummings-Johnson on day 120&lt;/h3&gt;

&lt;p&gt;For this model&lt;/p&gt;

&lt;p&gt;\[
p_i = \begin{cases}
  0.14&amp;amp;d &amp;lt; 40\\
  0.06&amp;amp;40 \le d &amp;lt; 120\\
  0.08\times
      \left\{1.02, 1.05, 1.10\right\}
      &amp;amp;120 \le d &amp;lt; 200\\
  0.06\times
      \left\{1.01, 1.03, 1.06\right\}
      &amp;amp;200\le d &amp;lt; 300\\
  0.08\times
      \left\{1.005, 1.02, 1.04\right\}
      &amp;amp;300 \le d &amp;lt; 600\\
  0.07\times
      \left\{1.002, 1.01, 1.02\right\}
      &amp;amp;d \ge 600
\end{cases}
\]&lt;/p&gt;

&lt;p&gt;Where the triples of numbers represent the Cummings-Johnson effect causing weakening of social distancing of 2%, 5% and 10% respectively on day 120, with the weakening declining over time. Here are plots for this:&lt;/p&gt;

&lt;div class="figure"&gt;&lt;img src="/fragments/img/2020/cummings-johnson/cummings-20200603-1M.svg" alt="Cummings-Johnson on day 120, 2%, 5% and 10%, population of 1 million" /&gt;
 &lt;p class="caption"&gt;Cummings-Johnson on day 120, 2%, 5% and 10%, population of 1 million&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;Here:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;the brown curves are the normal courses of the epidemic with and without mitigation;&lt;/li&gt;
 &lt;li&gt;the blue curves are 2%;&lt;/li&gt;
 &lt;li&gt;the orange curves are 5%;&lt;/li&gt;
 &lt;li&gt;the red curves are 10%;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;The figures are:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;551,000 deaths for the unmitigated epidemic;&lt;/li&gt;
 &lt;li&gt;63,100 deaths for the mitigated epidemic;&lt;/li&gt;
 &lt;li&gt;70,300 death for the 2% weakening;&lt;/li&gt;
 &lt;li&gt;86,500 deaths for the 5% weakening;&lt;/li&gt;
 &lt;li&gt;109,000 deaths for the 10% weakening.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Or in other words:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;7,200 additional deaths for 2% weakening;&lt;/li&gt;
 &lt;li&gt;32,400 additional deaths for 5% weakening;&lt;/li&gt;
 &lt;li&gt;45,900 additional deaths for 10% weakening.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;These numbers seemed far too high to me. And I also suspect that the epidemic in my model happens more slowly (takes more simulated days) than the real one. So I ran three more models, with the Cummings-Johnson effect taking place at successively later times.&lt;/p&gt;

&lt;h3 id="cummings-johnson-on-day-200"&gt;Cummings-Johnson on day 200&lt;/h3&gt;

&lt;p&gt;For this model&lt;/p&gt;

&lt;p&gt;\[
p_i = \begin{cases}
  0.14&amp;amp;d &amp;lt; 40\\
  0.06&amp;amp;40 \le d &amp;lt; 120\\
  0.08&amp;amp;120\le d &amp;lt; 200\\
  0.06\times
      \left\{1.02, 1.05, 1.10\right\}
      &amp;amp;200\le d &amp;lt; 300\\
  0.08\times
      \left\{1.01, 1.03, 1.06\right\}
      &amp;amp;300 \le d &amp;lt; 600\\
  0.07\times
      \left\{1.005, 1.02, 1.04\right\}
      &amp;amp;d \ge 600
\end{cases}
\]&lt;/p&gt;

&lt;p&gt;As you can see this allows the mitigated epidemic to run until day 200, when the same decaying effect happens. Here are plots for this:&lt;/p&gt;

&lt;div class="figure"&gt;&lt;img src="/fragments/img/2020/cummings-johnson/cummings-later-20200603-1M.svg" alt="Cummings-Johnson on day 200, 2%, 5% and 10%, population of 1 million" /&gt;
 &lt;p class="caption"&gt;Cummings-Johnson on day 200, 2%, 5% and 10%, population of 1 million&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;Figures:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;546,000 deaths unmitigated;&lt;/li&gt;
 &lt;li&gt;69,900 deaths mitigated;&lt;/li&gt;
 &lt;li&gt;75,100 deaths 2%;&lt;/li&gt;
 &lt;li&gt;93,700 deaths 5%;&lt;/li&gt;
 &lt;li&gt;128,700 deaths 10%.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Excess deaths:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;5,200 2%;&lt;/li&gt;
 &lt;li&gt;18,600 5%;&lt;/li&gt;
 &lt;li&gt;53,600 10%.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;This is a little better, but not much, and the 10% case is bizarrely bad.&lt;/p&gt;

&lt;h3 id="cummings-johnson-on-day-300"&gt;Cummings-Johnson on day 300&lt;/h3&gt;

&lt;p&gt;For this model&lt;/p&gt;

&lt;p&gt;\[
p_i = \begin{cases}
  0.14&amp;amp;d &amp;lt; 40\\
  0.06&amp;amp;40 \le d &amp;lt; 120\\
  0.08&amp;amp;120\le d &amp;lt; 200\\
  0.06&amp;amp;200\le d &amp;lt; 300\\
  0.08\times
      \left\{1.02, 1.05, 1.10\right\}
      &amp;amp;300 \le d &amp;lt; 600\\
  0.07\times
      \left\{1.01, 1.025, 1.05\right\}
      &amp;amp;d \ge 600
\end{cases}
\]&lt;/p&gt;

&lt;p&gt;Here are plots for this:&lt;/p&gt;

&lt;div class="figure"&gt;&lt;img src="/fragments/img/2020/cummings-johnson/cummings-even-later-20200603-1M.svg" alt="Cummings-Johnson on day 300, 2%, 5% and 10%, population of 1 million" /&gt;
 &lt;p class="caption"&gt;Cummings-Johnson on day 300, 2%, 5% and 10%, population of 1 million&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;Figures:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;551,000 deaths unmitigated;&lt;/li&gt;
 &lt;li&gt;59,800 deaths mitigated;&lt;/li&gt;
 &lt;li&gt;73,200 deaths 2%;&lt;/li&gt;
 &lt;li&gt;90,000 deaths 5%;&lt;/li&gt;
 &lt;li&gt;138,000 deaths 10%.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Excess deaths:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;13,400 2%;&lt;/li&gt;
 &lt;li&gt;30,200 5%;&lt;/li&gt;
 &lt;li&gt;78,200 10%.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;All these figures are &lt;em&gt;worse&lt;/em&gt; than the day 200 case, which think is because the big increase is happening when things are already too relaxed.&lt;/p&gt;

&lt;h3 id="cummings-johnson-on-day-600"&gt;Cummings-Johnson on day 600&lt;/h3&gt;

&lt;p&gt;For this model&lt;/p&gt;

&lt;p&gt;\[
p_i = \begin{cases}
  0.14&amp;amp;d &amp;lt; 40\\
  0.06&amp;amp;40 \le d &amp;lt; 120\\
  0.08&amp;amp;120\le d &amp;lt; 200\\
  0.06&amp;amp;200\le d &amp;lt; 300\\
  0.08&amp;amp;300 \le d &amp;lt; 600\\
  0.07\times
      \left\{1.02, 1.05, 1.10\right\}
      &amp;amp;d \ge 600
\end{cases}
\]&lt;/p&gt;

&lt;p&gt;Here are plots for this:&lt;/p&gt;

&lt;div class="figure"&gt;&lt;img src="/fragments/img/2020/cummings-johnson/cummings-really-late-20200603-1M.svg" alt="Cummings-Johnson on day 600, 2%, 5% and 10%, population of 1 million" /&gt;
 &lt;p class="caption"&gt;Cummings-Johnson on day 600, 2%, 5% and 10%, population of 1 million&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;Figures:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;546,000 deaths unmitigated;&lt;/li&gt;
 &lt;li&gt;61,700 deaths mitigated;&lt;/li&gt;
 &lt;li&gt;63,600 deaths 2%;&lt;/li&gt;
 &lt;li&gt;68,500 deaths 5%;&lt;/li&gt;
 &lt;li&gt;80,200 deaths 10%.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Excess deaths:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;1,900 2%;&lt;/li&gt;
 &lt;li&gt;6,800 5%;&lt;/li&gt;
 &lt;li&gt;18,500 10%.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;These seem a little less frightening&lt;/p&gt;

&lt;h3 id="why-is-it-so-fierce"&gt;Why is it so fierce?&lt;/h3&gt;

&lt;p&gt;I was really surprised by how large the differences are. I think part of the answer can be seen by looking at \(R\): at any point the progress of the epidemic goes something like \(e^{\alpha (R -1)t}\), where \(\alpha\) is some fudge factor. The only reason that the exponential runaway doesn&amp;rsquo;t continue is that \(R\) is a function not only of \(p_i\) but also of the proportion of people who are no longer susceptible. But if that proportion is low, which you very much want it to be, then everything is, more, or less, exponential, and really tiny changes in \(R\) can cause huge explosions.&lt;/p&gt;

&lt;p&gt;To control the epidemic over any length of time you need to keep \(R = 1 - \epsilon\) where \(\epsilon \ll 1, \epsilon &amp;gt; 0\): you want to do this because the epidemic will die out so long as \(R &amp;lt; 1\), but the social and economic cost of keeping it significantlly below 1 for any length of time is enormous. And for an epidemic which has infected, and therefore killed, only a relatively small proportion of the population then \(R \approx R_0\). So the useful thing to look at is \(\ln R\) &amp;amp; \(\ln R_0\), as this shows small changes near \(R = 1, R_0 = 1\) which is where all the action is&lt;sup&gt;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-5-definition" name="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-5-return"&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a plot of \(\ln R\) and \(\ln R_0\) for the Cummings-Johnson on day 120 2% variant, and the mitigated version without the 2% bump:&lt;/p&gt;

&lt;div class="figure"&gt;&lt;img src="/fragments/img/2020/cummings-johnson/cummings-2pct-20200603-rs.svg" alt="ln R, ln R0, Cummings-Johnson on day 120, 2% and mitigated" /&gt;
 &lt;p class="caption"&gt;ln R, ln R0, Cummings-Johnson on day 120, 2% and mitigated&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;Interestingly you can see that, for \(d \gtrapprox 500\) the Cummings 2% \(R\) is &lt;em&gt;lower&lt;/em&gt; than the mitigated \(R\). But it&amp;rsquo;s significantly higher for \(d \in [120, 200)\) and somewhat higher for \(d \in [200, 300)\) (although less than 1 in the second interval).&lt;/p&gt;

&lt;p&gt;So, well, very small changes for parameters in exponential processes can make very large differences: that should be obvious.&lt;/p&gt;

&lt;p&gt;It certainly would be the case that runs with more principled values for things (for instance my &amp;lsquo;decaying Cummings-Johnson effect&amp;rsquo; is pretty &lt;em&gt;ad-hoc&lt;/em&gt;: it would be better to model it by having some increase which exponentially decays with time: \(p_i = p_{i0}e^{-(t - t_0)/\tau}\) as people forget, which would be easy to model. Maybe I will have a go at that in due course.&lt;/p&gt;

&lt;h2 id="how-many-people-will-cummings-and-johnson-kill"&gt;How many people will Cummings and Johnson kill?&lt;/h2&gt;

&lt;p&gt;I don&amp;rsquo;t know. This model is not adequate to give a numerically-correct answer by a long way: it&amp;rsquo;s full of assumptions, and is in any case an extremely oversimplified model&lt;sup&gt;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-6-definition" name="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-6-return"&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;But I couldn&amp;rsquo;t get the number of people they will kill lower than 1,900, and I worked fairly hard to get it that low. I think my model is too sensitive, even though the numbers of people it kills for the mitigated epidemic are pretty reasonable and I did not fine-tune it for that, so I expect the real number will be somewhere between many hundreds and a few thousand. This is somewhere between mass murder and genocide&lt;sup&gt;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-7-definition" name="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-7-return"&gt;7&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Did Cummings &amp;amp; Johnson do this deliberately? Probably not. Are these the only people they will kill, or even most the people they will kill, due to their ideological, careless and incompetent handling of the epidemic and other things? No. Would the harm have been reduced if Johnson had promptly sacked Cummings? Yes. Would the harm still be reduced if he were to sack him now? Yes. Will he sack him? Of course not. Do either of them care that they will kill a lot of people? Definitely not: the people they have killed and will kill are only little people, like ants.&lt;/p&gt;

&lt;p&gt;This is the glorious work of Dominic Cummings, aided and abetted by his idiot stooge, Boris Johnson.&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;&lt;em&gt;Don&amp;rsquo;t expect me to lie,&lt;/em&gt;
  &lt;br /&gt;&lt;em&gt;don&amp;rsquo;t expect me to cry,&lt;/em&gt;
  &lt;br /&gt;&lt;em&gt;don&amp;rsquo;t expect me to die for thee.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;He says he did not take breaks. This seems a deeply implausible claim given that he drove 260 miles with a small child in the car.&amp;nbsp;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-2-definition" class="footnote-definition"&gt;
   &lt;p&gt;Which, again, he claims none of his family visited.&amp;nbsp;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-2-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-3-definition" class="footnote-definition"&gt;
   &lt;p&gt;Another option is that the epidemic becomes globally extinct, when leakage would stop: this seems unlikely.&amp;nbsp;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-3-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-4-definition" class="footnote-definition"&gt;
   &lt;p&gt;This is not really helpful as it makes the plots harder to read.&amp;nbsp;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-4-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-5-definition" class="footnote-definition"&gt;
   &lt;p&gt;In my model I&amp;rsquo;m treating \(R_0\) as something you adjust via changes to \(p_i\), rather than a constant of the epidemic. \(R_0 = p_i t_i\), and I am adjusting \(p_i\). It would perhaps be better to say \(R_0 = p_{i,0}t_i\) and then define \(p_i = p_{i,0} - p_{i,m}\), where \(p_{i,m}\) is the parameter you adjust, and use that together with the proportion of people remaining susceptible to define \(R\): it doesn&amp;rsquo;t make any difference to what actually happens though.&amp;nbsp;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-5-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-6-definition" class="footnote-definition"&gt;
   &lt;p&gt;I would be extremely interested in results about the Cummings-Johnson effect from more serious models. Please get in touch if you know of any. I am happy to sign nondisclosure agreements if need be.&amp;nbsp;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-6-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2020-06-02-the-glorious-work-of-dominic-cummings-footnote-7-definition" class="footnote-definition"&gt;
   &lt;p&gt;Since we know that &lt;a href="https://www.bbc.co.uk/news/uk-52219070"&gt;BAME people are disproportionately affected by CV19&lt;/a&gt; this really is looking like genocide. Perhaps not a deliberate one, but I wonder how much Cummings &amp;amp; Johnson care that a bunch of BAME people will die because of their actions? Not much, I should think.&amp;nbsp;&lt;a href="#2020-06-02-the-glorious-work-of-dominic-cummings-footnote-7-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Sexism in computer science</title>
   <link>https://www.tfeb.org/fragments/2020/05/09/sexism-in-computer-science/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2020-05-09-sexism-in-computer-science</guid>
   <pubDate>Sat, 09 May 2020 17:16:02 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Anyone who says that the facts show that men are innately better than women in computing either does not know the facts, does not understand them, or is lying.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;h2 id="the-facts"&gt;The facts&lt;/h2&gt;

&lt;p&gt;In 1971, about 14% of US computer science and information science graduates were women. By 1984, about 38% were. But by 2011 the proportion had fallen to under 18%&lt;sup&gt;&lt;a href="#2020-05-09-sexism-in-computer-science-footnote-1-definition" name="2020-05-09-sexism-in-computer-science-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;. Here is a graph of the proportions by year from 1971 to 2011:&lt;/p&gt;

&lt;div class="figure"&gt;&lt;img src="/fragments/img/2020/sexism-in-cs/cs-is-graduate-ratio-us-1971-1981.svg" alt="CS &amp;amp; IS graduate ratio, US, 1971-2011" /&gt;
 &lt;p class="caption"&gt;CS &amp;amp; IS graduate ratio, US, 1971&amp;ndash;2011&lt;/p&gt;&lt;/div&gt;

&lt;h2 id="what-the-facts-show"&gt;What the facts show&lt;/h2&gt;

&lt;p&gt;This entire process happened in about two generations: the proportion of women more than doubled in less than one generation, and then about halved in a generation: some of the women studying CS in 2011 could be the daughters of the cohort of 1984, and the granddaughters of the 1970 cohort.&lt;/p&gt;

&lt;p&gt;No genetic change in a human population can happen this fast: evolution operates on timescales of thousands to millions of years, not over a small number of decades. This means that &lt;em&gt;whatever caused these changes was not a change in innate ability&lt;/em&gt;. There simply can be no question about that: there must be some other explanation, since the innate ability of women to do computer science, or any other innate ability, cannot have changed significantly over this period.&lt;/p&gt;

&lt;p&gt;This means that the changes were caused by something environmental. Perhaps in 1984 there was enormous positive discrimination, or in 1970 and 2011 there was enormous negative discrimination, or some combination of the two&lt;sup&gt;&lt;a href="#2020-05-09-sexism-in-computer-science-footnote-2-definition" name="2020-05-09-sexism-in-computer-science-footnote-2-return"&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;This data is also perfectly compatible with the conclusion that women may be innately as good at computing as men: 38% is not very far from 50%, and if we assume some level of sexism in 1984&lt;sup&gt;&lt;a href="#2020-05-09-sexism-in-computer-science-footnote-3-definition" name="2020-05-09-sexism-in-computer-science-footnote-3-return"&gt;3&lt;/a&gt;&lt;/sup&gt; it is easily possible that the underlying figure was 50%.&lt;/p&gt;

&lt;p&gt;What this data tells us, unambiguously, that whatever has caused these changes is &lt;em&gt;environmental&lt;/em&gt;, and is not due to any differences in innate ability as such changes simply cannot happen over this timescale. It also tells us that things have got a lot more skewed since 1984: progress in this area has not only stopped, it is being reversed and has been so since the mid 1980s: the situation now is only about 28% less skewed than it was in 1970.&lt;/p&gt;

&lt;h2 id="what-the-facts-dont-show"&gt;What the facts don&amp;rsquo;t show&lt;/h2&gt;

&lt;p&gt;What the data does &lt;em&gt;not&lt;/em&gt; say is why this has happened, except that it is not due to changes in innate ability.&lt;/p&gt;

&lt;p&gt;While it is almost certain that there was strong institutional discrimination against women in 1970, it seems unlikely that, in 2011, there was any kind of institutional discrimination, as this would be illegal and institutions are pretty good targets for legal action. So it seems unlikely that the decline is due to &lt;em&gt;institutional&lt;/em&gt; discrimination. However all the data says is that there has been a decline: not why.&lt;/p&gt;

&lt;p&gt;If we assume that most of the change is not due to institutional discrimination then it&amp;rsquo;s tempting to speculate on what &lt;em&gt;did&lt;/em&gt; cause it. Well, I&amp;rsquo;m not going to do that: I have theories but they are based either on no evidence or on anecdotal evidence. Perhaps someone has done proper research into the causes, but I don&amp;rsquo;t know. There is a vast surfeit of theories based on little or no data, and outright made-up stuff on the internet &amp;mdash; wild speculation, outright lies and &amp;lsquo;alternative facts&amp;rsquo;&lt;sup&gt;&lt;a href="#2020-05-09-sexism-in-computer-science-footnote-4-definition" name="2020-05-09-sexism-in-computer-science-footnote-4-return"&gt;4&lt;/a&gt;&lt;/sup&gt; &amp;mdash; and people are dying of this surfeit: I won&amp;rsquo;t add any more to it.&lt;/p&gt;

&lt;p&gt;One possible inference is that women who, today, succeed at computing degrees, have done so against significant odds. It&amp;rsquo;s very likely that this means that they are &lt;em&gt;better&lt;/em&gt; than men who achieve the same grades. So companies, if they are legally able to, might consider actively selecting female candidates for jobs, on the grounds that they are, probably, better.&lt;/p&gt;

&lt;h2 id="related-lies-and-confusions"&gt;Related lies and confusions&lt;/h2&gt;

&lt;p&gt;In any area where people make a claim that some group is innately better than some other group based on some metric, and where the scores of one or both of those groups has changed radically over time, then it is immediately safe to conclude that those claims are either lies, confusions or both, because either the metric is junk, or it is not measuring innate ability. The obvious example of this is racial &amp;lsquo;science&amp;rsquo;.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2020-05-09-sexism-in-computer-science-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;&lt;a href="https://nces.ed.gov/programs/digest/d12/tables/dt12_349.asp"&gt;Source&lt;/a&gt;. Later figures may be available, but I couldn&amp;rsquo;t find them. I also don&amp;rsquo;t have the figures for other countries but I expect they are broadly similar.&amp;nbsp;&lt;a href="#2020-05-09-sexism-in-computer-science-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2020-05-09-sexism-in-computer-science-footnote-2-definition" class="footnote-definition"&gt;
   &lt;p&gt;I worked in academic computing from shortly after 1984 to the late 1990s and although I am not female I can say with some certainty that there was not enormous positive discrimination.&amp;nbsp;&lt;a href="#2020-05-09-sexism-in-computer-science-footnote-2-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2020-05-09-sexism-in-computer-science-footnote-3-definition" class="footnote-definition"&gt;
   &lt;p&gt;Again, in my experience there was some level of sexism in academia in this period.&amp;nbsp;&lt;a href="#2020-05-09-sexism-in-computer-science-footnote-3-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2020-05-09-sexism-in-computer-science-footnote-4-definition" class="footnote-definition"&gt;
   &lt;p&gt;Which are, of course, lies.&amp;nbsp;&lt;a href="#2020-05-09-sexism-in-computer-science-footnote-4-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>The U combinator</title>
   <link>https://www.tfeb.org/fragments/2020/03/09/the-u-combinator/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2020-03-09-the-u-combinator</guid>
   <pubDate>Mon, 09 Mar 2020 17:45:22 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;The U combinator allows you to define recursive functions and I think it is simpler to understand than the Y combinator.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;It&amp;rsquo;s not obvious how things like &lt;code&gt;letrec&lt;/code&gt; get defined in Scheme, without using secret assignment. In fact I think they &lt;em&gt;are&lt;/em&gt; defined using secret assignment:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(letrec ([f (λ (...) ... (f ...) ...)])
  ...)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;turns into&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(let ([f ...])
  (set! f (λ (...) ... (f ...) ...))
  ...)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But it&amp;rsquo;s interesting to see how you can define recursive functions without relying on assignment, including mutually-recursive collections of functions. One way is using the U combinator.&lt;/p&gt;

&lt;p&gt;I suspect that there is lots of information about this out there, but it&amp;rsquo;s seriously hard to search for anything which looks like &amp;rsquo;*-combinator&amp;rsquo; now (even now I am starting a set of companies called &amp;lsquo;integration by parts&amp;rsquo;, &amp;lsquo;the quotient rule&amp;rsquo; &amp;amp;c).&lt;/p&gt;

&lt;p&gt;You can famously do this with the Y combinator, but I didn&amp;rsquo;t want to do that because Y is something I find I can understand for a few hours at a time and then I have to work it all out again. But it turns out that you can use something much simpler: the U combinator. It seems to be even harder to search for this than Y, but here is a quote about it:&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;In the theory of programming languages, the U combinator, \(U\), is the mathematical function that applies its argument to its argument; that is \(U(f) = f(f)\), or equivalently, \(U = \lambda f \cdot f(f)\).&lt;/p&gt;&lt;/blockquote&gt;

&lt;blockquote&gt;
 &lt;p&gt;Self-application permits the simulation of recursion in the λ-calculus, which means that the U combinator enables universal computation. (The U combinator is actually more primitive than the more well-known fixed-point Y combinator.)&lt;/p&gt;&lt;/blockquote&gt;

&lt;blockquote&gt;
 &lt;p&gt;The expression \(U(U)\) is the smallest non-terminating program.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;(Text mildly edited from &lt;a href="http://www.ucombinator.org/"&gt;here&lt;/a&gt;, which unfortunately is not a site all about the U combinator other than this quote.)&lt;/p&gt;

&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;All of the following code samples are in &lt;a href="https://racket-lang.org/"&gt;Racket&lt;/a&gt;. The macros are certainly Racket-specific and some of the other code probably is as well. To make the macros work you will need &lt;code&gt;syntax-parse&lt;/code&gt; via:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(require (for-syntax syntax/parse))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;However note that my use of &lt;code&gt;syntax-parse&lt;/code&gt; is naïve in the extreme: I&amp;rsquo;m really just an unfrozen CL caveman pretending to understand Racket&amp;rsquo;s macro system.&lt;/p&gt;

&lt;p&gt;Also note I have not ruthlessly turned everything into λ: Rather than &lt;code&gt;((λ (...) ...) ...)&lt;/code&gt; there is &lt;code&gt;(let ([... ...] ...) ...)&lt;/code&gt; in this code; there is use of multiple values including &lt;code&gt;let-values&lt;/code&gt;; there is &lt;code&gt;(define (f ...) ...)&lt;/code&gt; rather than &lt;code&gt;(define f (λ (...) ...))&lt;/code&gt; and so on.&lt;/p&gt;

&lt;h2 id="two-versions-of-u"&gt;Two versions of U&lt;/h2&gt;

&lt;p&gt;The first version of U is the obvious one:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define (U f)
  (f f))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But this will run into some problems with an applicative-order language, which Racket is by default. To avoid that we can make the assumption that &lt;code&gt;(f f)&lt;/code&gt; is going to be a function, and wrap that form in another function to delay its evaluation until it&amp;rsquo;s needed: this is the standard trick that you have to do for Y in an applicative-order language as well. I&amp;rsquo;m only going to use the applicative-order U when I have to, so I&amp;rsquo;ll give it a different name:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define (U/ao f)
  (λ args (apply (f f) args)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note also that I&amp;rsquo;m allowing more than one argument rather than doing the pure-λ-calculus thing.&lt;/p&gt;

&lt;h2 id="using-u-to-construct-a-recursive-functions"&gt;Using U to construct a recursive functions&lt;/h2&gt;

&lt;p&gt;To do this we do a similar trick that you do with Y: write a function which, if given a function as argument which deals with the recursive cases, will return a recursive function. And obviously I&amp;rsquo;ll use the Fibonacci function as the canonical recursive function.&lt;/p&gt;

&lt;p&gt;So, consider this thing:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define fibber
  (λ (f)
    (λ (n)
      (if (&amp;lt;= n 2)
          1
          (+ ((U f) (- n 1))
             ((U f) (- n 2)))))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a function which, given another function, &lt;code&gt;U&lt;/code&gt; of which computes smaller Fibonacci numbers, will return a function which will compute the Fibonacci number for &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In other words, &lt;em&gt;&lt;code&gt;U&lt;/code&gt; of this function is the Fibonacci function&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;And we can test this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (define fibonacci (U fibber))
&amp;gt; (fibonacci 10)
55&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So that&amp;rsquo;s very nice.&lt;/p&gt;

&lt;h2 id="wrapping-u-in-a-macro"&gt;Wrapping U in a macro&lt;/h2&gt;

&lt;p&gt;So, to hide all this the first thing to do is to remove the explicit calls to &lt;code&gt;U&lt;/code&gt; in the recursion. We can lift them out of the inner function completely:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define fibber/broken
  (λ (f)
    (let ([fib (U f)])
      (λ (n)
        (if (&amp;lt;= n 2)
            1
            (+ (fib (- n 1))
               (fib (- n 2))))))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Don&amp;rsquo;t try to compute &lt;code&gt;U&lt;/code&gt; of this&lt;/em&gt;: it will recurse endlessly because &lt;code&gt;(U fibber/broken)&lt;/code&gt; -&amp;gt; &lt;code&gt;(fibber/broken fibber/broken)&lt;/code&gt; and this involves computing &lt;code&gt;(U fibber/broken)&lt;/code&gt;, and we&amp;rsquo;re doomed.&lt;/p&gt;

&lt;p&gt;Instead we can use &lt;code&gt;U/ao&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define fibber
  (λ (f)
    (let ([fib (U/ao f)])
      (λ (n)
        (if (&amp;lt;= n 2)
            1
            (+ (fib (- n 1))
               (fib (- n 2))))))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And this is all fine &lt;code&gt;((U fibber) 10)&lt;/code&gt; is &lt;code&gt;55&lt;/code&gt; (and terminates!).&lt;/p&gt;

&lt;p&gt;Purists can then turn &lt;code&gt;let&lt;/code&gt; into &lt;code&gt;λ&lt;/code&gt; in the usual way:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define fibber
  (λ (f)
    ((λ (fib)
       (λ (n)
         (if (&amp;lt;= n 2)
             1
             (+ (fib (- n 1))
                (fib (- n 2))))))
     (U/ao f))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And this is really all you need to be able to write the macro:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax (with-recursive-binding stx)
  (syntax-parse stx
    [(_ (name:id value:expr) form ...+)
     #'(let ([name (U (λ (f)
                        (let ([name (U/ao f)])
                          value)))])
         form ...)]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or, for the pure of heart:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax (with-recursive-binding stx)
  (syntax-parse stx
    [(_ (name:id value:expr) form ...+)
     #'((λ (name)
          form ...)
        (U (λ (f)
             ((λ (name)
                value)
              (U/ao f)))))]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And this works fine:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(with-recursive-binding (fib (λ (n)
                               (if (&amp;lt;= n 2)
                                   1
                                   (+ (fib (- n 1))
                                      (fib (- n 2))))))
  (fib 10))&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="a-caveat-on-bindings"&gt;A caveat on bindings&lt;/h2&gt;

&lt;p&gt;One fairly obvious thing here is that there are &lt;em&gt;two&lt;/em&gt; bindings constructed by this macro: the outer one, and an inner one of the same name. And these are not bound to the same function in the sense of &lt;code&gt;eq?&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(with-recursive-binding (ts (λ (it)
                              (eq? ts it)))
  (ts ts))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;is &lt;code&gt;#f&lt;/code&gt;. This matters only in a language where bindings can be mutated: a language with assignment in other words. Both the outer and inner bindings, unless they have been mutated, are to functions which are identical &lt;em&gt;as functions&lt;/em&gt;: they compute the same values for all values of their arguments. In fact, it&amp;rsquo;s hard to see what purpose &lt;code&gt;eq?&lt;/code&gt; would serve in a language without assignment.&lt;/p&gt;

&lt;p&gt;This caveat will apply below as well.&lt;/p&gt;

&lt;h2 id="two-versions-of-u-for-many-functions"&gt;Two versions of U for many functions&lt;/h2&gt;

&lt;p&gt;The obvious generalization of U, U*, to many functions is that \(U^*(f_1, \ldots, f_n)\) is the tuple \((f_1(f_1, \ldots, f_n), f_2(f_1, \ldots, f_n), \ldots)\). And a nice way of expressing that in Racket is to use multiple values:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define (U* . fs)
  (apply values (map (λ (f)
                       (apply f fs))
                     fs)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And we need the applicative-order one as well:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define (U*/ao . fs)
  (apply values (map (λ (f)
                       (λ args (apply (apply f fs) args)))
                     fs)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that U* is a true generalization of U: &lt;code&gt;(U f)&lt;/code&gt; and &lt;code&gt;(U* f)&lt;/code&gt; are the same.&lt;/p&gt;

&lt;h2 id="using-u-to-construct-mutually-recursive-functions"&gt;Using U* to construct mutually-recursive functions&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;ll work with a trivial pair of functions:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;an object is a &lt;em&gt;numeric tree&lt;/em&gt; if it is a cons and its car and cdr are numeric objects;&lt;/li&gt;
 &lt;li&gt;an objct is a &lt;em&gt;numeric object&lt;/em&gt; if it is a number, or if it is a numeric tree.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;So we can define &amp;lsquo;maker&amp;rsquo; functions (with an &amp;rsquo;-er&amp;rsquo; convention: a function which makes an &lt;em&gt;x&lt;/em&gt; is an &lt;em&gt;x&lt;/em&gt;er, or, if &lt;em&gt;x&lt;/em&gt; has hyphens in it, an &lt;em&gt;x&lt;/em&gt;-er) which will make suitable functions:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define numeric-tree-er
  (λ (nter noer)
    (λ (o)
      (let-values ([(nt? no?) (U* nter noer)])
        (and (cons? o)
             (no? (car o))
             (no? (cdr o)))))))

(define numeric-object-er
  (λ (nter noer)
    (λ (o)
      (let-values ([(nt? no?) (U* nter noer)])
        (cond
          [(number? o) #t]
          [(cons? o) (nt? o)]
          [else #f])))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that for both of these I&amp;rsquo;ve raised the call to &lt;code&gt;U*&lt;/code&gt; a little, simply to make the call to the appropriate value of &lt;code&gt;U*&lt;/code&gt; less opaque.&lt;/p&gt;

&lt;p&gt;And this works:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-values (numeric-tree? numeric-object?)
  (U* numeric-tree-er numeric-object-er))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (numeric-tree? 1)
#f
&amp;gt; (numeric-object? 1)
#t
&amp;gt; (numeric-tree? '(1 . 2))
#t
&amp;gt; (numeric-tree? '(1 2 . (3 4)))
#f&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="wrapping-u-in-a-macro"&gt;Wrapping U* in a macro&lt;/h2&gt;

&lt;p&gt;The same problem as previously happens when we raise the inner call to &lt;code&gt;U*&lt;/code&gt; with the same result: we need to use &lt;code&gt;U*/ao&lt;/code&gt;. In addition the macro becomes significantly more hairy and I&amp;rsquo;m moderately surprised that I got it right so easily. It&amp;rsquo;s not conceptually hard: it&amp;rsquo;s just not obvious to me that the pattern-matching works.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax (with-recursive-bindings stx)
  (syntax-parse stx
    [(_ ((name:id value:expr) ...) form ...+)
     #:fail-when (check-duplicate-identifier (syntax-&amp;gt;list #'(name ...)))
     "duplicate variable name"
     (with-syntax ([(argname ...) (generate-temporaries #'(name ...))])
       #'(let-values
             ([(name ...) (U* (λ (argname ...)
                                (let-values ([(name ...)
                                              (U*/ao argname ...)])
                                  value)) ...)])
           form ...))]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now, in a shower of sparks, we can write:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(with-recursive-bindings ((numeric-tree?
                           (λ (o)
                             (and (cons? o)
                                  (numeric-object? (car o))
                                  (numeric-object? (cdr o)))))
                          (numeric-object?
                           (λ (o)
                             (cond [(number? o) #t]
                                   [(cons? o) (numeric-tree? o)]
                                   [else #f]))))
  (numeric-tree? '(1 2 3 (4 (5 . 6) . 7) . 8)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and get &lt;code&gt;#t&lt;/code&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;As I said, I am sure there are well-known better ways to do this, but I thought this was interesting enough not to lose. This originated as an answer to &lt;a href="https://stackoverflow.com/questions/60460322/implement-a-self-reference-pointer-in-a-pure-functional-language-elm-haskell"&gt;this Stack Overflow question&lt;/a&gt;.&lt;/p&gt;</description></item>
  <item>
   <title>Polkit: wat</title>
   <link>https://www.tfeb.org/fragments/2020/02/24/polkit-wat/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2020-02-24-polkit-wat</guid>
   <pubDate>Mon, 24 Feb 2020 16:41:11 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;What polkit is, why you should worry about it, some ways to defang it.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;h2 id="what-polkit-is"&gt;What polkit is&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.freedesktop.org/software/polkit/" title="polkit's home page"&gt;Polkit&lt;/a&gt;&lt;sup&gt;&lt;a href="#2020-02-24-polkit-wat-footnote-1-definition" name="2020-02-24-polkit-wat-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt; is part of the &lt;a href="https://www.freedesktop.org/"&gt;freedesktop.org&lt;/a&gt; project. The &lt;a href="https://www.freedesktop.org/software/polkit/docs/latest/polkit.8.html" title="polkit(8)"&gt;documentation for polkit&lt;/a&gt; describes what it does:&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;polkit provides an authorization API intended to be used by privileged programs (“MECHANISMS”) offering service to unprivileged programs (“SUBJECTS”) often through some form of inter-process communication mechanism. In this scenario, the mechanism typically treats the subject as untrusted. For every request from a subject, the mechanism needs to determine if the request is authorized or if it should refuse to service the subject. Using the polkit APIsu, a mechanism can offload this decision to a trusted party: The polkit authority.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;In other words, polkit provides a mechanism by which applications can run parts of themselves with elevated privilege, in a similar way that &lt;code&gt;sudo&lt;/code&gt; and other mechanisms do. There are no limits to the privilege that can be gained using polkit, and in particular there is nothing preventing it from allowing programs to run as any user, including &lt;code&gt;root&lt;/code&gt; via the &lt;a href="https://www.freedesktop.org/software/polkit/docs/latest/pkexec.1.html" title="pkexec(8)"&gt;&lt;code&gt;pkexec&lt;/code&gt;&lt;/a&gt; utiity. As well as polkit&amp;rsquo;s own documentation the &lt;a href="https://en.wikipedia.org/wiki/Polkit" title="Wikipedia entry"&gt;Wikipedia article&lt;/a&gt; on it is fairly good.&lt;/p&gt;

&lt;p&gt;An example of the sort of problem that polkit wants to solve, I think, is that it&amp;rsquo;s desirable that someone using a desktop system should be able to turn it off without needing to be a privileged user. But it&amp;rsquo;s rather &lt;em&gt;undesirable&lt;/em&gt; that someone using the same machine via &lt;code&gt;ssh&lt;/code&gt; for instance should be able to turn it off, &lt;em&gt;even if they are the same user&lt;/em&gt;. So there needs to be some framework which lets you express the idea that &amp;lsquo;if this person is using a GUI on the console of this machine, they should be able to shut it down, but they should not be able to do that if they are not using the GUI on the console (for instance, they should almost certainly not be able to set up a &lt;code&gt;cron&lt;/code&gt; or &lt;code&gt;at&lt;/code&gt; job to turn the machine off)&amp;rsquo;. There are enough other such operations, such as connecting USB disks to machines, which need to have similar controls around them to make a general framework worth having.&lt;/p&gt;

&lt;p&gt;Polkit ships as part of the basic installs of several Linux distributions, including (but not limited to):&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;RHEL 7;&lt;/li&gt;
 &lt;li&gt;Ubuntu 19.10 (older version of polkit);&lt;/li&gt;
 &lt;li&gt;CentOS 7 &amp;amp; 8.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Polkit is included as part of server as well as desktop installs of these platforms. I&amp;rsquo;m not sure what purpose it serves on server installs: I suspect that it may be used for device management.&lt;/p&gt;

&lt;h2 id="a-simple-example-of-pkexec"&gt;A simple example of pkexec&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;pkexec&lt;/code&gt; is a command-line tool which uses &lt;code&gt;polkit&lt;/code&gt; to decide whether a user is allowed to run a command as another user, with that other user being, by default, &lt;code&gt;root&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="brush: bash"&gt;&lt;code&gt;$ groups
tfb wheel
$ id -u
1000
$ pkexec id -u
==== AUTHENTICATING FOR org.freedesktop.policykit.exec ====
Authentication is needed to run `/usr/bin/id' as the super user
Authenticating as: Tim Bradshaw (tfb)
Password:
==== AUTHENTICATION COMPLETE ====
0
$&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So you can see that &lt;code&gt;pkexec&lt;/code&gt; is doing the same thing that &lt;code&gt;sudo&lt;/code&gt; would do: it has some rules which say that &lt;code&gt;tfb&lt;/code&gt; is allowed to do things as &lt;code&gt;root&lt;/code&gt; and is then asking that user to authenticate themselves. In fact, as configured on the machine this ran on, &lt;code&gt;tfb&lt;/code&gt; is allowed to become &lt;code&gt;root&lt;/code&gt; by virtue of being in the &lt;code&gt;wheel&lt;/code&gt; group (&lt;code&gt;sudo&lt;/code&gt; has equivalent rules on this machine).&lt;/p&gt;

&lt;h2 id="enough-polkit-to-be-dangerous"&gt;Enough polkit to be dangerous&lt;/h2&gt;

&lt;p&gt;Polkit is a big complicated system and part of an even bigger and more complicated system: in order to understand it you need to &lt;a href="https://www.freedesktop.org/software/polkit/docs/" title="polkit manuals"&gt;read the manuals&lt;/a&gt;, and also to understand about how things like &lt;a href="https://www.freedesktop.org/wiki/Software/dbus/" title="D-bus"&gt;D-bus&lt;/a&gt; work. I don&amp;rsquo;t understand all of those things, but here is enough information to be able to poke around in the configuration files and get some idea about what is going on. This is not a definitive guide: reading the manuals or the source is the only way to get that.&lt;/p&gt;

&lt;p&gt;There have been at least two versions of polkit: I&amp;rsquo;m mostly describing the newer one here. As of 19.10, Ubuntu still uses an older version.&lt;/p&gt;

&lt;h3 id="the-names-of-things"&gt;The names of things&lt;/h3&gt;

&lt;ul&gt;
 &lt;li&gt;An unprivileged program making a request to polkit to do something is known as a &lt;strong&gt;subject&lt;/strong&gt;.&lt;/li&gt;
 &lt;li&gt;What the unprivileged program is asking for is an &lt;strong&gt;action&lt;/strong&gt;.&lt;/li&gt;
 &lt;li&gt;A privileged program which performs an action is a &lt;strong&gt;mechanism&lt;/strong&gt;.&lt;/li&gt;
 &lt;li&gt;The thing that verifies whether a given subject can get a given mechanism to perform a given action is the &lt;strong&gt;authority&lt;/strong&gt;.&lt;/li&gt;
 &lt;li&gt;An &lt;strong&gt;authentication agent&lt;/strong&gt; is something which is asked by the authority to get someone or something authenticate themselves.&lt;/li&gt;&lt;/ul&gt;

&lt;h3 id="an-overview-of-polkit"&gt;An overview of polkit&lt;/h3&gt;

&lt;div class="figure"&gt;&lt;img src="/fragments/img/2020/polkit-wat/polkit-overview-20200131.svg" alt="Polkit overview" /&gt;
 &lt;p class="caption"&gt;Polkit overview&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;In this figure:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;links in red are (usually?) mediated by dbus;&lt;/li&gt;
 &lt;li&gt;&lt;code&gt;polkitd&lt;/code&gt; is the authority at the centre of the process, and deals with checking if an action is allowed, and getting authentication for it;&lt;/li&gt;
 &lt;li&gt;the policies files describe what actions exist;&lt;/li&gt;
 &lt;li&gt;the rules files provide rules which tell you if a given requested action should be allowed.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;The most important part of the process is &lt;code&gt;polkitd&lt;/code&gt;, together with the rules and policies files it consults.&lt;/p&gt;

&lt;p&gt;I am fairly sure that the requesting program (subject) and the privileged program (mechanism) can be the same: this is the case for &lt;code&gt;pkexec&lt;/code&gt; for instance. However it could be the intent is that the subject is whatever invoked &lt;code&gt;pkexec&lt;/code&gt; in this case.&lt;/p&gt;

&lt;h3 id="polkitd"&gt;polkitd&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;polkitd&lt;/code&gt; is the daemon which is at the centre of polkit. Its job is to serve as the authority: it answers the question of whether a given request should be allowed or not and deals with any required authentication by talking to an authentication agent. &lt;code&gt;polkitd&lt;/code&gt; does not itself have any particular privilege, and runs as the &lt;code&gt;polkitd&lt;/code&gt; user: the questions it answers can be very critical to security however.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;polkitd&lt;/code&gt; is configured by two sets of files:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;policy files, also known as action files which describe what sort of &amp;lsquo;actions&amp;rsquo; polkit knows about;&lt;/li&gt;
 &lt;li&gt;rules files, which describe the conditions under which a given action should be allowed.&lt;/li&gt;&lt;/ul&gt;

&lt;h3 id="policy-files"&gt;Policy files&lt;/h3&gt;

&lt;p&gt;Policy files live in the &lt;code&gt;/usr/share/polkit-1/actions/&lt;/code&gt; directory, and have extension &lt;code&gt;policy&lt;/code&gt;. All the files in that directory are read, and I&amp;rsquo;m reasonably sure that &lt;code&gt;polkitd&lt;/code&gt; watches for changes in the directory and reads or rereads things appropriately.&lt;/p&gt;

&lt;p&gt;Policy files are XML, and their content is described in &lt;a href="https://www.freedesktop.org/software/polkit/docs/latest/polkit.8.html" title="polkit(8)"&gt;polkit(8)&lt;/a&gt;. The important elements are &lt;code&gt;&amp;lt;action&amp;gt;&lt;/code&gt;s, which specify what the actions are. A given policy file can specify many actions. Because the files are XML and also because they often have a lot of internationalisation support they are fairly hard to read. However there&amp;rsquo;s a nice utility called &lt;code&gt;pkaction&lt;/code&gt; which will tell you what actions exist and display them in a more readable format: &lt;code&gt;pkaction&lt;/code&gt; on its own will list all of the available actions and &lt;code&gt;pkaction --verbose&lt;/code&gt; will display details about them. You can also use the &lt;code&gt;--action-id&lt;/code&gt; option to specify an individual action to display, as here:&lt;/p&gt;

&lt;pre class="brush: bash"&gt;&lt;code&gt;$ pkaction --verbose --action-id org.freedesktop.policykit.exec
org.freedesktop.policykit.exec:
  description:       Run a program as another user
  message:           Authentication is required to run a program as another user
  vendor:            The polkit project
  vendor_url:        http://www.freedesktop.org/wiki/Software/polkit/
  icon:
  implicit any:      auth_admin
  implicit inactive: auth_admin
  implicit active:   auth_admin &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This corresponds to the following XML fragment&lt;sup&gt;&lt;a href="#2020-02-24-polkit-wat-footnote-2-definition" name="2020-02-24-polkit-wat-footnote-2-return"&gt;2&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;action id="org.freedesktop.policykit.exec"&amp;gt;
  &amp;lt;description&amp;gt;Run a program as another user&amp;lt;/description&amp;gt;
  &amp;lt;message&amp;gt;Authentication is required to run a program as another user&amp;lt;/message&amp;gt;
  &amp;lt;defaults&amp;gt;
    &amp;lt;allow_any&amp;gt;auth_admin&amp;lt;/allow_any&amp;gt;
    &amp;lt;allow_inactive&amp;gt;auth_admin&amp;lt;/allow_inactive&amp;gt;
    &amp;lt;allow_active&amp;gt;auth_admin&amp;lt;/allow_active&amp;gt;
  &amp;lt;/defaults&amp;gt;
&amp;lt;/action&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;org.freedesktop.policykit.exec&lt;/code&gt; action is the one that &lt;code&gt;pkexec&lt;/code&gt; uses to do things: the policy file that specifies it is probably &lt;code&gt;/usr/share/polkit-1/actions/org.freedesktop.policykit.policy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The interesting part of action specifications in policy files is their defaults: these tell you what is required to perform the action in various circumstances. &lt;code&gt;pkaction&lt;/code&gt; reports these defaults as &lt;code&gt;implicit ...&lt;/code&gt; at the end. It&amp;rsquo;s not completely clear from the documentation, but I strongly assume that these are &lt;em&gt;minimum&lt;/em&gt; requirements for the action to be performed. In the example above, anything requesting the action is required to authenticate as an administrative user, and that authentication is not remembered for any period.&lt;/p&gt;

&lt;p&gt;Additionally there can be annotations added, which are key/value pairs which let you specify various things like paths.&lt;/p&gt;

&lt;h3 id="rules-files"&gt;Rules files&lt;/h3&gt;

&lt;p&gt;Rules files live in two locations: &lt;code&gt;/etc/polkit-1/rules.d&lt;/code&gt; and &lt;code&gt; /usr/share/polkit-1/rules.d&lt;/code&gt;, and have extension &lt;code&gt;rules&lt;/code&gt;. All files in both directories are read, after being sorted in lexical order by filename, with files in &lt;code&gt;/etc&lt;/code&gt; being read first when there&amp;rsquo;s a tie. The daemon watches for changes in the directories and rereads everything in that case.&lt;/p&gt;

&lt;p&gt;The contents of rules files is JavaScript. Polkit defines an object called &lt;code&gt;polkit&lt;/code&gt; and there are various methods on this object which do useful things:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;&lt;code&gt;addRule(fn)&lt;/code&gt; adds a rule, which is a function which, given arguments representing an action and a subject, is responsible for saying if the action is allowed and what authorisation is needed to run it;&lt;/li&gt;
 &lt;li&gt;&lt;code&gt;addAdminRule(fn)&lt;/code&gt;adds a rule &amp;mdash; a function again &amp;mdash; which gets to say what counts as being an administrator;&lt;/li&gt;
 &lt;li&gt;&lt;code&gt;log(message)&lt;/code&gt;will log things in some suitable way;&lt;/li&gt;
 &lt;li&gt;&lt;code&gt;spawn(argv)&lt;/code&gt; will spawn a program, capturing its output.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;The functions added by &lt;code&gt;addRule&lt;/code&gt; are called in the order they were added, until one returns a non-null result, which can either unconditionally allow or deny the action, or require authorisation of various kinds.&lt;/p&gt;

&lt;p&gt;The functions added by &lt;code&gt;addAdminRule&lt;/code&gt; are called in the order they were added until one returns a description of what an administrator is.&lt;/p&gt;

&lt;p&gt;These functions can call &lt;code&gt;polkit.log(...)&lt;/code&gt; to log things and &lt;code&gt;polkit.spawn(...)&lt;/code&gt; to run programs.&lt;/p&gt;

&lt;p&gt;There are bounds on how long a rule may run for, and also on how long programs spawned by &lt;code&gt;polkit.spawn(...)&lt;/code&gt; can run for.&lt;/p&gt;

&lt;p&gt;More details on the rules files are in &lt;a href="https://www.freedesktop.org/software/polkit/docs/latest/polkit.8.html" title="polkit(8)"&gt;the documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id="example-rules-and-actions"&gt;Example rules and actions&lt;/h3&gt;

&lt;p&gt;Here is a sample rule which tries to require administrator authentication to run &lt;code&gt;pkexec&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="brush: js"&gt;&lt;code&gt;polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.policykit.exec") {
        polkit.log("pkexec rule hit\n");
        return polkit.Result.AUTH_ADMIN;
    } else {
        polkit.log("pkexec rule missed\n");
        return polkit.Result.NOT_HANDLED;
    }});&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If this is installed as, for instance &lt;code&gt;/usr/share/polkit-1/rules.d/00-pkexec.rules&lt;/code&gt; then it will try to ensure that anyone trying to use &lt;code&gt;pkexec&lt;/code&gt; requires administrator authorisation (equivalently: is required to authenticate themselves as an administrator). Since it is almost certainly first in the sort order, it also gets to control things before any other rules get their hands on things.&lt;/p&gt;

&lt;p&gt;Except this rule does not work: it &lt;em&gt;does&lt;/em&gt; catch actions whose id is &lt;code&gt;org.freedesktop.policykit.exec&lt;/code&gt;, but these are &lt;em&gt;not&lt;/em&gt; the only actions which &lt;code&gt;pkexec&lt;/code&gt; can use: it can also use actions which have an &lt;code&gt;org.freedesktop.policykit.exec.path&lt;/code&gt; annotation. For instance this policy file&lt;/p&gt;

&lt;pre class="brush: html"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD polkit Policy Configuration 1.0//EN"
"http://www.freedesktop.org/software/polkit/policyconfig-1.dtd"&amp;gt;
&amp;lt;policyconfig&amp;gt;
  &amp;lt;vendor&amp;gt;The sinister TFEB organisation&amp;lt;/vendor&amp;gt;
  &amp;lt;vendor_url&amp;gt;https://www.tfeb.org/&amp;lt;/vendor_url&amp;gt;
  &amp;lt;action id="org.tfeb.tc.explode"&amp;gt;
    &amp;lt;description&amp;gt;Explode&amp;lt;/description&amp;gt;
    &amp;lt;message&amp;gt;Authentication is not required to explode&amp;lt;/message&amp;gt;
    &amp;lt;annotate
        key="org.freedesktop.policykit.exec.path"&amp;gt;/usr/sbin/explode&amp;lt;/annotate&amp;gt;
    &amp;lt;defaults&amp;gt;
      &amp;lt;allow_any&amp;gt;yes&amp;lt;/allow_any&amp;gt;
      &amp;lt;allow_inactive&amp;gt;yes&amp;lt;/allow_inactive&amp;gt;
      &amp;lt;allow_active&amp;gt;yes&amp;lt;/allow_active&amp;gt;
    &amp;lt;/defaults&amp;gt;
  &amp;lt;/action&amp;gt;
&amp;lt;/policyconfig&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;will allow &lt;code&gt;/usr/sbin/explode&lt;/code&gt; to be run by &lt;code&gt;pkexec&lt;/code&gt; with no authentication at all:&lt;/p&gt;

&lt;pre class="brush: bash"&gt;&lt;code&gt;$ /usr/sbin/explode
exploded as UID 1000 GID 1000
$ pkexec /usr/sbin/explode
exploded as UID 0 GID 0&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To catch this, one approach is to rely on the fact that the &lt;code&gt;Action&lt;/code&gt; objects passed to the rule have properties which can be looked up with a &lt;code&gt;lookup&lt;/code&gt; method, and &lt;code&gt;pkexec&lt;/code&gt; sets a &lt;code&gt;program&lt;/code&gt; property. So the following version of the above rule should catch all &lt;code&gt;pkexec&lt;/code&gt; rules:&lt;/p&gt;

&lt;pre class="brush: js"&gt;&lt;code&gt;polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.policykit.exec"
        || action.lookup("program")) {
        polkit.log("pkexec rule hit\n");
        return polkit.Result.AUTH_ADMIN;
    } else {
        polkit.log("pkexec rule missed\n");
        return polkit.Result.NOT_HANDLED;
    }});&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A similar rule can simply disable &lt;code&gt;pkexec&lt;/code&gt; altogether&lt;sup&gt;&lt;a href="#2020-02-24-polkit-wat-footnote-3-definition" name="2020-02-24-polkit-wat-footnote-3-return"&gt;3&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;pre class="brush: js"&gt;&lt;code&gt;polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.policykit.exec"
        || action.lookup("program")) {
        polkit.log("pkexec rule hit\n");
        return polkit.Result.NO;
    } else {
        polkit.log("pkexec rule missed\n");
        return polkit.Result.NOT_HANDLED;
    }});&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now:&lt;/p&gt;

&lt;pre class="brush: bash"&gt;&lt;code&gt;$ pkexec /usr/sbin/explode
Error executing command as another user: Not authorized

This incident has been reported.&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="why-polkit-is-a-security-disaster"&gt;Why polkit is a security disaster&lt;/h2&gt;

&lt;p&gt;There are at least two reasons why the way polkit works is a security disaster:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;expressing rules in JavaScript (or any general programming language) is a terrible idea;&lt;/li&gt;
 &lt;li&gt;the implementation is deficient.&lt;/li&gt;&lt;/ul&gt;

&lt;h3 id="writing-rules-in-a-general-purpose-language-is-a-terrible-idea"&gt;Writing rules in a general-purpose language is a terrible idea&lt;/h3&gt;

&lt;p&gt;It might seem like a clever idea to write rules in JavaScript:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;using a general-purpose programming language means that very general rules can be implemented;&lt;/li&gt;
 &lt;li&gt;given that decision JavaScript is a common language which is not entirely awful.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;But in fact this is a terrible idea, just &lt;em&gt;because&lt;/em&gt; it means that very general rules can be implemented. In particular &lt;strong&gt;it is not possible, even in principle, to statically determine what polkit will allow or deny&lt;/strong&gt;. JavaScript is a fully-fledged programming language which means that the only way you can know what a program will do, in general, is to run it. There is, at least, no halting problem since the execution time of the rules is bounded, but all of the other problems associated with general-purpose programming languages are still present.&lt;/p&gt;

&lt;p&gt;What this means is that any kind of security analysis of a system needs to&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;check the rules are valid JavaScript, which can be done statically;&lt;/li&gt;
 &lt;li&gt;check what the rules do, which can&amp;rsquo;t be done statically, but requires the rules to be run.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;A possible counter argument to this is&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;Well, only very simple rules will ever be written: no-one is actually going to make use of all this power. In particular the rules people actually write will be so simple that they can in fact be analysed statically.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;That&amp;rsquo;s exactly the same argument as&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;Well, no-one is ever going to do anything bad, so they can all have the root password.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;and it&amp;rsquo;s equally stupid. Secure systems should make it &lt;em&gt;impossible&lt;/em&gt; to do things which are undesirable, not rely on people just not doing them. The language in which rules are expressed should be just expressive enough that allows the options needed, but no more expressive than that, and it should certainly always be possible to statically analyse a rule to know what it will allow. Using a general-purpose programming language for rules is just dumb.&lt;/p&gt;

&lt;p&gt;Just to drive home this point it turns out that the rules supplied with the system are indeed mildly hard to analyse: here is &lt;code&gt;/etc/polkit-1/rules.d/49-polkit-pkla-compat.rules&lt;/code&gt; from a CentOS 8 system:&lt;/p&gt;

&lt;pre class="brush: js"&gt;&lt;code&gt;polkit.addAdminRule(function(action, subject) {
        //polkit.log('Starting pkla-admin-identities\n');
        // Let exception, if any, propagate to the JS authority
        var res = polkit.spawn(['/usr/bin/pkla-admin-identities']);
        //polkit.log('Got "' + res.replace(/\n/g, '\\n') + '"\n');
        if (res == '')
                return null;
        var identities = res.split('\n');
        //polkit.log('Identities: ' + identities.join(',') + '\n');
        if (identities[identities.length - 1] == '')
                identities.pop()
        //polkit.log('Returning: ' + identities.join(',') + '\n');
        return identities;
});

polkit.addRule(function(action, subject) {
        var params = ['/usr/bin/pkla-check-authorization',
                      subject.user, subject.local ? 'true' : 'false',
                      subject.active ? 'true' : 'false', action.id];
        //polkit.log('Starting ' + params.join(' ') + '\n');
        var res = polkit.spawn(params);
        //polkit.log('Got "' + res.replace(/\n/g, '\\n') + '"\n');
        if (res == '')
                return null;
        return res.replace(/\n$/, '');
});&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Well, it&amp;rsquo;s possible to work out what this is doing, if you try hard. But note that, in particular what it is doing is deferring to completely separate programs both to work out who administrative users are, and whether an action should be allowed. So now you need to understand that program as well. And yes, it is doing all sorts of string hacking to parse the output of that program, which is always a really good sign.&lt;/p&gt;

&lt;h3 id="the-implementation-is-deficient"&gt;The implementation is deficient&lt;/h3&gt;

&lt;p&gt;Even given the design, polkit&amp;rsquo;s implementation is deficient.&lt;/p&gt;

&lt;p&gt;The first and most obvious sign of deficiency is that rules can invoke external programs: those programs run as the &lt;code&gt;polkitd&lt;/code&gt; user and can do anything it can do, including writing to the filesystem.&lt;/p&gt;

&lt;p&gt;If &lt;a href="https://selinuxproject.org/page/Main_Page" title="SELinux"&gt;SELinux&lt;/a&gt; is enabled on the system (which can be checked with &lt;code&gt;sestatus&lt;/code&gt;), and if the correct policy is loaded, then it may well prohibit this, as polkit&amp;rsquo;s rules run under a policy which prevents them writing to the filesystem. But &lt;code&gt;polkitd&lt;/code&gt; doesn&amp;rsquo;t check that SELinux is enforcing, or that the correct policy is in place: it just blunders on, trusting whatever external programs it runs to be well-behaved.&lt;/p&gt;

&lt;p&gt;But this is only the start of the horrors. The actions, and even more so the rules that &lt;code&gt;polkitd&lt;/code&gt; uses are security-critical. If I can install an early rule such as, for instance&lt;/p&gt;

&lt;pre class="brush: js"&gt;&lt;code&gt;polkit.addRule(function(action, subject) {
    return polkit.Result.YES;
});&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then I have completely bypassed security on the system, because &lt;code&gt;pkexec&lt;/code&gt; will let me do anything with no authentication at all.&lt;/p&gt;

&lt;p&gt;So polkit, and specifically &lt;code&gt;polkitd&lt;/code&gt; should be very careful about the ownership and permissions of the files and directories it looks at. In particular everything in the path down to any file it looks at should be owned by a privileged user and writable only by that user, and &lt;code&gt;polkitd&lt;/code&gt;. That user should almost certainly be &lt;code&gt;root&lt;/code&gt;. &lt;code&gt;polkitd&lt;/code&gt; should check this every time it reads anything.&lt;/p&gt;

&lt;p&gt;It doesn&amp;rsquo;t do that. In fact it doesn&amp;rsquo;t check at all:&lt;/p&gt;

&lt;pre class="brush: bash"&gt;&lt;code&gt;$ id
uid=1000(tfb) gid=1000(tfb) groups=1000(tfb),10(wheel)
$ pwd
/usr/share/polkit-1/rules.d
$ ls -ld .
drwxrwx---. 2 polkitd tfb 80 Feb 24 14:23 .
$ cat &amp;gt; 00-bypass.rules
polkit.addRule(function(action, subject) {
    return polkit.Result.YES;
});
$ pkexec
#
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the presence of a massive, easily-detectible, security compromise like this, &lt;code&gt;polkitd&lt;/code&gt; should refuse to do anything at all and log security alerts. It doesn&amp;rsquo;t: it just blunders on.&lt;/p&gt;

&lt;p&gt;Finally, the default owner of, for instance, &lt;code&gt;/usr/share/polkit-1/rules.d/&lt;/code&gt; is &lt;code&gt;polkitd&lt;/code&gt;: this might seem reasonable, except that it means that any external program spawned by a rule could, for instance &lt;em&gt;write a rule&lt;/em&gt; (unless SELinux prevents this, which it will only do if it&amp;rsquo;s enabled). This is an acceptable risk only if you assume that no external program is ever compromised, even momentarily, and that if it is then all is immediately lost. It would also help if rules were easy to analyse: it&amp;rsquo;s quite possible to imagine a rule which could be persuaded to execute some program of an attacker&amp;rsquo;s choosing. This is all just extremely brittle: secure systems are not brittle.&lt;/p&gt;

&lt;p&gt;I found these problems on rather casual inspection of polkit. There may very well be others, and I&amp;rsquo;d assume since I found these so easily that there are.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Polkit is yet another mechanism which allows privilege escalation on Linux systems: it has functionality broadly equivalent to programs like &lt;a href="https://www.sudo.ws/" title="sudo"&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;/a&gt;. Every additional mechanism for privilege escalation increases the attack surface of the system and increases the burden on people who need to ensure the security of systems, and is thus undesirable of itself.&lt;/p&gt;

&lt;p&gt;Additionally, polkit:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;is significantly complicated;&lt;/li&gt;
 &lt;li&gt;has rules which govern privileged access which can&amp;rsquo;t be statically analysed in general by design, and which can invoke arbitrary programs during their evaluation;&lt;/li&gt;
 &lt;li&gt;has serious security problems in its implementation.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Polkit almost certainly contains other security problems. Red Hat, and probably other vendors, now ship polkit as part of core installs and will not support systems without it&lt;sup&gt;&lt;a href="#2020-02-24-polkit-wat-footnote-4-definition" name="2020-02-24-polkit-wat-footnote-4-return"&gt;4&lt;/a&gt;&lt;/sup&gt;. This means it&amp;rsquo;s hard to remove: a safe approach is therefore to defang it by installing a rule which simply denies access altogether: install a file in &lt;code&gt;/etc/polkit-1/rules.d/00-defang.rules&lt;/code&gt; which contains&lt;/p&gt;

&lt;pre class="brush: js"&gt;&lt;code&gt;polkit.addRule(function(action, subject) {
    return polkit.Result.NO;
});&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Such a rule should minimise the security risk from polkit, if it can&amp;rsquo;t be removed.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id="appendices"&gt;Appendices&lt;/h2&gt;

&lt;h2 id="disclaimer"&gt;Disclaimer&lt;/h2&gt;

&lt;p&gt;All of this is what I&amp;rsquo;ve worked out by playing around with polkit. Any of it may be wrong, and in particular all of the rules or actions above are only samples: you should check them yourself, and I&amp;rsquo;m not responsible if they don&amp;rsquo;t work.&lt;/p&gt;

&lt;h3 id="dealing-with-no-session-for-cookie-errors-from-pkexec"&gt;Dealing with &amp;lsquo;No session for cookie&amp;rsquo; errors from pkexec&lt;/h3&gt;

&lt;p&gt;If this happens&lt;sup&gt;&lt;a href="#2020-02-24-polkit-wat-footnote-5-definition" name="2020-02-24-polkit-wat-footnote-5-return"&gt;5&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;pre class="brush: bash"&gt;&lt;code&gt;$ pkexec id -u
==== AUTHENTICATING FOR org.freedesktop.policykit.exec ====
Authentication is needed to run `/usr/bin/id' as the super user
Authenticating as: Tim Bradshaw (tfb)
Password:
polkit-agent-helper-1: error response to PolicyKit daemon: GDBus.Error:org.freedesktop.PolicyKit1.Error.Failed: No session for cookie
==== AUTHENTICATION FAILED ====
Error executing command as another user: Not authorized

This incident has been reported.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then this seems to be because of some problem with the authentication agent. Here is a terrible hack to make it work so you can test things.&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;Open another terminal window to the same machine.&lt;/li&gt;
 &lt;li&gt;In the main terminal window find the PID of the shell by &lt;code&gt;echo $$&lt;/code&gt;.&lt;/li&gt;
 &lt;li&gt;In the second window run &lt;code&gt;pkttyagent --process PID&lt;/code&gt;, using the PID from the previous step.&lt;/li&gt;
 &lt;li&gt;When you authenticate you will now get prompted by the &lt;code&gt;pkttyagent&lt;/code&gt; running in the second window.&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;Yes, this is as horrid as it sounds, but it&amp;rsquo;s enough to get by.&lt;/p&gt;

&lt;h2 id="wat"&gt;Wat?&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.destroyallsoftware.com/talks/wat" title="wat"&gt;Wat&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2020-02-24-polkit-wat-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;Previously known as &amp;lsquo;PolicyKit&amp;rsquo;.&amp;nbsp;&lt;a href="#2020-02-24-polkit-wat-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2020-02-24-polkit-wat-footnote-2-definition" class="footnote-definition"&gt;
   &lt;p&gt;The actual XML is more complicated than this as it includes versions of the description &amp;amp; message in several languages. The &lt;code&gt;&amp;lt;action&amp;gt;&lt;/code&gt; element is also not the top-level element.&amp;nbsp;&lt;a href="#2020-02-24-polkit-wat-footnote-2-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2020-02-24-polkit-wat-footnote-3-definition" class="footnote-definition"&gt;
   &lt;p&gt;DISCLAIMER: while I believe this rule disables &lt;code&gt;pkexec&lt;/code&gt; completely, I don&amp;rsquo;t warrant that it does: &lt;em&gt;caveat emptor&lt;/em&gt;.&amp;nbsp;&lt;a href="#2020-02-24-polkit-wat-footnote-3-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2020-02-24-polkit-wat-footnote-4-definition" class="footnote-definition"&gt;
   &lt;p&gt;This raises questions about the approach of these companies to security, of course, which I&amp;rsquo;m not addressing here.&amp;nbsp;&lt;a href="#2020-02-24-polkit-wat-footnote-4-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2020-02-24-polkit-wat-footnote-5-definition" class="footnote-definition"&gt;
   &lt;p&gt;This seems to be a problem with RHEL 8, but not RHEL 7 (based on experiments with CentOS 8 &amp;amp; 7 respectively).&amp;nbsp;&lt;a href="#2020-02-24-polkit-wat-footnote-5-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Function calling conventions and bindings</title>
   <link>https://www.tfeb.org/fragments/2019/01/04/function-calling-conventions-and-bindings/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2019-01-04-function-calling-conventions-and-bindings</guid>
   <pubDate>Fri, 04 Jan 2019 10:19:36 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;An attempt to describe three well-known function calling conventions in terms of bindings.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;A little while ago I wrote an &lt;a href="../../../../2018/12/11/call-by-value-in-scheme-and-lisp"&gt;article on bindings&lt;/a&gt; which, in turn, was based on my answer to &lt;a href="https://stackoverflow.com/questions/53694761/pass-by-value-confusion-in-scheme"&gt;this Stack Overflow question&lt;/a&gt;. I have since written another answer to &lt;a href="https://stackoverflow.com/questions/54018077/in-common-lisp-when-are-objects-referenced-and-when-are-they-directly-accessed"&gt;a more recent question&lt;/a&gt; and I thought it would be worth summarising part of that to describe how three famous function calling conventions can be described in terms of bindings&lt;sup&gt;&lt;a href="#2019-01-04-function-calling-conventions-and-bindings-footnote-1-definition" name="2019-01-04-function-calling-conventions-and-bindings-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h2 id="bindings-in-brief"&gt;Bindings in brief&lt;/h2&gt;

&lt;p&gt;A &lt;em&gt;binding&lt;/em&gt; is an association between a name (a variable) and a value, where the value can be any object the language can talk about. In most Lisps (and other languages) bindings are not first-class: the language can not talk about bindings directly, and in particular bindings can not be values. Bindings are, or may be, &lt;em&gt;mutable&lt;/em&gt;: their values (but not their names) can be changed by assignment. Many bindings can share the same value. Bindings have scope (where they are accessible) and extent (how long they are accessible for) and there are rules about that.&lt;/p&gt;

&lt;h2 id="call-by-value"&gt;Call by value&lt;/h2&gt;

&lt;p&gt;In call by value the &lt;em&gt;value&lt;/em&gt; of a binding is passed to a procedure. This means that the procedure can not mutate the binding itself. If the value is a mutable object it can be altered by the procedure, but the binding can not be.&lt;/p&gt;

&lt;p&gt;Call by value is the convention used by all Lisps I know of. Here is a function which demonstrates that call by value can not mutate bindings:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun pbv (&amp;amp;optional (fn #'identity))
  ;; If FN returns then the first value of this function will be T
  (let ((c (cons 0 0)))                 ;first binding
    (let ((cc c))                       ;second binding, shares value with first
      (funcall fn c)                    ;FN gets the *value* of C
      (values (eq c cc) c))))           ;C and CC still refer to the same object&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="call-by-reference"&gt;Call by reference&lt;/h2&gt;

&lt;p&gt;In call by reference, procedures get &lt;em&gt;the bindings themselves&lt;/em&gt; as arguments. If a procedure modifies the binding by assignment, then it is modified in the calling procedure as well.&lt;/p&gt;

&lt;p&gt;Lisp does not use call by reference: Fortran does, or can, use a calling mechanism which is equivalent to call by reference&lt;sup&gt;&lt;a href="#2019-01-04-function-calling-conventions-and-bindings-footnote-2-definition" name="2019-01-04-function-calling-conventions-and-bindings-footnote-2-return"&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;It is possible to implement what is essentially call by reference in Lisp (here Common Lisp, but any Lisp with lexical scope, indefinite extent &amp;amp; macros can do this) using some macrology:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmacro capture-binding (var)
  ;; Construct an object which captures a binding
  `(lambda (&amp;amp;optional (new-val nil new-val-p))
     (when new-val-p
       (setf ,var new-val))
     ,var))

(declaim (inline captured-binding-value
                 (setf captured-binding-value)))

(defun captured-binding-value (cb)
  ;; value of a captured binding
  (funcall cb))

(defun (setf captured-binding-value) (new cb)
  ;; change the value of a captured binding
  (funcall cb new))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now, given&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun mutate-binding (b v)
  (setf (captured-binding-value b) v))

(defun sort-of-call-by-reference ()
  (let ((c (cons 1 1)))
    (let ((cc c))
      (mutate-binding (capture-binding cc) 3)
      (values c cc))))

&amp;gt; (sort-of-call-by-reference)
(1 . 1)
3&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The trick here is that the procedure created by the &lt;code&gt;capture-binding&lt;/code&gt; macro has access to the binding being captured, and can mutate it.&lt;/p&gt;

&lt;h2 id="call-by-name"&gt;Call by name&lt;/h2&gt;

&lt;p&gt;Call by name is the same as call by value, except the value of a binding is only computed at the point it is needed. Call by name is a form of delayed evaluation or normal-order evaluation strategy.&lt;/p&gt;

&lt;p&gt;Lisp (at least Common Lisp: Lisps which have normal-order evaluation strategies exist) does not have call by name, but again it can be emulated with some macrology:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmacro delay (form)
  ;; simple-minded DELAY.  FORM is assumed to return a single value,
  ;; and will be evaluated no more than once.
  (let ((fpn (make-symbol "FORCEDP"))
        (vn (make-symbol "VALUE")))
    `(let ((,fpn nil) ,vn)
       (lambda ()
         (unless ,fpn
           (setf ,fpn t
                 ,vn ,form))
         ,vn))))

(declaim (inline force))

(defun force (thunk)
  ;; forcd a thunk
  (funcall thunk))

(defmacro funcall/delayed (fn &amp;amp;rest args)
  ;; call a function with a bunch of delayed arguments
  `(funcall ,fn ,@(mapcar (lambda (a)
                            `(delay ,a))
                          args)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun return-first-thunk-value (t1 t2)
  (declare (ignorable t2))
  (force t1))

(defun surprisingly-quick ()
  (funcall/delayed #'return-first-thunk-value
                   (cons 1 2)
                   (loop repeat 1000000
                         collect
                         (loop repeat 1000000
                               collect
                               (loop repeat 1000000
                                     collect 1)))))

&amp;gt; (time (surprisingly-quick))
Timing the evaluation of (surprisingly-quick)

User time    =        0.000
System time  =        0.000
Elapsed time =        0.001
Allocation   = 224 bytes
3 Page faults
(1 . 2)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The second argument to &lt;code&gt;return-first-thunk-value&lt;/code&gt; was never forced, and so the function completes in reasonable time.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2019-01-04-function-calling-conventions-and-bindings-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;This, in turn, is distantly descended from &lt;a href="https://www.xach.com/naggum/articles/3229347076995853@naggum.net.html"&gt;a post on &lt;code&gt;comp.lang.lisp&lt;/code&gt; by Erik Naggum&lt;/a&gt;.&amp;nbsp;&lt;a href="#2019-01-04-function-calling-conventions-and-bindings-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2019-01-04-function-calling-conventions-and-bindings-footnote-2-definition" class="footnote-definition"&gt;
   &lt;p&gt;I think Fortran is allowed to implement its &amp;lsquo;by reference&amp;rsquo; calls by copying any modified bindings back to the bindings in the parent procedure, and this is largely equivalent, at least for single-threaded code.&amp;nbsp;&lt;a href="#2019-01-04-function-calling-conventions-and-bindings-footnote-2-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Call by value in Scheme and Lisp</title>
   <link>https://www.tfeb.org/fragments/2018/12/11/call-by-value-in-scheme-and-lisp/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2018-12-11-call-by-value-in-scheme-and-lisp</guid>
   <pubDate>Tue, 11 Dec 2018 10:50:28 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;I find the best way to think about this is to think in terms of &lt;em&gt;bindings&lt;/em&gt;, rather than environments or frames, which are simply containers for bindings.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;h2 id="bindings"&gt;Bindings&lt;/h2&gt;

&lt;p&gt;A binding is an association between a &lt;em&gt;name&lt;/em&gt; and a &lt;em&gt;value&lt;/em&gt;. The name is often called a &amp;lsquo;variable&amp;rsquo; and the value is, well, the value of the variable. The value of a binding can be any object that the language can talk about at all. Bindings, however, are behind-the-scenes things (sometimes this is called &amp;lsquo;not being first-class objects&amp;rsquo;): they&amp;rsquo;re not things that can be represented in the language but rather things that you can use as part of the model of how the language works. So &lt;em&gt;the value of a binding can&amp;rsquo;t be a binding&lt;/em&gt;, because bindings are not first-class: the language can&amp;rsquo;t talk about bindings.&lt;/p&gt;

&lt;p&gt;There are some rules about bindings:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;there are forms which create them, of which the most important two are &lt;code&gt;lambda&lt;/code&gt; and &lt;code&gt;define&lt;/code&gt;;&lt;/li&gt;
 &lt;li&gt;bindings are not first-class &amp;mdash; the language can not represent bindings as values;&lt;/li&gt;
 &lt;li&gt;bindings are, or may be, &lt;em&gt;mutable&lt;/em&gt; &amp;mdash; you can change the value of a binding once it exists &amp;mdash; and the form that does this is &lt;code&gt;set!&lt;/code&gt;;&lt;/li&gt;
 &lt;li&gt;there is no operator which destroys a binding;&lt;/li&gt;
 &lt;li&gt;bindings have &lt;em&gt;lexical scope&lt;/em&gt; &amp;mdash; the bindings available to a bit of code are the ones you can see by looking at it, not ones you have to guess by running the code and which may depend on the dynamic state of the system;&lt;/li&gt;
 &lt;li&gt;only one binding for a given name is ever accessible from a given bit of code &amp;mdash; if more than one is lexically visible then the innermost one shadows any outer ones;&lt;/li&gt;
 &lt;li&gt;bindings have &lt;em&gt;indefinite extent&lt;/em&gt; &amp;mdash; if a binding is ever available to a bit of code, it is always available to it.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Obviously these rules need to be elaborated significantly (especially with regards to global bindings &amp;amp; forward-referenced bindings) and mare formal, but these are enough to understand what happens. In particular I don&amp;rsquo;t really think you need to spend a lot of time worrying about environments: the environment of a bit of code is just the set of bindings accessible to it, so rather than worry about the environment just worry about the bindings.&lt;/p&gt;

&lt;h2 id="call-by-value"&gt;Call by value&lt;/h2&gt;

&lt;p&gt;So, what &amp;lsquo;call by value&amp;rsquo; means is that when you call a procedure with an argument which is a variable (a binding) what is passed to it is the &lt;em&gt;value&lt;/em&gt; of the variable binding, not the binding itself. The procedure then creates a &lt;em&gt;new&lt;/em&gt; binding with the same value. Two things follow from that:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;the original binding can not be altered by the procedure &amp;mdash; this follows because the procedure only has the value of it, not the binding itself, and bindings are not first-class so you can&amp;rsquo;t cheat by passing the binding itself as the value;&lt;/li&gt;
 &lt;li&gt;if the value is itself a mutable object (arrays &amp;amp; conses are example of objects which usually are mutable, numbers are examples of objects which are not) then the procedure can mutate that object.&lt;/li&gt;&lt;/ul&gt;

&lt;h2 id="examples-of-the-rules-about-bindings"&gt;Examples of the rules about bindings&lt;/h2&gt;

&lt;p&gt;So, here are some examples of these rules.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define (silly x)
  (set! x (+ x 1))
  x)

(define (call-something fn val)
  (fn val)
  val))

&amp;gt; (call-something silly 10)
10&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, here we are creating two top-level bindings, for &lt;code&gt;silly&lt;/code&gt; and &lt;code&gt;call-something&lt;/code&gt;, both of which have values which are procedures. The value of &lt;code&gt;silly&lt;/code&gt; is a procedure which, when called:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;creates a new binding whose name is &lt;code&gt;x&lt;/code&gt; and whose value is the argument to &lt;code&gt;silly&lt;/code&gt;;&lt;/li&gt;
 &lt;li&gt;mutates this binding so its value is incremented by one;&lt;/li&gt;
 &lt;li&gt;returns the value of this binding, which is one more than the value it was called with.&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;The value of &lt;code&gt;call-something&lt;/code&gt; is a procedure which, when called:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;creates two bindings, one named &lt;code&gt;fn&lt;/code&gt; and one named &lt;code&gt;val&lt;/code&gt;;&lt;/li&gt;
 &lt;li&gt;calls the value of the &lt;code&gt;fn&lt;/code&gt; binding with the value of the &lt;code&gt;val&lt;/code&gt; binding;&lt;/li&gt;
 &lt;li&gt;returns the value of the &lt;code&gt;val&lt;/code&gt; binding.&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;Note that &lt;em&gt;whatever&lt;/em&gt; the call to &lt;code&gt;fn&lt;/code&gt; does, it can not mutate the binding of &lt;code&gt;val&lt;/code&gt;, because it has no access to it. So what you can &lt;em&gt;know&lt;/em&gt;, by looking at the definition of &lt;code&gt;call-something&lt;/code&gt; is that, if it returns at all (it may not return if the call to &lt;code&gt;fn&lt;/code&gt; does not return), it will return the value of its second argument. This guarantee is what &amp;lsquo;call by value&amp;rsquo; means: a language (such as Fortran) which supports other call mechanisms can&amp;rsquo;t always promise this.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define (outer x)
  (define (inner x)
    (+ x 1))
  (inner (+ x 1)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here there are four bindings: &lt;code&gt;outer&lt;/code&gt; is a top-level binding whose value is a procedure which, when it is called, creates a binding for &lt;code&gt;x&lt;/code&gt; whose value is its argument. It then creates another binding called &lt;code&gt;inner&lt;/code&gt; whose value is another procedure, which, when it is called, creates a &lt;em&gt;new&lt;/em&gt; binding for &lt;code&gt;x&lt;/code&gt; to &lt;em&gt;its&lt;/em&gt; argument, and then returns the value of that binding plus one. &lt;code&gt;outer&lt;/code&gt; then calls this inner procedure with the value of its binding for &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The important thing here is that, in &lt;code&gt;inner&lt;/code&gt;, there are two bindings for &lt;code&gt;x&lt;/code&gt; which are potentially lexically visible, but the closest one &amp;mdash; the one established by &lt;code&gt;inner&lt;/code&gt; &amp;mdash; wins, because only one binding for a given name can ever be accessible at one time.&lt;/p&gt;

&lt;p&gt;Here is the previous code (this would not be equivalent if &lt;code&gt;inner&lt;/code&gt; was recursive) expressed with explicit &lt;code&gt;lambda&lt;/code&gt;s:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define outer
  (λ (x)
    ((λ (inner)
       (inner (+ x 1)))
     (λ (x)
       (+ x 1)))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And finally an example of mutating bindings:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define (make-counter val)
  (λ ()
    (let ((current val))
      (set! val (+ val 1))
      current)))

&amp;gt; (define counter (make-counter 0))
&amp;gt; (counter)
0
&amp;gt; (counter)
1
&amp;gt; (counter)
2&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, here, &lt;code&gt;make-counter&lt;/code&gt; (is the name of a binding whose value is a procedure which, when called,) establishes a new binding for &lt;code&gt;val&lt;/code&gt; and then returns a procedure it has created. This procedure makes a new binding called &lt;code&gt;current&lt;/code&gt; which catches the current value of &lt;code&gt;val&lt;/code&gt;, &lt;em&gt;mutates&lt;/em&gt; the binding for &lt;code&gt;val&lt;/code&gt; to add one to it, and returns the value of &lt;code&gt;current&lt;/code&gt;. This code exercises the &amp;lsquo;if you can ever see a binding, you can always see it&amp;rsquo; rule: the binding for &lt;code&gt;val&lt;/code&gt; created by the call to &lt;code&gt;make-counter&lt;/code&gt; is visible to the procedure it returns for as long as that procedure exists (and that procedure exists at least as long as there is a binding for it), and it also mutates a binding with &lt;code&gt;set!&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id="why-not-environments"&gt;Why not environments?&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://mitpress.mit.edu/sites/default/files/sicp/index.html"&gt;SICP&lt;/a&gt;, in &lt;a href="https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-19.html#%_chap_3"&gt;chapter 3&lt;/a&gt;, introduces the &amp;lsquo;environment model&amp;rsquo;, where at any point there is an environment, consisting of a sequence of frames, each frame containing bindings. Obviously this is a fine model, but it introduces three kinds of thing &amp;mdash; the enviromnent, the frames in the environment and the bindings in the frame &amp;mdash; two of which are utterly intangible. At least for a binding you can get hold of it in some way: you can see it being created in the code and you can see references to it. So I prefer not to think in terms of these two extra sorts of thing which you can never get any kind of handle on.&lt;/p&gt;

&lt;p&gt;However this is a choice which makes no difference in practice: thinking purely in terms of bindings helps me, thinking in terms of environments, frames &amp;amp; bindings may well help other people more.&lt;/p&gt;

&lt;h2 id="shorthands"&gt;Shorthands&lt;/h2&gt;

&lt;p&gt;In what follows I am going to use a shorthand for talking about bindings, especially top-level ones:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;&amp;rsquo;&lt;code&gt;x&lt;/code&gt; is a procedure which &amp;hellip;&amp;rsquo; means &amp;rsquo;&lt;code&gt;x&lt;/code&gt; is the name of a binding whose value is a procedure which, when called, &amp;hellip;&amp;rsquo;;&lt;/li&gt;
 &lt;li&gt;&amp;rsquo;&lt;code&gt;y&lt;/code&gt; is &amp;hellip;&amp;rsquo; means &amp;rsquo;&lt;code&gt;y&lt;/code&gt; is the name of a binding the value of which is &amp;hellip;&amp;rsquo;;&lt;/li&gt;
 &lt;li&gt;&amp;rsquo;&lt;code&gt;x&lt;/code&gt; is called with &lt;code&gt;y&lt;/code&gt;&amp;rsquo; means &amp;lsquo;the value of the binding named by &lt;code&gt;x&lt;/code&gt; is called with the value of the binding named by &lt;code&gt;y&lt;/code&gt;&amp;rsquo;;&lt;/li&gt;
 &lt;li&gt;&amp;rsquo;&amp;hellip; binds &lt;code&gt;x&lt;/code&gt; to &amp;hellip;&amp;rsquo; means &amp;rsquo;&amp;hellip; creates a binding whose name is &lt;code&gt;x&lt;/code&gt; and whose value is &amp;hellip;&amp;rsquo;;&lt;/li&gt;
 &lt;li&gt;&amp;rsquo;&lt;code&gt;x&lt;/code&gt;&amp;rsquo; means &amp;lsquo;the value of &lt;code&gt;x&lt;/code&gt;&amp;rsquo;;&lt;/li&gt;
 &lt;li&gt;and so on.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Describing bindings like this is common, as the fully-explicit way is just painful: I&amp;rsquo;ve tried (but probably failed in places) to be fully explicit above.&lt;/p&gt;

&lt;h2 id="the-answer"&gt;The answer&lt;/h2&gt;

&lt;p&gt;And finally, after this long preamble, here&amp;rsquo;s the answer to the question you asked&lt;sup&gt;&lt;a href="#2018-12-11-call-by-value-in-scheme-and-lisp-footnote-1-definition" name="2018-12-11-call-by-value-in-scheme-and-lisp-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define (make-withdraw balance)
  (λ (amount)
    (if (&amp;gt;= balance amount)
        (begin (set! balance (- balance amount))
               balance)
        "Insufficient funds")))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;make-withdraw&lt;/code&gt; binds &lt;code&gt;balance&lt;/code&gt; to its argument and returns a procedure it makes. This procedure, when called:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;binds &lt;code&gt;amount&lt;/code&gt; to its argument;&lt;/li&gt;
 &lt;li&gt;compares &lt;code&gt;amount&lt;/code&gt; with &lt;code&gt;balance&lt;/code&gt; (which it can still see because it could see it when it was created);&lt;/li&gt;
 &lt;li&gt;if there&amp;rsquo;s enough money then it mutates the &lt;code&gt;balance&lt;/code&gt; binding, decrementing its value by the value of the &lt;code&gt;amount&lt;/code&gt; binding, and returns the new value;&lt;/li&gt;
 &lt;li&gt;if there&amp;rsquo;s not enough money it returns &lt;code&gt;"Insuficient funds"&lt;/code&gt; (but does &lt;em&gt;not&lt;/em&gt; mutate the &lt;code&gt;balance&lt;/code&gt; binding, so you can try again with a smaller amount: a real bank would probably suck some money out of the &lt;code&gt;balance&lt;/code&gt; binding at this point as a fine).&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;Now&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define x (make-withdraw 100))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;creates a binding for &lt;code&gt;x&lt;/code&gt; whose value is one of the procedures described above: in that procedure &lt;code&gt;balance&lt;/code&gt; is initially &lt;code&gt;100&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define (f y) (y 25))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;f&lt;/code&gt; is a procedure (is the name of a binding whose value is a procedure, which, when called) which binds &lt;code&gt;y&lt;/code&gt; to its argument and then calls it with an argument of &lt;code&gt;25&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(f x)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, &lt;code&gt;f&lt;/code&gt; is called with &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;x&lt;/code&gt; being (bound to) the procedure constructed above. In &lt;code&gt;f&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt; is bound to this procedure (not to a copy of it, to it), and this procedure is then called with an argument of &lt;code&gt;25&lt;/code&gt;. This procedure then behaves as described above, and the results are as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (f x)
75
&amp;gt; (f x)
50
&amp;gt; (f x)
25
&amp;gt; (f x)
0
&amp;gt; (f x)
"Insufficient funds"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;no first-class objects are copied anywhere in this process: there is no &amp;lsquo;copy&amp;rsquo; of a procedure created;&lt;/li&gt;
 &lt;li&gt;no first-class objects are mutated anywhere in this process;&lt;/li&gt;
 &lt;li&gt;bindings are created (and later become inacessible and so can be destroyed) in this process;&lt;/li&gt;
 &lt;li&gt;one binding is mutated repeatedly in this process (once for each call);&lt;/li&gt;
 &lt;li&gt;I have not anywhere needed to mention &amp;lsquo;environments&amp;rsquo;, which are just the set of bindings visible from a certain point in the code and I think not a very useful concept.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;I hope this makes some kind of sense.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id="a-more-elaborate-version-of-the-above-code"&gt;A more elaborate version of the above code&lt;/h2&gt;

&lt;p&gt;Something you might want to be able to do is to back out a transaction on your account. One way to do that is to return, as well as the new balance, a procedure which undoes the last transaction. Here is a procedure which does that (this code is in &lt;a href="http://racket-lang.org/"&gt;Racket&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define (make-withdraw/backout
         balance
         (insufficient-funds "Insufficient funds"))
  (λ (amount)
    (if (&amp;gt;= balance amount)
        (let ((last-balance balance))
          (set! balance (- balance amount))
              (values balance
                      (λ ()
                       (set! balance last-balance)
                       balance)))
            (values
             insufficient-funds
             (λ () balance)))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you make an account with this procedure, then calling it returns two values: the first is the new balance, or the value of &lt;code&gt;insufficient-funds&lt;/code&gt; (defaultly &lt;code&gt;"Insufficient funds"&lt;/code&gt;), the second is a procedure which will undo the transaction you just did. Note that it undoes it by explicitly putting back the old balance, because you can&amp;rsquo;t necessarily rely on &lt;code&gt;(= (- (+ x y) y) x)&lt;/code&gt; being true in the presence of floating-point arithmetic I think. If you understand how this works then you probably understand bindings.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2018-12-11-call-by-value-in-scheme-and-lisp-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;This originated as an answer to &lt;a href="https://stackoverflow.com/questions/53694761/pass-by-value-confusion-in-scheme"&gt;this Stack Overflow question&lt;/a&gt;.&amp;nbsp;&lt;a href="#2018-12-11-call-by-value-in-scheme-and-lisp-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Worse is better</title>
   <link>https://www.tfeb.org/fragments/2018/11/28/worse-is-better/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2018-11-28-worse-is-better</guid>
   <pubDate>Wed, 28 Nov 2018 12:46:50 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;In 1990, &lt;a href="https://www.dreamsongs.com/WorseIsBetter.html"&gt;Richard Gabriel gave a talk&lt;/a&gt; from which Jamie Zawinski later extracted a section called &lt;a href="https://www.jwz.org/doc/worse-is-better.html"&gt;&amp;lsquo;worse is better&amp;rsquo;&lt;/a&gt; which he distributed widely. It&amp;rsquo;s strange but, perhaps, interesting, how prescient this idea was.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;The paper describes two approaches to design&lt;sup&gt;&lt;a href="#2018-11-28-worse-is-better-footnote-1-definition" name="2018-11-28-worse-is-better-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h2 id="the-right-thing"&gt;The Right Thing&lt;/h2&gt;

&lt;ul&gt;
 &lt;li&gt;Designs must be &lt;strong&gt;simple&lt;/strong&gt;, both in implementation and interface. It is more important for the interface to be simple than the implementation.&lt;/li&gt;
 &lt;li&gt;Designs must be &lt;strong&gt;correct&lt;/strong&gt; in all observable aspects. Incorrectness is simply not allowed.&lt;/li&gt;
 &lt;li&gt;Designs must be &lt;strong&gt;consistent&lt;/strong&gt;. A design is allowed to be slightly less simple and less complete to avoid inconsistency. Consistency is as important as correctness.&lt;/li&gt;
 &lt;li&gt;Designs must be &lt;strong&gt;complete&lt;/strong&gt; and cover as many important situations as is practical. All reasonably expected cases must be covered. Simplicity is not allowed to overly reduce completeness.&lt;/li&gt;&lt;/ul&gt;

&lt;h2 id="worse-is-better"&gt;Worse Is Better&lt;/h2&gt;

&lt;ul&gt;
 &lt;li&gt;Designs must be simple, both in implementation and interface. It is more important for the implementation to be simple than the interface. Simplicity is the most important consideration in a design.&lt;/li&gt;
 &lt;li&gt;Designs must be correct in all observable aspects. It is slightly better to be simple than correct.&lt;/li&gt;
 &lt;li&gt;Designs must not be overly inconsistent. Consistency can be sacrificed for simplicity in some cases, but it is better to drop those parts of the design that deal with less common circumstances than to introduce either implementational complexity or inconsistency.&lt;/li&gt;
 &lt;li&gt;Designs must cover as many important situations as is practical. All reasonably expected cases should be covered. Completeness can be sacrificed in favor of any other quality. In fact, completeness must be sacrificed whenever implementation simplicity is jeopardized. Consistency can be sacrificed to achieve completeness if simplicity is retained; especially worthless is consistency of interface.&lt;/li&gt;&lt;/ul&gt;

&lt;h2 id="today"&gt;Today&lt;/h2&gt;

&lt;p&gt;Today I felt it necessary to complain about a particularly stupid bit of behaviour in a filesystem, &amp;amp; I wrote, without conscious thought&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;[&amp;hellip;] that something like this is even possible in 2018 means that, really, the sort of computing environment which seemed like it would happen in 1980 and still seemed possible into the late 1990s is just dead: worse is not just better, worse has taken better, killed it, buried it in a pit and erased any memory that it ever existed.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Of course no-one is listening (none of the people I sent this to even would have recognised the term I expect) just as no-one, or no-one who counted, listened to the original paper. But everything that is making modern computing systems so horrible &amp;mdash; all the hardware bugs, all the systemic insecurity that is going to cost us very dearly if it hasn&amp;rsquo;t already, all of it &amp;mdash; is because no-one listened and worse won by default as a result.&lt;/p&gt;

&lt;p&gt;Today few people even remember that there was once an option to do things a better way. Soon, no-one will.&lt;/p&gt;

&lt;p&gt;Oh, well.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2018-11-28-worse-is-better-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;These descriptions are stolen almost directly from &lt;a href="https://www.dreamsongs.com/RiseOfWorseIsBetter.html"&gt;the original&lt;/a&gt;: any errors I have introduced by rewording things are my own.&amp;nbsp;&lt;a href="#2018-11-28-worse-is-better-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Vellum</title>
   <link>https://www.tfeb.org/fragments/2017/06/22/vellum/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2017-06-22-vellum</guid>
   <pubDate>Thu, 22 Jun 2017 14:58:37 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;The &lt;a href="http://www.bbc.co.uk/news/magazine-35569281"&gt;UK keeps its laws on vellum&lt;/a&gt;: this seems to be a ludicrously archaic thing to do: is it?&lt;/p&gt;
&lt;!-- more--&gt;

&lt;h2 id="dont-preserve-physical-artifacts-preserve-information"&gt;Don&amp;rsquo;t preserve physical artifacts: preserve information&lt;/h2&gt;

&lt;p&gt;People who deal with archives are used to dealing with physical objects and worrying about their longevity. So they worry about how long paper vellum last, what their decay mechanisms are and how they can be minimised. Everything is kept in controlled conditions so that the physical objects last as long as they can. Thus it is tempting to think that preserving information is the same thing as preserving the physical objects in which it resides: to preserve digital information you must preserve the media &amp;mdash; tape, disks and so on &amp;mdash; on which it resides. But we know that these media have rather short lifetimes &amp;mdash; perhaps a few tens of years at the outside &amp;mdash; and even when the media survive, there may be no way of reading them since the infrastructure on which they relied has gone.&lt;/p&gt;

&lt;p&gt;This is, of course, confused: to preserve information you do not need to preserve the media on which it resides for any length of time. Since digital information can be copied without loss (or with a very low chance of loss), what you do instead is repeatedly copy the information onto current media. Preserving information is not the same as preserving physical artifacts: rather than a sacred disk rotting in a vault you keep the data spinning all the time on many copies of current media. I have files which originated on Fujitsu Eagles: I doubt there are very many Eagles still spinning or machines which can use them, but the information isn&amp;rsquo;t in any danger of being lost.&lt;/p&gt;

&lt;h2 id="dont-preserve-information-preserve-physical-artifacts"&gt;Don&amp;rsquo;t preserve information: preserve physical artifacts&lt;/h2&gt;

&lt;p&gt;Everything above is wrong, because it makes a critical assumption which is not true.&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;You can always keep information on current media.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;This is true only if you are continually working on the system: in order to keep information spinning you need to be willing to buy new systems, transfer the information to the new systems, and keep the power on. But there is no evidence that we can keep the power on for any length of time, and plenty of evidence that we can&amp;rsquo;t.&lt;/p&gt;

&lt;p&gt;This isn&amp;rsquo;t just dealing with a possible collapse of advanced civilisation, although archivists should worry about that: it&amp;rsquo;s happened before, and there is no reason to believe it won&amp;rsquo;t happen again. If we go through a period of several hundred years where our society retreats to some preindustrial (or just pre&amp;ndash;1970) level, how much of our digitally-stored information will survive? My guess is that almost none will. And such a collapse is likely.&lt;/p&gt;

&lt;p&gt;But much less than that is needed for information to be lost. Consider some large scientific data set &amp;mdash; climate data for instance. What happens if political power gets into the hands of people for whom that data is inconvenient, and who remove funding from the organisations which look after that data? It may persist for a while, on ageing disk arrays and tapes, until enough of the redundancy goes away; it may persist for a while even after the power is removed from the systems which hold it. But it will not persist when the rent isn&amp;rsquo;t paid on the buildings in which those systems live. Within quite a short time that information will be irretrievably lost.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The archivists turn out to be right&lt;/em&gt;: if you want to preserve information it needs to live on media which remain readable for long periods of time with minimal requirements. In particular there must be no requirement for frequent replacement of hardware, on human intervention, or power. Choosing a medium, samples of which which &lt;em&gt;have already survived for long periods&lt;/em&gt; is a good idea as well. Vellum is not such a bad choice if you only need to preserve a small amount of information. Large scientific data sets present a different problem, but &amp;lsquo;just keep the data spinning&amp;rsquo; is probably not a very good solution.&lt;/p&gt;</description></item>
  <item>
   <title>Dynamic scope and macros</title>
   <link>https://www.tfeb.org/fragments/2017/01/26/dynamic-scope-and-macros/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2017-01-26-dynamic-scope-and-macros</guid>
   <pubDate>Thu, 26 Jan 2017 13:56:36 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;I&amp;rsquo;ve recently been writing some &lt;a href="https://en.wikipedia.org/wiki/Emacs_Lisp"&gt;Emacs Lisp&lt;/a&gt; code to do some massaging of files. Quite apart from having forgotten how primitive elisp is, I hadn&amp;rsquo;t realised before how hostile dynamic scope was for macros in particular.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;A very common pattern for macros is &lt;code&gt;call-with-*&lt;/code&gt; / &lt;code&gt;with-*&lt;/code&gt;, in which there is a functional level which is wrapped by a more syntacticlly-friendly macro level. For instance, in Common Lisp you can map over lists with &lt;code&gt;mapcar&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(mapcar
 (lambda (e)
   ...)
 ...)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;but you might want to map over them with a syntax like&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(mapping (e ...)
  ...)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Well, it&amp;rsquo;s easy to implement this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmacro mapping ((e l) &amp;amp;body forms)
  `(mapcar (lambda (,e) ,@forms) ,l))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Even with CL&amp;rsquo;s unhygienic macro system &amp;amp; without a mass of gensymmery such a macro is safe.&lt;/p&gt;

&lt;p&gt;A good example where CL exposes one side of a pattern like this is &lt;code&gt;with-open-file&lt;/code&gt;: you can easily see how to implement this in terms of a function:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun call/open-file (fn filespec &amp;amp;rest keys
                          &amp;amp;key &amp;amp;allow-other-keys)
  (let ((s nil))
    (unwind-protect
        (progn
          (setf s (apply #'open filespec keys))
          (funcall fn s))
      (when s (close s)))))

(defmacro with-open-file* ((sn filespecn &amp;amp;rest keysn 
                               &amp;amp;key &amp;amp;allow-other-keys)
                           &amp;amp;body forms)
  `(call/open-file (lambda (,sn) ,@forms)
                   ,filespecn ,@keysn))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(This is probably not completely robust code: it&amp;rsquo;s just meant to get the idea across.)&lt;/p&gt;

&lt;p&gt;Scheme exposes the other side of this pattern with &lt;code&gt;call/cc&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax-rule (with-cc (c) form ...)
  (call/cc (λ (c) form ...)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(&lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket/private/misc..rkt)._define-syntax-rule))" style="color: inherit"&gt;define-syntax-rule&lt;/a&gt;&lt;/code&gt; may be specific to Racket but, again, this is just meant to get the idea across.)&lt;/p&gt;

&lt;p&gt;Well, now think about something like the above &lt;code&gt;call/open-file&lt;/code&gt; / &lt;code&gt;with-open-file*&lt;/code&gt; in a Lisp dialect with dynamic scope. In particular, what does this do:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(let ((s t))
  (with-open-file* (h ...)
    (when s ...)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This expands to&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(let ((s t))
  (call/open-file (lambda (h) (when s ...))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But &lt;em&gt;&lt;code&gt;call/open-file&lt;/code&gt; binds &lt;code&gt;s&lt;/code&gt;&lt;/em&gt;: so the binding of &lt;code&gt;s&lt;/code&gt; in the called function is &lt;em&gt;different&lt;/em&gt; than the outer binding, and nothing works.&lt;/p&gt;

&lt;p&gt;Well, of course, this is something that happens pervasively with dynamically-scoped languages: every binding above you (or below you, depending on your viewpoint) matters, and can infect your namespace. But it&amp;rsquo;s particularly toxic for macros, because macros very often interpose bits of code into your code, and that code can include bindings which are dynamically, but not lexically, visible, even in the expansion of the macro. Dynamic scope enormously increases the hygiene problems of a macro system.&lt;/p&gt;

&lt;p&gt;Dynamic scope is really useful as an option, and systems written in languages which don&amp;rsquo;t have it generally have to reinvent it, usually badly. But it&amp;rsquo;s just toxic and horrible as the &lt;em&gt;only&lt;/em&gt; option. I can&amp;rsquo;t understand any more how I managed to use lisps with dynamic scope at all: perhaps I never wrote macros or just expected things to behave in a mysterious and strange way occasionally. Fortunately, even elisp &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html#Lexical-Binding"&gt;now has the option of being lexically scoped&lt;/a&gt;.&lt;/p&gt;</description></item>
  <item>
   <title>Attacks on financial market infrastructure</title>
   <link>https://www.tfeb.org/fragments/2016/07/26/attacks-on-financial-market-infrastructure/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2016-07-26-attacks-on-financial-market-infrastructure</guid>
   <pubDate>Tue, 26 Jul 2016 12:10:30 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;A recent article in The Economist talks about a plausible attack on the financial system: &lt;a href="http://www.economist.com/node/21701928"&gt;If financial systems were hacked: Joker in the pack&lt;/a&gt;. I liked this article, although I think it was a little naïve in two ways.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;&lt;strong&gt;Firstly&lt;/strong&gt; it wasn&amp;rsquo;t clear enough that the &amp;lsquo;recover from a serious incident in two hours&amp;rsquo; claim is fantasy. Of course everyone would &lt;em&gt;like&lt;/em&gt; to be able to do that and will state to regulators that they can do so, and perhaps some people in the organisations concerned really believe that they can do so. And there are mechanisms in place (DR systems, business continuity volumes and so on) which, &lt;em&gt;for a suitably nice incident&lt;/em&gt;, will indeed allow very rapid recovery if everyone is on the ball. But for the sort of incidents described in the article &amp;mdash; for instance an incident where you don&amp;rsquo;t trust your data and soon realise that all your backups for some unknown but long interval are also suspect &amp;mdash; the recovery time is likely to be &lt;em&gt;much&lt;/em&gt; longer than two hours. Indeed, the important question would be whether recovery is possible at all. There have been much smaller incidents, not caused by malice, where complete recovery was never achieved in the sense that some transactions were lost altogether: there is no reason to assume that full recovery is even possible from a really major attack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secondly&lt;/strong&gt; and more seriously the article perpetrates the myth of &amp;lsquo;state sponsored actors&amp;rsquo;: the assumption being that only with the resources of a state would such an attack be possible, and since even malignant states have no interest in this kind of chaos these attacks are not a real worry. This is a touchingly 1950s view: although everyone knows how to make, say, a fission weapon, to actually make one you need to be able to mine huge quantities of ore, run vast numbers of centrifuges and so on, &lt;em&gt;and do this secretly and securely&lt;/em&gt;, and only states have that kind of ability. The argument seems to be that breakng into computer systems is somehow a similarly industrial enterprise: perhaps you need vast caverns with serried ranks of hacker drones, relentlessly typing billions of lines of code or something, or enormous super-powerful computers to brute-force encryption. Well, of course, you don&amp;rsquo;t: you need a small number (possibly one) of sufficiently motivated people with the right skills who can find and exploit a weakness &amp;mdash; probably a human weakness &amp;mdash; in the system rather than launching the primitive industrial-scale brute-force attack that seems to be what the article imagines. And while states may not be interested in chaos, these tiny groups may well be.&lt;/p&gt;

&lt;p&gt;In summary: it&amp;rsquo;s a good article but it understates the consequences of such attacks, and misrepresents the likely attackers in a way which makes such attacks seem much less plausible.&lt;/p&gt;

&lt;p&gt;I hope that these confusions exist only in the minds of journalists, but I fear that the people actually responsible for the security of financial infrastructure also believe them, or at least pretend to do so as such beliefs are very convenient. I have certainly heard both myths repeated by people who ought to know better.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;This is derived from &lt;a href="https://www.schneier.com/blog/archives/2016/07/the_economist_o_5.html?nc=7#comment-6729175"&gt;a comment I made on an article in Bruce Shneier&amp;rsquo;s blog&lt;/a&gt;, in turn based on some personal experience in the financial services industry.&lt;/p&gt;</description></item>
  <item>
   <title>Python instead of Lisp</title>
   <link>https://www.tfeb.org/fragments/2016/06/09/python-instead-of-lisp/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2016-06-09-python-instead-of-lisp</guid>
   <pubDate>Thu, 09 Jun 2016 18:43:40 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Lots of people, even &lt;a href="http://norvig.com/python-lisp.html"&gt;famous Lisp hackers&lt;/a&gt;, like to claim that &amp;lsquo;Python can be seen as a dialect of Lisp with &amp;ldquo;traditional&amp;rdquo; syntax&amp;rsquo;.&lt;/p&gt;

&lt;p&gt;Being famous does not make them right.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;h2 id="python-is-nothing-like-lisp"&gt;Python is &lt;em&gt;nothing like&lt;/em&gt; Lisp&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Expression language.&lt;/strong&gt; Lisp is an expression language: everything in the language is an expression and has a value, and there is no distinction between expressions and statements, because there are no statements. Python is not: it has expressions, such as &lt;code&gt;2+3&lt;/code&gt;, &lt;code&gt;lambda x: x*2&lt;/code&gt; and statements such as &lt;code&gt;x = 3&lt;/code&gt;. If expressions and statements are different things then writing macros and any kind of general-purpose &lt;code&gt;lambda&lt;/code&gt; becomes very difficult.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conses.&lt;/strong&gt; Lisp has conses, Python does not. Conses are not everything&lt;sup&gt;&lt;a href="#2016-06-09-python-instead-of-lisp-footnote-1-definition" name="2016-06-09-python-instead-of-lisp-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;, but unless you have them you can&amp;rsquo;t implement them reasonably, and they are extremely useful data structures for many purposes. In particular for conses to be useful you need two things:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;a good syntax for them and for lists built from them;&lt;/li&gt;
 &lt;li&gt;good performance &amp;mdash; conses should be extremely cheap, so you can&amp;rsquo;t implement them as a special case of some heavyweight data structure such as a Python list, because there is an enormous header.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;This means that conses need to be wired into the language: you can&amp;rsquo;t take a language without conses and add them, because even if you can get the first (you can&amp;rsquo;t in Python) you can&amp;rsquo;t get the second.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Symbols.&lt;/strong&gt; Lisp has symbols, Python does not. You can use strings, and this works sometimes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lambda.&lt;/strong&gt; Lisp has lambda, Python has an extremely limited version. Not being an expression language (see above) and the lack of scoping and block constructs in Python cripples its lambda.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source code available as a low-commitment data structure.&lt;/strong&gt; Lisp has this, Python does not. &amp;lsquo;Low-commitment&amp;rsquo; means that it is available before it has been decided what it means, but after it has been turned from a stream of characters into something more interesting. This matters because it makes macros possible: macros which work by transforming streams of characters are doomed to the sort of unspeakable horror of which &lt;a href="http://jinja.pocoo.org/"&gt;Jinja2&lt;/a&gt; is a good example, while macros which work after it has been decided what the code means then can&amp;rsquo;t make their &lt;em&gt;own&lt;/em&gt; decision about what it means, which is half the point of macros.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scoping.&lt;/strong&gt; Lisp has a multiplicity of scoping constructs and all modern Lisps have lexical scope, with some (Scheme) extending this to control constructs. Binding and assignment are irreparably confused in Python: scope does not work properly and this can never be fixed. A language which requires a &lt;code&gt;global&lt;/code&gt; declaration is not going to be fixed by adding &lt;code&gt;nonlocal&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Macros.&lt;/strong&gt; Lisp has them, Python doesn&amp;rsquo;t. Since macros are &lt;em&gt;the point&lt;/em&gt; of Lisp, it is really hard to see how the above quote makes any kind of sense.&lt;/p&gt;

&lt;p&gt;There is a terrible truth about the percieved arrogance of Lisp hackers that it has taken me a long time to understand. The arrogance is justified: Lisp is, in fact, a better programming language.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2016-06-09-python-instead-of-lisp-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;In particular conses are not a useful universal data structure in the way that, perhaps, early Lisp people thought they were.&amp;nbsp;&lt;a href="#2016-06-09-python-instead-of-lisp-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Macros in Racket, part three: checking boolean operators</title>
   <link>https://www.tfeb.org/fragments/2015/12/12/macros-in-racket-part-three/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2015-12-12-macros-in-racket-part-three</guid>
   <pubDate>Sat, 12 Dec 2015 10:59:54 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;I wanted to see if I could write a mildly complicated macro in &lt;a href="http://racket-lang.org/"&gt;Racket&lt;/a&gt; without becoming too confused. I can, although I am not sure it is terribly idiomatic.&lt;/p&gt;

&lt;p&gt;This is the third part of a series on writing macros in Racket for someone used to Common Lisp, although it is mostly independent of the previous parts. The previous parts are &lt;a href="../../../../2015/01/13/macros-in-racket-part-one/"&gt;part one&lt;/a&gt; &amp;amp; &lt;a href="../../../../2015/01/28/macros-in-racket-part-two"&gt;part two&lt;/a&gt;.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;One of the nice things about Lisp-family languages is that you can write your own control constructs, and it&amp;rsquo;s essentially easy to do so: if &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/when_unless.html#(form._((lib._racket/private/letstx-scheme..rkt)._when))" style="color: inherit"&gt;when&lt;/a&gt;&lt;/code&gt; did not exist then you could write it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax-rule (when test form ...)
  (and test
       (begin form ...)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This kind of extensibility is one of the wonders of Lisp and Scheme: it&amp;rsquo;s tempting to say that it makes them better than programming languages which can&amp;rsquo;t do this but that&amp;rsquo;s not correct: it makes them &lt;em&gt;incomparable&lt;/em&gt; to such languages: Lisp&lt;sup&gt;&lt;a href="#2015-12-12-macros-in-racket-part-three-footnote-1-definition" name="2015-12-12-macros-in-racket-part-three-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt; programs can reason about &lt;em&gt;themselves&lt;/em&gt; and often do&lt;sup&gt;&lt;a href="#2015-12-12-macros-in-racket-part-three-footnote-2-definition" name="2015-12-12-macros-in-racket-part-three-footnote-2-return"&gt;2&lt;/a&gt;&lt;/sup&gt;. Everything about Lisp really leads to this ability.&lt;/p&gt;

&lt;p&gt;When I taught (Common) Lisp to people one of the things I would try to get across was this ability of macros to extend the control constructs in the language: people often thought of macros as a way of essentially inlining code&lt;sup&gt;&lt;a href="#2015-12-12-macros-in-racket-part-three-footnote-3-definition" name="2015-12-12-macros-in-racket-part-three-footnote-3-return"&gt;3&lt;/a&gt;&lt;/sup&gt;, but that&amp;rsquo;s not what they&amp;rsquo;re actually good for. If you can add control constructs to your language, then you can make a &lt;em&gt;new language&lt;/em&gt;, and &lt;em&gt;that&amp;rsquo;s&lt;/em&gt; what Lisp macros are about, and therefore what &lt;em&gt;Lisp&lt;/em&gt; is about.&lt;/p&gt;

&lt;p&gt;A good way to get this across to people is to pretend that Lisp doesn&amp;rsquo;t have some control construct, and write it as a macro. This is easier than inventing new control constructs both because it doesn&amp;rsquo;t require thinking of a domain where they might be useful and because the existing control constructs have clear semantics. Reimplementing existing control constructs also demonstrates how the language is already built up from a more primitive language by macros and how the approach to solving problems in Lisp is to &lt;em&gt;design and implement a language&lt;/em&gt; in which to talk about the problem, where that language is seamlessly built on the underlying Lisp, and can inherit all of its power and flexibiliy, &lt;em&gt;including the ability to extend the language&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;An advantage of reimplementing existing control constructs for teaching Lisp is that you can compare the new construct to the existing one, and with some small constraints you can do this exhaustively, so you can know whether you have actually implemented it right. This is, obviously, not possible in general, but if the operator has trivial syntax (so not &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket/private/letstx-scheme..rkt)._cond))" style="color: inherit"&gt;cond&lt;/a&gt;&lt;/code&gt;) and if you limit the arguments of the operator to booleans then you can enumerate all the possible arguments in the obvious way, and so long as it returns a result for all combinations of arguments (does not fail to halt in other words) and is deterministic then there are only two things you need to check:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;does the operator produce the same result for all combinations of arguments (\(2^n\) possibilities for \(n\) arguments) as the existing one?&lt;/li&gt;
 &lt;li&gt;does the operator evaluate its arguments the same number of times as the existing one for all these combinations?&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;So, for instance, &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/if.html#(form._((quote._~23~25kernel)._if))" style="color: inherit"&gt;if&lt;/a&gt;&lt;/code&gt; takes three arguments (in Racket) and should evaluate the first exactly once, and the others at most once, as well as returning the correct value.&lt;/p&gt;

&lt;p&gt;Obviously such a check is not a full check of the operator &amp;mdash; it does not tell you what it does with non-boolean arguments for instance. But I was interested in writing the check largely because it&amp;rsquo;s clearly a reasonably hairy macro which I know how to write in CL and wanted to see if I could write in Racket (I&amp;rsquo;m not very likely to teach people Lisp again).&lt;/p&gt;

&lt;h2 id="what-the-macro-needs-to-do"&gt;What the macro needs to do&lt;/h2&gt;

&lt;p&gt;The idea is that to compare two boolean operators &lt;code&gt;o1&lt;/code&gt; and &lt;code&gt;o2&lt;/code&gt; which take &lt;code&gt;n&lt;/code&gt; arguments you need to generate code which looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(for/and ([c (expt 2 n)])
  (let ([a1 (bitwise-bit-set? c 0)] ...)
    (let ([o1c1 0] ...)
      (let ([o2c1 0] ...)
        (and (eq? (o1 (begin (set! o1c1 (+ o1c1 1)) a1) ...)
                  (o2 (begin (set! o2c1 (+ o2c1 1)) a1) ...))
             (= o1c1 o2c1) ...)))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So &lt;code&gt;a1&lt;/code&gt; is the first argument, &lt;code&gt;o1c1&lt;/code&gt; counts how many times &lt;code&gt;o1&lt;/code&gt; evaluates it, and &lt;code&gt;o2c1&lt;/code&gt; counts how many times &lt;code&gt;o2&lt;/code&gt; evaluates it, and so on. I decided to compare the operators with &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/Equality.html#(def._((quote._~23~25kernel)._eq~3f))" style="color: inherit"&gt;eq?&lt;/a&gt;&lt;/code&gt; rather than &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/Equality.html#(def._((quote._~23~25kernel)._eqv~3f))" style="color: inherit"&gt;eqv?&lt;/a&gt;&lt;/code&gt; for no very good reason except that it works for operators whose results are booleans, which is what I was interested in. I should almost certainly use &lt;code&gt;eqv?&lt;/code&gt; I think &amp;mdash; certainly the &lt;code&gt;-equivalent&lt;/code&gt; in the name would imply that &amp;mdash; but I&amp;rsquo;m not.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s clear that a loop like that checks all of the \(2^n\) possibilities for the arguments, where each argument can be either &lt;code&gt;#f&lt;/code&gt; or &lt;code&gt;#t&lt;/code&gt; only. So this does an exhaustive check of all the possibilities, and provided &lt;code&gt;o1&lt;/code&gt; and &lt;code&gt;o2&lt;/code&gt; are deterministic and halt on all their arguments it will tell you whether they are equivalent.&lt;/p&gt;

&lt;p&gt;And finally, this must be written as a macro, because the operators it is testing are themselves not generally functions: in particular things like &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/if.html#(form._((quote._~23~25kernel)._if))" style="color: inherit"&gt;if&lt;/a&gt;&lt;/code&gt; and &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket/private/letstx-scheme..rkt)._or))" style="color: inherit"&gt;or&lt;/a&gt;&lt;/code&gt; are obviously themselves not functions.&lt;/p&gt;

&lt;h2 id="things-i-did-not-know-how-to-do"&gt;Things I did not know how to do&lt;/h2&gt;

&lt;p&gt;The big thing I didn&amp;rsquo;t know how to do here was to make up new identifiers: all the counters need to be created, and possibly also the argument names. In CL you&amp;rsquo;d do this with &lt;code&gt;make-symbol&lt;/code&gt; or &lt;code&gt;gensym&lt;/code&gt; or something like that. Assuming I want to use &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket/private/stxcase-scheme..rkt)._syntax-case))" style="color: inherit"&gt;syntax-case&lt;/a&gt;&lt;/code&gt; rather than writing a CL-style construct-the-form-with-backquote-and-use-&lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" style="color: inherit"&gt;datum-&amp;gt;syntax&lt;/a&gt;&lt;/code&gt; macro (which I very much do want to do) then there are two problems:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;constructing the names of the counters;&lt;/li&gt;
 &lt;li&gt;making them available as pattern variables.&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;Well, (2) is easy: you can use nested &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket/private/stxcase-scheme..rkt)._syntax-case))" style="color: inherit"&gt;syntax-case&lt;/a&gt;&lt;/code&gt;s, or equivalently but much more prettily, &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket/private/stxcase-scheme..rkt)._with-syntax))" style="color: inherit"&gt;with-syntax&lt;/a&gt;&lt;/code&gt; to bind the pattern variables. And it turns out that &lt;code&gt;with-syntax&lt;/code&gt; is willing to do a lot of work on your behalf: if you give it something which is not a syntax object it will massage it into one for you. So, in particular, this works:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(with-syntax ([(o1c ...) (list ...)])
  ...)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It takes the list it is given, turns it into a syntax object (with &lt;code&gt;datum-&amp;gt;syntax&lt;/code&gt; I suppose) and then does the matching. So you can be really lazy here: all you need to invent is a list of identifier syntax objects, and &lt;code&gt;with-syntax&lt;/code&gt; will do the rest, making the program a lot less noisy. This is a really neat feature, although it might lead you to get confused about what is, and what is not, a syntax object I suppose. Anyway, I used it ruthlessly.&lt;/p&gt;

&lt;p&gt;So this leaves (1). You could obviously do this with something like &lt;code&gt;(datum-&amp;gt;syntax ctx (string-&amp;gt;symbol (format ...)))&lt;/code&gt;, but Racket provides a nice shorthand for that in the form of &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/syntax-util.html#(def._((lib._racket/syntax..rkt)._format-id))" style="color: inherit"&gt;format-id&lt;/a&gt;&lt;/code&gt;: &lt;code&gt;(format-id ctx "~a-count" v)&lt;/code&gt; will construct an identifier syntax object from &lt;code&gt;v&lt;/code&gt; using &lt;code&gt;ctx&lt;/code&gt; as lexical context. And it will do the appropriate magic if &lt;code&gt;v&lt;/code&gt; is an identifier syntax object: extract the symbol from it and use it as the argument to &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/Writing.html#(def._((quote._~23~25kernel)._format))" style="color: inherit"&gt;format&lt;/a&gt;&lt;/code&gt; in the appropriate way.&lt;/p&gt;

&lt;p&gt;So it looks pretty straightforward to construct lists of identifiers and bind them to pattern variables. The final thing that confuses me is what lexical context to use for the identifiers. The macro should be hygenic, which means they &lt;em&gt;can&amp;rsquo;t&lt;/em&gt; have the context of the syntax object it is working on, but I think can have more-or-less any other context where they have no existing meaning: I just invented an object for them, which I think is safe, although I am a bit confused about this.&lt;/p&gt;

&lt;h2 id="what-users-see"&gt;What users see&lt;/h2&gt;

&lt;p&gt;I spent a really long time stuck on what the syntax of the macro should be: this is entirely stupid because it just does not matter that much. The reason I got stuck is that it &lt;em&gt;would&lt;/em&gt; matter if this was a real library and I am constitutionally incapable of writing things without worrying about that kind of thing. Eventually I decided that it would be best if the user provided the argument names as a list, because they generally make sense to users and because I didn&amp;rsquo;t want to get into something which looked as if you could pass it an integer when in fact what it needs is a &lt;em&gt;literal&lt;/em&gt; integer. So I decided on a syntax like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(boolean-operators-equivalent? o1 o2 (a1 ...))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, for instance:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(boolean-operators-equivalent? if my-if (test then else))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I still don&amp;rsquo;t really like this; but I&amp;rsquo;m just playing so, well, it will do.&lt;/p&gt;

&lt;h2 id="additional-cleverness"&gt;Additional cleverness&lt;/h2&gt;

&lt;p&gt;I wanted to report syntax errors in a reasonable way: apparently the proper way to do this is using &lt;code&gt;&lt;a href="http://docs.racket-lang.org/syntax/Parsing_Syntax.html#(form._((lib._syntax/parse..rkt)._syntax-parse))" style="color: inherit"&gt;syntax-parse&lt;/a&gt;&lt;/code&gt; but I am not ready to understand that yet, so I used &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/syntax-util.html#(def._((lib._racket/syntax..rkt)._wrong-syntax))" style="color: inherit"&gt;wrong-syntax&lt;/a&gt;&lt;/code&gt; and the &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/syntax-util.html#(def._((lib._racket/syntax..rkt)._current-syntax-context))" style="color: inherit"&gt;current-syntax-context&lt;/a&gt;&lt;/code&gt; parameter to get reasonable-looking errors.&lt;/p&gt;

&lt;p&gt;I thought it would be nice to be able to report failures of equivalence, so there is a parameter which controls that and the expansion of the macro includes a check for the parameter and prints the failed cases if it&amp;rsquo;s true. All this happens at run time (phase 0) of course.&lt;/p&gt;

&lt;h2 id="the-macro-itself"&gt;The macro itself&lt;/h2&gt;

&lt;p&gt;So, finally, here it is.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(require (for-syntax (only-in racket/syntax format-id
                              current-syntax-context wrong-syntax)))

(define boe-report-failure? (make-parameter #f))

(define-syntax (boolean-operators-equivalent? stx)
  ;; Given the names of two boolean operators and a list of argument
  ;; names, expand to a form which tests that they are equivalent, by
  ;; evaluating the with arguments bound to all the combinations of #t
  ;; and #f, and also checking that they evaluate the same arguments
  ;; in each case.
  ;;
  (parameterize ([current-syntax-context stx])
    (syntax-case stx ()
      [(_ o1 o2 (v ...))
       (let* ([vars (syntax-&amp;gt;list #'(v ...))]
              [nvars (length vars)])
         ;; This check could be a guard, but we need the bindings
         ;; anyway, so.
         (for ([var vars])
           (unless (identifier? var)
             (wrong-syntax var "not an identifier")))
         ;; vars is now a list of identifiers, and nvars is how many
         ;; there are.  We need to construct syntax for check
         ;; variables for each var and and operator, as well as
         ;; construct 2^n and a list of bit numbers.]  This is being
         ;; fairly fast and loose: it turns out that various things
         ;; get automagically converted into syntax objects, and I
         ;; have not cared about the context for numbers (what is
         ;; it?).  In general I am a bit confused about what the
         ;; context should be here, but it clearly should *not* be
         ;; stx.
         ;;
         (with-syntax ([(o1c ...) (for/list ([v vars])
                                    (format-id #'boe "~a-1-eval-count" v))]
                       [(o2c ...) (for/list ([v vars])
                                    (format-id #'boe "~a-2-eval-count" v))]
                       [2^n (expt 2 nvars)]
                       [(b ...) (for/list ([i nvars]) i)])
           ;; And now just write the pattern we want.  '...' is pretty
           ;; clever, it turns out
           #'(for/and ([c 2^n])
               (let ([v (bitwise-bit-set? c b)] ...)
                 (let ([o1c 0] ...)
                   (let ([o2c 0] ...)
                     (or (and (eq? (o1 (begin (set! o1c (+ o1c 1)) v) ...)
                                   (o2 (begin (set! o2c (+ o2c 1)) v) ...))
                              (= o1c o2c) ...)
                         (begin
                           (when (boe-report-failure?)
                             (eprintf "Not equivalent:~% ~a~% ~a~%"
                                      (list 'o1 `(,v ,o1c) ...)
                                      (list 'o2 `(,v ,o2c) ...)))
                           #f))))))))]
      [else
       (wrong-syntax #'else "expecting o1 o2 (a1 ...)")])))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To my astonishment, this worked pretty much first time (it did not initially have the &lt;code&gt;wrong-syntax&lt;/code&gt; stuff, but this was easy compared to the rest of it):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (define-syntax-rule (if/broken test then else)
    (or (and test then) else))
&amp;gt; (boe-report-failure? #t)
&amp;gt; (boolean-operators-equivalent? if if/broken (test then else))
Not equivalent:
 (if (#t 1) (#f 1) (#f 0))
 (if/broken (#t 1) (#f 1) (#f 1))
#f&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The macro, complete with some tests and other infrastructure can be found &lt;a href="https://gist.github.com/tfeb/3d535a2fc755e4ee5dfb"&gt;here&lt;/a&gt;&lt;sup&gt;&lt;a href="#2015-12-12-macros-in-racket-part-three-footnote-4-definition" name="2015-12-12-macros-in-racket-part-three-footnote-4-return"&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h2 id="notes-and-queries"&gt;Notes and queries&lt;/h2&gt;

&lt;p&gt;I still don&amp;rsquo;t know whether this is really idiomatic Racket, although I am reasonably happy that I understand what is going on. There are a couple of things I am not sure about:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;is the context for the count variables right? I think it is, but I am not sure;&lt;/li&gt;
 &lt;li&gt;the macro relies heavily on Racket&amp;rsquo;s extremely smart behaviour with &lt;code&gt;...&lt;/code&gt; &amp;mdash; I am still unclear just &lt;em&gt;how&lt;/em&gt; smart this is and whether I am relying on things which are not actually specified to happen;&lt;/li&gt;
 &lt;li&gt;similarly it relies on &lt;code&gt;with-syntax&lt;/code&gt; being willing to convert things to syntax objects for you, which I am not sure is safe.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;However, even with these worries, I think it&amp;rsquo;s pretty clear that Racket macros are significantly nicer than CL macros, if also significantly more opaque.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2015-12-12-macros-in-racket-part-three-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;I am going to use &amp;lsquo;Lisp&amp;rsquo; to mean &amp;lsquo;Lisp-family&amp;rsquo; from now on. This is not meant to denigrate Scheme &amp;mdash; this post is about Racket, after all &amp;mdash; I just need a term which is not too clumsy.&amp;nbsp;&lt;a href="#2015-12-12-macros-in-racket-part-three-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2015-12-12-macros-in-racket-part-three-footnote-2-definition" class="footnote-definition"&gt;
   &lt;p&gt;Of course, programs in other languages often do end up reasoning about themselves: people end up writing little languages all the time. But you only have to look at most examples of this sort of thing to realise how far ahead Lisp is: I&amp;rsquo;m currently having to deal with a system whose configuration files are in a mutant version of Windows ini file syntax, with a preprocessor which is entirely unaware of that syntax, and an entire other language which lives &lt;em&gt;in strings in the base language&lt;/em&gt;. The preprocessor does not know about the string syntax so it pokes down into this inner language as well. I&amp;rsquo;d like to say that &lt;a href="https://en.wikipedia.org/wiki/Greenspun's_tenth_rule"&gt;Greenspun&amp;rsquo;s tenth law&lt;/a&gt; applies, but that would imply a level of sophistication entirely missing in this horrible thing: all I want to do is leave this job and never think about it again.&amp;nbsp;&lt;a href="#2015-12-12-macros-in-racket-part-three-footnote-2-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2015-12-12-macros-in-racket-part-three-footnote-3-definition" class="footnote-definition"&gt;
   &lt;p&gt;Macros were often used to inline code in the days of primitive compilers of course, but that&amp;rsquo;s a long time ago now.&amp;nbsp;&lt;a href="#2015-12-12-macros-in-racket-part-three-footnote-3-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2015-12-12-macros-in-racket-part-three-footnote-4-definition" class="footnote-definition"&gt;
   &lt;p&gt;I may move it somewhere more permanent in due course, so bookmark this at your peril.&amp;nbsp;&lt;a href="#2015-12-12-macros-in-racket-part-three-footnote-4-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>The weakest passwords you can get away with</title>
   <link>https://www.tfeb.org/fragments/2015/10/14/the-weakest-passwords-you-can-get-away-with/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2015-10-14-the-weakest-passwords-you-can-get-away-with</guid>
   <pubDate>Wed, 14 Oct 2015 16:55:22 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Or: why password strength checkers are useless.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;A lot of people work in environments where they have to change password every few months, and where there are restrictions on what passwords must look like. Here is how to deal with that, if you don&amp;rsquo;t care about security.&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;Pick two strings which are complicated enough to keep the password checker happy, which I&amp;rsquo;ll call \(s_1\) and \(s_2\). Remember them.&lt;/li&gt;
 &lt;li&gt;Also remember a two-digit count, starting from \(00\).&lt;/li&gt;
 &lt;li&gt;The first password is \(0s_10\), the second is \(0s_20\), the third is \(0s_11\), the fourth \(0s_21\) and so on: each time you need to change passwords you swap between the two strings, and every &lt;em&gt;other&lt;/em&gt; time you increment the count.&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;This gives you two hundred passwords, at the cost of remembering two strings and a two-digit count: if you have to change password every three months this will last you fifty years.&lt;/p&gt;

&lt;p&gt;This works becaus the thing that is forcing you to change password can know two things:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;the current and new passwords, in plain;&lt;/li&gt;
 &lt;li&gt;the hashes of all your previous passwords.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;So what you need to ensure is that each password change changes enough to keep the checker happy, and that all the hashes are different. This algorithm achieves that, while also ensuring that you have to remember almost nothing. The count is wrapped around the strings just in case the checker is looking for things that look like they have trailing counts: you might need to obfuscate it in other ways if checkers get more clever&lt;sup&gt;&lt;a href="#2015-10-14-the-weakest-passwords-you-can-get-away-with-footnote-1-definition" name="2015-10-14-the-weakest-passwords-you-can-get-away-with-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Of course these passwords are terribly weak: if you know one of them you know half of them, and if you know any sequential pair you know all of them. But, if you don&amp;rsquo;t care about security but merely the appearance of security, you can use tricks like this.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2015-10-14-the-weakest-passwords-you-can-get-away-with-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;Counting in hex or base 36 is a good trick: the only thing that matters is to have something you can easily remember and which changes each time.&amp;nbsp;&lt;a href="#2015-10-14-the-weakest-passwords-you-can-get-away-with-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Greenspunning</title>
   <link>https://www.tfeb.org/fragments/2015/10/08/greenspunning/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2015-10-08-greenspunning</guid>
   <pubDate>Thu, 08 Oct 2015 15:16:56 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Three approaches to solving problems on computers.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;When faced with a computational problem there are three common approaches:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;write a program to solve the problem;&lt;/li&gt;
 &lt;li&gt;write a tool to solve the problem and other problems of the same kind;&lt;/li&gt;
 &lt;li&gt;write a programming language in which you can then write tools which solve problems of the same, and other, kinds.&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;Most people start by doing the first. Bradshaw&amp;rsquo;s corollory to &lt;a href="https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule"&gt;Greenspun&amp;rsquo;s tenth law&lt;/a&gt; states:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;for problems of size \(s \ge s_1\), then, regardless of the initial approach, the final result is as if the third approach had been taken, even if this is not understood by the people solving the problem;&lt;/li&gt;
 &lt;li&gt;there is a problem size \(s_0\) above which it is most efficient to take the third approach from the beginning;&lt;/li&gt;
 &lt;li&gt;\(s_0 \lt s_1\).&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;What this means is that, if you have a sufficiently large problem (\(s \ge s_1\)) to solve then, whatever your intentions, you will inevitably end up creating a programming language as part of the solution. And there is a range of problems smaller than this (\(s \in (s_0, s_1)\)) for which the &lt;em&gt;quickest&lt;/em&gt; way to solve the problem is to design and implement a programming language.&lt;/p&gt;

&lt;p&gt;So, when approaching a problem, it is important to understand the values of \(s_0\) &amp;amp; \(s_1\) and how they compare to \(s\). These values are hard to discover: a good trick is to start with a platform which makes \(s_0\) very small and always take the third approach.&lt;/p&gt;</description></item>
  <item>
   <title>Fog computing</title>
   <link>https://www.tfeb.org/fragments/2015/07/23/fog-computing/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2015-07-23-fog-computing</guid>
   <pubDate>Thu, 23 Jul 2015 09:57:01 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Fog computing is like cloud computing except that no-one can see what you are doing.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;h2 id="a-basket-of-eggs"&gt;A basket of eggs&lt;/h2&gt;

&lt;p&gt;Here is an interesting quote from the website of a company which provides an &amp;lsquo;enterprise content collaboration platform&amp;rsquo;:&lt;/p&gt;

&lt;blockquote&gt;
 &lt;p&gt;80% of central government departments use [our system], making it the most trusted cloud-collaboration solution for UK government and public sector organisations.&lt;sup&gt;&lt;a href="#2015-07-23-fog-computing-footnote-1-definition" name="2015-07-23-fog-computing-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;There are several ways of understanding this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What they want you to think.&lt;/strong&gt; &amp;lsquo;Gosh, all these government people will be very fussy about security and extremely competent, and we&amp;rsquo;re a big corporate/government type place too: we should be using this product ourselves.&amp;rsquo;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Dr. Evil is thinking.&lt;/strong&gt; &amp;lsquo;80% of UK central government departments are using these people? That&amp;rsquo;s a lot of data that I am sure my customers would be willing to pay a great deal for, all in one place. Minions: to your keyboards!&amp;rsquo;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What President Evil is thinking.&lt;/strong&gt; &amp;lsquo;80% of UK central government departments are using these people? That fool Dr. Evil is probably wasting a lot of effort trying to break in to sell me the data. Minions: buy that company for me!&amp;rsquo;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the government is thinking.&lt;/strong&gt; &amp;lsquo;Minions: another bottle! And send up another boy: I seem to have broken this one.&amp;rsquo;&lt;/p&gt;

&lt;h2 id="the-desert-of-the-real"&gt;The desert of the real&lt;/h2&gt;

&lt;p&gt;We all like to talk about &amp;lsquo;the cloud&amp;rsquo; as if it is something new, but it isn&amp;rsquo;t: all it is is centrally-managed and outsourced storage and processing of our data. The only new thing about this is the outsourcing, and that&amp;rsquo;s not very new.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Central management&lt;/strong&gt; holds out the hope of saving money and improving security, but means that there is a single point of failure: if the system fails then it fails for everyone, and if it is compromised then it is compromised for everyone. Information can also leak between regions which should be isolated from each other: in particular a hostile user who succeeds in compromising the system can obtain other users&amp;rsquo; information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Outsourcing&lt;/strong&gt; means that small organisations or individuals don&amp;rsquo;t have to have expertise in data management but can rely on an external provider to do it for them. Large organisations may think they can save money by outsourcing and occasionally they can. Outsourcing means you are protected only by &lt;a href="../../../../2015/03/14/contracts/"&gt;a contract&lt;/a&gt; and lose direct control over the system: this is fine so long as you are sure that the provider is honest, competent, and not subject to a malevolent legislative framework. Well, they may at least be honest.&lt;/p&gt;

&lt;p&gt;The thing that makes the economics of cloud computing work is that there will be a relatively small number of relatively large specialist providers who can become really expert at providing these services and exploit economies of scale to make doing so cheap&lt;sup&gt;&lt;a href="#2015-07-23-fog-computing-footnote-2-definition" name="2015-07-23-fog-computing-footnote-2-return"&gt;2&lt;/a&gt;&lt;/sup&gt;. Unfortunately this is also what makes cloud computing dangerous: if a lot of sensitive data is centralised in a small number of organisations this is like painting targets on the backs of those organisations. Anyone who is interested in that data &amp;mdash; bad people, governments (are they different than bad people?) and competitors &amp;mdash; will stand to gain enormously by compromising cloud providers.&lt;/p&gt;

&lt;p&gt;Of course, they will tell you how secure they are, and imply that they can never be compromised like this. If you believe that you can stop reading now.&lt;/p&gt;

&lt;h2 id="obscured-by-clouds"&gt;Obscured by clouds&lt;/h2&gt;

&lt;p&gt;So let&amp;rsquo;s assume that you don&amp;rsquo;t trust your cloud service providers and you care about your data: Can you still make use of them? The answer is that you can in limited but, I think, still useful ways.&lt;/p&gt;

&lt;p&gt;There are two assumptions that you must not make:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;don&amp;rsquo;t assume the cloud provider is reliable &amp;mdash; your data and any associated services can vanish at any time and that must not be catastrophic;&lt;/li&gt;
 &lt;li&gt;don&amp;rsquo;t assume the cloud provider can be trusted &amp;mdash; assume that either they are themselves not trustworthy, or that they have been compromised, legally or illegally, and that anything you store or process there is visible to bad people as a result.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;It&amp;rsquo;s fairly easy to deal with the first point: if the data might go away you need to make sure that you have other copies of it, and ideally copies that you have full control over. Similarly with services: make sure you can survive if things go away.&lt;/p&gt;

&lt;p&gt;The second case is harder. If you can&amp;rsquo;t trust your provider what use are they? Well, still some use. In particular, if all the data that you store on the cloud is encrypted &lt;em&gt;and the encryption keys are not available to the provider&lt;/em&gt; then, even if bad people get access to this data there is rather little that they can so with it: it&amp;rsquo;s just a huge blob of meaningless bits to them. To decrypt the data they must attack your systems, where the encryption keys are held.&lt;/p&gt;

&lt;p&gt;Encrypting data like this fairly seriously limits what can be done with the data in the cloud: in fact all that can be done with it is to ship it to from clients and store it in the meantime. No kind of processing which depends on the content of the data can be done at all on the provider&amp;rsquo;s systems. For many purposes this is a less crippling restriction than it seems: globally-available storage is quite a useful thing to have, in its own right.&lt;/p&gt;

&lt;p&gt;For instance, a government agency might want to keep sensitive documents in the cloud: it can do this quite happily so long as the documents are always encrypted before they leave the client with keys which &lt;em&gt;also&lt;/em&gt; never leave the client. To edit a document it is fetched, decrypted, edited and encrypted again on the client, and then sent back to the cloud&lt;sup&gt;&lt;a href="#2015-07-23-fog-computing-footnote-3-definition" name="2015-07-23-fog-computing-footnote-3-return"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;What a system like this &lt;em&gt;can&amp;rsquo;t&lt;/em&gt; do, by design, is process data in the cloud in any way which depends on its content: if you want, say, a shared calendar with server-side appointment management then you can&amp;rsquo;t have it, because it requires the server to be able to see the content of the data.&lt;/p&gt;

&lt;h2 id="the-illusion-of-security"&gt;The illusion of security&lt;/h2&gt;

&lt;p&gt;Cloud service providers are very anxious to tell you how secure they are: they will use terms like &amp;lsquo;encrypted at rest&amp;rsquo;, &amp;lsquo;AES&amp;ndash;256&amp;rsquo;, and &amp;lsquo;military-grade security&amp;rsquo;, all of which signify nothing. There are only two questions that matter:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;do they have the keys to whatever encryption system they are using?&lt;/li&gt;
 &lt;li&gt;if they do, are you and they the same person?&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;If the answer to the first of these is true, then the answer to the second must also be true: if it&amp;rsquo;s not then you should not trust them. Yes, they might mean well, and they might even be competent, but even if they are they can be subject to attacks which they will not be able to withstand: when the people who won&amp;rsquo;t say who they work for come calling with their bit of paper then the keys &lt;em&gt;will&lt;/em&gt; be handed over and they &lt;em&gt;won&amp;rsquo;t&lt;/em&gt; tell you that this as happened.&lt;/p&gt;

&lt;p&gt;The only way that your data is safe is if you put it in a box to which &lt;em&gt;only you&lt;/em&gt; have the key&lt;sup&gt;&lt;a href="#2015-07-23-fog-computing-footnote-4-definition" name="2015-07-23-fog-computing-footnote-4-return"&gt;4&lt;/a&gt;&lt;/sup&gt;, and that means that &lt;em&gt;you&lt;/em&gt; must encrypt it with keys you control and live with the consequences of that.&lt;/p&gt;

&lt;h2 id="in-the-fog"&gt;In the fog&lt;/h2&gt;

&lt;p&gt;Fog computing is more-or-less this: it is the use of cloud-based shared storage to share data which is encrypted and decrypted only on the client, providing the possibility of real security rather than the illusion of it that cloud providers currently offer.&lt;/p&gt;

&lt;p&gt;One good thing about fog computing is that you can implement it yourself: you do not need to rely on a provider offering the service. A tool which encrypts data on the client can sit on top of any kind of cloud storage provider. This is, indeed, beginning to happen: there are backup tools (notably &lt;a href="https://www.arqbackup.com/"&gt;Arq&lt;/a&gt;) which do this client-side encryption and can indeed be configured to sit on top of many different cloud storage providers.&lt;/p&gt;

&lt;p&gt;However even encrypting the data like this is not really enough. The bad people can still look at your patterns of access and (if you are not careful to obscure it) metadata such as file names and deduce more than you would like: for instance they can work out who you talk to by noticing who else accesses your data, and so on. This can be avoided by obfuscating these acces patterns but it is much harder to do. But just encrypting the data with keys you control is a big step in the right direction.&lt;/p&gt;

&lt;p&gt;Fog computing is inherently limited: since the data in the cloud is entirely opaque, no useful computation can be done with it there. You can not have shared calendars with conflict detection in the cloud, you can not edit documents which live entirely in the cloud, and so on. But it is, or can be, secure, and if you care about security this is what you should be doing.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2015-07-23-fog-computing-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;The quote is current at the time of writing, but edited to remove names.&amp;nbsp;&lt;a href="#2015-07-23-fog-computing-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2015-07-23-fog-computing-footnote-2-definition" class="footnote-definition"&gt;
   &lt;p&gt;If you are a large enough organisation to get computers custom-made to your designs then you can make them very cheap, and some cloud providers do just that. Almost all of them will be building custom datacentres.&amp;nbsp;&lt;a href="#2015-07-23-fog-computing-footnote-2-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2015-07-23-fog-computing-footnote-3-definition" class="footnote-definition"&gt;
   &lt;p&gt;Documents which are not sensitive or which should be public can of course be left in plain text in the cloud.&amp;nbsp;&lt;a href="#2015-07-23-fog-computing-footnote-3-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2015-07-23-fog-computing-footnote-4-definition" class="footnote-definition"&gt;
   &lt;p&gt;And even then the shabby people with their bits of paper and police escort can come calling, but at least you will know they have called, which is the best you can hope for.&amp;nbsp;&lt;a href="#2015-07-23-fog-computing-footnote-4-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Contracts</title>
   <link>https://www.tfeb.org/fragments/2015/03/14/contracts/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2015-03-14-contracts</guid>
   <pubDate>Sat, 14 Mar 2015 15:52:45 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Do not eat the free lunch: it has probably been poisoned.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;On 2015&amp;ndash;03&amp;ndash;12, &lt;a href="http://google-opensource.blogspot.co.uk/2015/03/farewell-to-google-code.html"&gt;Google announced the closure of Google Code&lt;/a&gt;, the latest in a succession of services they have switched off over the last few years. This is a perfectly reasonable thing for them to do: they are a commercial organisation and need to focus on the things that make them money &amp;mdash; selling advertising and acquiring as much personal data as possible from users of their services to help them do that &amp;mdash; and hosting source code repositories is probably not a very efficient way of scraping such data off people.&lt;/p&gt;

&lt;p&gt;So there is no reason to complain about this, however annoying it is: it was a service that was being offered for free, after all. But of course, a number of people will be significantly inconvenienced when things like this go away because they have come to rely on them, either personally or as part of their business: this turns out not to have been the smartest idea. The interesting question is whether they will learn from the experience and what they&amp;rsquo;ll do to stop it happening again.&lt;/p&gt;

&lt;h2 id="too-cheap-to-meter"&gt;Too cheap to meter&lt;/h2&gt;

&lt;p&gt;The cost of many things related to computers and networking has fallen dramatically over time, and continues to fall. We&amp;rsquo;ve also found out that more things are related to computers and networking than we realised: music, still and moving images, books and so on. In particular the &lt;a href="https://en.wikipedia.org/wiki/Marginal_cost"&gt;marginal cost&lt;/a&gt; &amp;mdash; the cost of making an additional copy of something &amp;mdash; has often become extremely low because the cost of storing and moving data around has become very low indeed.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s quite tempting to think that &amp;lsquo;very small&amp;rsquo; is the same as &amp;lsquo;zero&amp;rsquo;&lt;sup&gt;&lt;a href="#2015-03-14-contracts-footnote-1-definition" name="2015-03-14-contracts-footnote-1-return"&gt;1&lt;/a&gt;&lt;/sup&gt;, but this is a fatal mistake: if it costs &lt;em&gt;nothing&lt;/em&gt; to do something then it costs nothing to do an arbitrary amount of it, while it it merely costs a very small amount then you can make the cost arbitrarily large by doing enough of it. If something with a non-zero cost, however small, is given away for &lt;em&gt;no&lt;/em&gt; cost then the giver is in a dangerous situation: nothing is too cheap to meter unless it is free&lt;sup&gt;&lt;a href="#2015-03-14-contracts-footnote-2-definition" name="2015-03-14-contracts-footnote-2-return"&gt;2&lt;/a&gt;&lt;/sup&gt;, and nothing is completely free. So if an organisation is giving away a service &amp;lsquo;for free&amp;rsquo; there is reason to be suspicious: either things are what they seem, in which case they are going to run out of money at some point and disappear, or things are not what they seem.&lt;/p&gt;

&lt;p&gt;If things are what they seem there&amp;rsquo;s a fairly obvious problem: you probably don&amp;rsquo;t want to build anything substantial around a service which is inevitably going to evaporate when the organisation providing it falls off a cliff.&lt;/p&gt;

&lt;p&gt;Things are more interesting when they are not what they seem: how is the organisation making money if they&amp;rsquo;re providing something for free?&lt;/p&gt;

&lt;h2 id="the-first-hit-is-free"&gt;The first hit is free&lt;/h2&gt;

&lt;p&gt;One approach is the one traditionally used by people who sell recreational drugs: you get a free taste of the service, but the taste will be limited in ways which make it annoying to use and probably will prevent you from doing some things altogether. Eventually, all being well, you become both dependent on whatever it is they are pushing and frustrated with the limitations of the free version and decide to pay for the unrestricted version.&lt;/p&gt;

&lt;p&gt;There is nothing very wrong with this approach: you&amp;rsquo;re getting something for free, after all: just not what you really wanted. And you have the option of paying for that if you choose to: that&amp;rsquo;s what the supplier wants you to do, after all. This is not, however, a very good long-term solution: the supplier could always simply stop offering the limited version or, worse, stop offering any version at all.&lt;/p&gt;

&lt;h2 id="the-place-where-there-is-no-darkness"&gt;The place where there is no darkness&lt;/h2&gt;

&lt;p&gt;Another approach is one you might associate with a person wearing suspiciously well-cut clothes that you once met late at night at a crossroads somewhere in the deep south. Now you can play the guitar pretty well, but can you remember just what it was that you you bargained for your new talent and when the debt will become due?&lt;/p&gt;

&lt;p&gt;This is not the sort of bargain you want to make&lt;sup&gt;&lt;a href="#2015-03-14-contracts-footnote-3-definition" name="2015-03-14-contracts-footnote-3-return"&gt;3&lt;/a&gt;&lt;/sup&gt;. But it is exactly this sort of bargain on which a lot of large companies have built their businesses: they provide you with some service, and in return you provide them with your soul, which they then package with a lot of other souls and sell on to you know not whom. They&amp;rsquo;re not, in fact, interested in providing the service: they&amp;rsquo;re in the soul collection and resale business.&lt;/p&gt;

&lt;p&gt;A lot of people quite clearly think this is all just fine. They&amp;rsquo;re quite happy to trade their souls for an endless set of distractions: perhaps the point of the distractions is so they don&amp;rsquo;t realise just what it is they&amp;rsquo;ve lost and what exactly it was they gained in return if anything; or perhaps they have souls which are not very valuable and the bargain is a perfectly reasonable one, after all.&lt;/p&gt;

&lt;p&gt;There is worse. When you met someone late at night to make this sort of bargain, you made very sure that you got a bit of paper with signatures on it detailing just exactly what the deal was&lt;sup&gt;&lt;a href="#2015-03-14-contracts-footnote-4-definition" name="2015-03-14-contracts-footnote-4-return"&gt;4&lt;/a&gt;&lt;/sup&gt;. That&amp;rsquo;s not how the deals that are made so willingly now work: you get something momentarily useful or amusing, and in return you irrevocably give away something of yourself, and that&amp;rsquo;s as far as it goes. If, later, it becomes convenient for the entity you did the deal with to stop providing whatever entertainment it was, then one day it simply goes away and you have bargained your soul for air and darkness, and precious little of that.&lt;/p&gt;

&lt;h2 id="better-living-through-chemistry"&gt;Better living through chemistry&lt;/h2&gt;

&lt;p&gt;The answer is quite conventional. If there is something you want and on which you might come to rely, then you &lt;em&gt;sign a contract for it&lt;/em&gt;: a document which obliges you to pay for it, and in return obliges the provider to actually provide the service.&lt;/p&gt;

&lt;p&gt;Contracts really do three things.&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;They make it clear what exactly is being bought and sold, and avoid the &amp;lsquo;too cheap to meter&amp;rsquo; fallacy I talked about above: the contract should detail what you get and what the limits on it are &amp;mdash; how much bandwidth or storage you can use for instance &amp;mdash; and what you are paying for it, which should generally not be &amp;lsquo;your immortal soul&amp;rsquo;.&lt;/li&gt;
 &lt;li&gt;They ensure that the interests of the consumer and the provider are the same, or at least similar: the consumer wants a service or a product that works well, and the provider gets paid if they provide that.&lt;/li&gt;
 &lt;li&gt;They specify what happens if the contract is terminated: what the responsibilities of each party are and what they are not. For instance the organisation providing your cloud storage might be obliged to give you a way to recover your data.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;The second point is particularly important: for a contract to be of any use at all &lt;em&gt;both parties have to get something out of it&lt;/em&gt;: you can sign a contract with someone to provide you some service for free, but if they decide to stop doing that what are you going to do &amp;mdash; perhaps you could ask them for your money back?&lt;/p&gt;

&lt;p&gt;But, well, this &lt;em&gt;is&lt;/em&gt; a very conventional and rather boring answer: surely we all live in a future where all this awful tedium is no longer needed. Wasn&amp;rsquo;t the internet meant to do away with all that? What happened to the gift economy? Are there no flying cars, after all? Sadly, no, the internet didn&amp;rsquo;t change all that: it simply enabled a collection of large corporations with toxic business models to fool a really large number of people. There are no flying cars.&lt;/p&gt;

&lt;p&gt;On 2015&amp;ndash;07&amp;ndash;16 &lt;a href="http://www.theregister.co.uk/2015/07/17/souceforge_titsup/"&gt;SourceForge fell over&lt;/a&gt;: perhaps it will recover, this time. Once upon a time it was the bright future of source code hosting: who knows what will be lost when it finally goes away?&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
 &lt;ol&gt;
  &lt;li id="2015-03-14-contracts-footnote-1-definition" class="footnote-definition"&gt;
   &lt;p&gt;It is particularly tempting to people who want to make the argument that &amp;lsquo;no harm is done to the artists if I just download this song, because it costs nothing for them to deliver an extra copy: they have already been paid&amp;rsquo;. I am not sure if this argument is ever made in good faith, but it&amp;rsquo;s very easy to see that it doesn&amp;rsquo;t work by &lt;em&gt;reductio ad absurdam&lt;/em&gt;: what would happen if &lt;em&gt;everyone&lt;/em&gt; made it? However I don&amp;rsquo;t want to get sidetracked by that here.&amp;nbsp;&lt;a href="#2015-03-14-contracts-footnote-1-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2015-03-14-contracts-footnote-2-definition" class="footnote-definition"&gt;
   &lt;p&gt;&amp;lsquo;Metering&amp;rsquo; may be simply restriction of supply &amp;mdash; for instance a limit to the amount of data you can transfer, which may not seem like metering although it is. In the limiting case the limit may be the physical capacity of the system: you can only transfer so much data per month over link with a given bandwidth. I suspect that the original &amp;lsquo;too cheap to meter&amp;rsquo; claim was made based on this assumption for domestic electricity usage (if it was ever really made at all). &amp;nbsp;&lt;a href="#2015-03-14-contracts-footnote-2-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2015-03-14-contracts-footnote-3-definition" class="footnote-definition"&gt;
   &lt;p&gt;Well, perhaps it is a bargain worth making, but probably not in exchange for anything related very closely to computers.&amp;nbsp;&lt;a href="#2015-03-14-contracts-footnote-3-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li id="2015-03-14-contracts-footnote-4-definition" class="footnote-definition"&gt;
   &lt;p&gt;Perhaps in the hope of later renegotiation, although it generally seemed to turn out that the counterparty had rather better negotiation skills than you and, obviously, expensive lawyers with dead eyes.&amp;nbsp;&lt;a href="#2015-03-14-contracts-footnote-4-return"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item>
  <item>
   <title>Rumours of my death</title>
   <link>https://www.tfeb.org/fragments/2015/02/01/rumours-of-my-death/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2015-02-01-rumours-of-my-death</guid>
   <pubDate>Sun, 01 Feb 2015 20:54:34 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;When I first used Lisp, the common refrain was that Lisp was dead.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;There was a single free implementation of CL (which required you to physically sign a license of some kind and return it, in exchange for a tape) which was deficient in many respects. The two or three commercial implementations cost about a year&amp;rsquo;s salary each. Enormous effort had been spent on implementations which ran on special hardware. One variant of these cost more than your house: the other rather less, but turned out to have been implemented by the fey &amp;mdash; you seriously did not want to spend too much time with it if you did not want problems involving having your firstborn somehow changed into a strange and somehow &lt;em&gt;absent&lt;/em&gt; creature.&lt;/p&gt;

&lt;p&gt;(And there was a terrible, unspeakable truth about even the expensive hardware: the people who implemented it didn&amp;rsquo;t understand computer performance very well with the result you would expect. The systems were faster than a VAX, but &lt;em&gt;everything&lt;/em&gt; was faster than a VAX, including some PDP&amp;ndash;11s. A Sun 3/260 ate them alive, and you could buy several of those for the cost of a house, with bundled licenses.)&lt;/p&gt;

&lt;p&gt;Performance was pretty grim: of course nothing was fast on machines that, on a good day, could execute a few million instructions a second, but Lisp implementations were problematic at best. You spent a lot of time turning recursive code into iterative code by hand and writing macros (no inlining) to get performance to be reasonable and worrying about the primitive garbage collectors.&lt;/p&gt;

&lt;p&gt;There was no standard: existing implementations differed in basic details like error handling (not in the aluminium book) and a standard object system was a distant dream. The news from the standards committee was ominous: the special-hardware people were exerting pressure and there were serious worries that the object system would not be efficiently implementable on stock hardware. The language was going to be huge.&lt;/p&gt;

&lt;p&gt;Standard or semi-standard libraries were not really thought of.&lt;/p&gt;

&lt;p&gt;Everyone knew Lisp was dead: the coming thing was, perhaps, Scheme &amp;mdash; tail-call elimination &lt;em&gt;in the language&lt;/em&gt;, a small language (yet MIT Scheme somehow had a bigger footprint than the CLs we used) &amp;mdash; or C++ or some functional language whose name no-one now remembers. But Lisp was dead: no question about it.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Fast forward.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I have two high-quality CL implementations on my machine and one Scheme-derived system, also of very high quality, which created this blog: I have long ago stopped counting the number of good-quality free implementations. One of the implementations I use is commercial: the annual support is about 10% of my monthly rent. I can run dozens of instances of each without the machine noticing, and I could happily run a full CL development system on a system less powerful and smaller than my phone. Performance is a solved problem: yes, highly-optimised code is, perhaps, slower than optimised C or Fortran but since almost all performance problems are design problems no-one older than about 19 cares any more. CL has an advanced, performant and standard object system and, in effect, a standard metaobject system as well. The library problem has been solved by Quicklisp and a large number of good-quality standard libraries. I am still using code I wrote over twenty-five years ago with essentially no modification: meanwhile the Python code I wrote ten years ago is long rendered obsolete by gratuitous changes in the language (the Perl code I wrote at the same time is doing fine, however).&lt;/p&gt;

&lt;p&gt;And yet still the cry goes up: Lisp is dead; Lisp is dead.&lt;/p&gt;</description></item>
  <item>
   <title>Macros in Racket, part two</title>
   <link>https://www.tfeb.org/fragments/2015/01/28/macros-in-racket-part-two/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2015-01-28-macros-in-racket-part-two</guid>
   <pubDate>Wed, 28 Jan 2015 19:31:18 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;The second part of my notes on writing macros in Racket.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;This is the second part of at least three: the first part is &lt;a href="../../../../2015/01/13/macros-in-racket-part-one/"&gt;here&lt;/a&gt;, and the third part is &lt;a href="../../../../2015/12/12/macros-in-racket-part-three/"&gt;here&lt;/a&gt;. This won&amp;rsquo;t make much sense unless you&amp;rsquo;ve read that. As before I make no claims to be an expert in Racket&amp;rsquo;s macro system although I am familiar with Lisp macros in general: this is just some more notes I wrote while learning it.&lt;/p&gt;

&lt;h2 id="the-unwashed-lisp-hackers-version-of-collecting"&gt;The unwashed Lisp hacker&amp;rsquo;s version of &lt;code&gt;collecting&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;So, we can write &lt;code&gt;clet&lt;/code&gt;: can we write &lt;code&gt;collecting&lt;/code&gt;? Yes, we can:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(require (for-syntax racket/list))

(define-syntax (collecting stx)
  (datum-&amp;gt;syntax
   (quote-syntax collecting)
   `(let ([r '()])
      (define (,(datum-&amp;gt;syntax stx 'collect) it)
        (set! r (cons it r)) it)
      ,@(rest (syntax-&amp;gt;list stx))
      (reverse r))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This works because, in the internal definition of &lt;code&gt;collect&lt;/code&gt;, we&amp;rsquo;ve intentionally given it a name which uses the context of the syntax object we&amp;rsquo;re transforming, not the context of the macro. It&amp;rsquo;s easy to confirm that this works the way you would expect, and in particular that it&amp;rsquo;s safe in both directions: for instance&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (let ((reverse (λ (x) x)))
    (collecting (collect 1) (collect 2)))
'(1 2)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;shows that the binding of &lt;code&gt;reverse&lt;/code&gt; when the macro is called has not &amp;lsquo;infected&amp;rsquo; the macro definition.&lt;/p&gt;

&lt;p&gt;It seems as if that should be all you need: so long as you are careful about which context you choose, and you make sure that the &amp;lsquo;default&amp;rsquo; context is the one from the macro not from where it is used. In fact it isn&amp;rsquo;t, quite: see &lt;a href="#macro-composition"&gt;below&lt;/a&gt;. However even if it were, it&amp;rsquo;s clearly a pain to write macros this way.&lt;/p&gt;

&lt;h2 id="pattern-matching"&gt;Pattern matching&lt;/h2&gt;

&lt;p&gt;Pretty much all macros do two things:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;deconstruct their arguments in some more-or-less complicated way, but almost always in a way which is significantly more complicated than anything that needs to be done for the arguments of a function;&lt;/li&gt;
 &lt;li&gt;construct a form which is the result of the macro and which, again, may be complicated.&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;The beauty of traditional Lisp macros is that since the arguments and results of the macro were just what the reader spat out &amp;mdash; lists and symbols and so on &amp;mdash; and since Lisp was kind of good at doing things to these structures as it was designed for that, and finally since the whole power of the language was available in the macro, this was not horrible even without special tools, although it was not particularly pleasant for complicated macros.&lt;/p&gt;

&lt;p&gt;Hygienic macros make this much less pleasant because the objects that need to be deconstructed and constructed are now opaque syntax objects, and there is additional worrying about context to do. The answer to this is to provide special tools which do the boring bits for you: this makes everything simpler, at the cost of making it still more opaque what is actually happening. In almost all cases that&amp;rsquo;s a tradeoff worth making. Pattern matching is also a fashionable thing amongst the young and hip, of course.&lt;/p&gt;

&lt;p&gt;The way this is done in Racket is via &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket/private/stxcase-scheme..rkt)._syntax-case))" style="color: inherit"&gt;syntax-case&lt;/a&gt;&lt;/code&gt;, its slightly simpler friend &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket/private/stxcase-scheme..rkt)._syntax-rules))" style="color: inherit"&gt;syntax-rules&lt;/a&gt;&lt;/code&gt;, and by &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket/private/stxcase-scheme..rkt)._syntax))" style="color: inherit"&gt;syntax&lt;/a&gt;&lt;/code&gt; and variants on it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket/private/stxcase-scheme..rkt)._syntax-case))" style="color: inherit"&gt;syntax-case&lt;/a&gt;&lt;/code&gt; takes a bit of syntax and matches it against patterns, binding matches, which can then be used in &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket/private/stxcase-scheme..rkt)._syntax))" style="color: inherit"&gt;syntax&lt;/a&gt;&lt;/code&gt; forms lexically within it to return syntax objects, whose context is that of the &lt;code&gt;syntax-case&lt;/code&gt; form (so hygienic). There is syntactic sugar for &lt;code&gt;syntax&lt;/code&gt;: &lt;code&gt;(syntax ...)&lt;/code&gt; can be written &lt;code&gt;#'...&lt;/code&gt; in the same way that &lt;code&gt;(quote ...)&lt;/code&gt; can be written &lt;code&gt;'...&lt;/code&gt;. There is also &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket/private/qqstx..rkt)._quasisyntax))" style="color: inherit"&gt;quasisyntax&lt;/a&gt;&lt;/code&gt; which works the same way as &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/quasiquote.html#(form._((lib._racket/private/letstx-scheme..rkt)._quasiquote))" style="color: inherit"&gt;quasiquote&lt;/a&gt;&lt;/code&gt;, except that the various unquoting things are preceeded with &lt;code&gt;#&lt;/code&gt;. &lt;code&gt;quasisyntax&lt;/code&gt;, unsurprisingly also has syntactic sugar coating: &lt;code&gt;(quasisyntax ...)&lt;/code&gt; can be written &lt;code&gt;#`...&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m not going to describe the patterns in any detail, largely because I only understand the simple cases. However the simple cases are relatively easy to understand and pleasant to use.&lt;/p&gt;

&lt;p&gt;Once a case has matched in &lt;code&gt;syntax-case&lt;/code&gt; the corresponding expression is evaluated, and its value is the value of the form. Generally that wants to be a bit of syntax.&lt;/p&gt;

&lt;p&gt;The first important thing to understand is that &lt;code&gt;syntax&lt;/code&gt; is not &lt;code&gt;quote&lt;/code&gt;-for-syntax: it interpolates things which matched in a lexically surrounding &lt;code&gt;syntax-case&lt;/code&gt;, if there is one (if there isn&amp;rsquo;t, then I think it &lt;em&gt;is&lt;/em&gt; &lt;code&gt;quote&lt;/code&gt;-for-syntax).&lt;/p&gt;

&lt;p&gt;The second important thing to understand is that &lt;code&gt;syntax-case&lt;/code&gt; and &lt;code&gt;syntax&lt;/code&gt; turn Racket into a sort of bodged Lisp&amp;ndash;2: the things matched by &lt;code&gt;syntax-case&lt;/code&gt; can be used &lt;em&gt;only&lt;/em&gt; in &lt;code&gt;syntax&lt;/code&gt; forms. But it&amp;rsquo;s not actually a separate namespace, because if you refer to them outwith such a form you get a compile-time error. I don&amp;rsquo;t know why this is &amp;mdash; perhaps to avoid accidentally naming matches outside a &lt;code&gt;syntax&lt;/code&gt; form &amp;mdash; but it is certainly annoying.&lt;/p&gt;

&lt;p&gt;So, here are some examples.&lt;/p&gt;

&lt;p&gt;A simple &lt;code&gt;while&lt;/code&gt; form:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax (while stx)
  (syntax-case stx ()
    [(_ test body ...)
     #'(let loop ()
         (when test
           body ...
           (loop)))]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A simple implementation of &lt;code&gt;let&lt;/code&gt;, leaving out the named-&lt;code&gt;let&lt;/code&gt; case, which shows how good the pattern matching is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax (with stx)
  (syntax-case stx ()
    [(_ ([var val] ...) body ...)
     #'((λ (var ...) body ...) val ...)]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A better implementation which deals with the empty body case (&lt;code&gt;(λ (...))&lt;/code&gt; is illegal in Racket) and also optimises a simple case:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax (with stx)
  (syntax-case stx ()
    [(_ () body ...)
     ;; no vars: trivial case
     #'(begin body ...)]
    [(_ ([var val] ...))
     ;; null body: make sure vars are evaluated
     #'(begin val ... (void))]
    [(_ ([var val] ...) body ...)
     #'((λ (var ...) body ...) val ...)]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;One thing which &lt;code&gt;syntax-case&lt;/code&gt; allows is the notion of literal names which must occur in the source. So for instance let&amp;rsquo;s say I wanted to write some mutant &lt;code&gt;loop&lt;/code&gt; macro whose syntax was &lt;code&gt;(loop for x in y do ...)&lt;/code&gt;: where &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;in&lt;/code&gt;, &lt;code&gt;do&lt;/code&gt; are literals. Well, I can write something to match this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (define-syntax (loop stx)
    (syntax-case stx (for in do)
    [(_ for v in l do body ...)
     #'(for ([v (in-list l)]) body ...)]))
&amp;gt; (loop for x in '(1 2 3) do (print x))
123
&amp;gt; (loop with x in '(1 2 3) do (print x))
loop: bad syntax in: (loop with x in (quote (1 2 3)) do (print x))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The syntax object that corresponds to &lt;code&gt;stx&lt;/code&gt; here is the whole form: the equivalent to CL&amp;rsquo;s &lt;code&gt;&amp;amp;WHOLE&lt;/code&gt;. It&amp;rsquo;s almost never necessary to worry about the &lt;code&gt;car&lt;/code&gt; of this since it will obviously be &lt;code&gt;loop&lt;/code&gt;. However I&amp;rsquo;m always tempted to provide it as a literal.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket/private/stxcase-scheme..rkt)._syntax-rules))" style="color: inherit"&gt;syntax-rules&lt;/a&gt;&lt;/code&gt; is (almost: there is some complexity I think) a wrapper around &lt;code&gt;syntax-case&lt;/code&gt; which provides the function wrapper for it and which implicitly wraps the right hand side of the cases, which must be just one form, in a &lt;code&gt;syntax&lt;/code&gt; form. So the above definition of &lt;code&gt;with&lt;/code&gt; could be written:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax with
  (syntax-rules ()
    [(_ () body ...)
     ;; no vars: trivial case
     (begin body ...)]
    [(_ ([var val] ...))
     ;; null body: make sure vars are evaluated
     (begin val ... (void))]
    [(_ ([var val] ...) body ...)
     ((λ (var ...) body ...) val ...)]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;syntax-rules&lt;/code&gt; can be defined something like this (this is due to &lt;a href="https://gist.github.com/tfeb/0b8531c94cf685824626"&gt;bmastenbrook&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(require (for-syntax 
          (rename-in racket 
                     [syntax-rules racket:syntax-rules])))

(begin-for-syntax
  (define-syntax syntax-rules
    (racket:syntax-rules ()
      [(_ literals (pattern expansion) ...)
       (lambda (s)
         (syntax-case s literals
           (pattern #'expansion) ...))])))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket/private/misc..rkt)._define-syntax-rule))" style="color: inherit"&gt;define-syntax-rule&lt;/a&gt;&lt;/code&gt; combines &lt;code&gt;define-syntax&lt;/code&gt; and a single rule for &lt;code&gt;syntax-rules&lt;/code&gt;. I &lt;em&gt;think&lt;/em&gt; it might be equivalent to this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax define-syntax-rule
  (syntax-rules ()
    [(_ (name pat ...) expansion)
     (define-syntax name
       (syntax-rules ()
         [(name pat ...) expansion]))]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;although I am probably missing some complexity here.&lt;/p&gt;

&lt;p&gt;There is a useful variant on &lt;code&gt;syntax-case&lt;/code&gt; called &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket/private/stxcase-scheme..rkt)._with-syntax))" style="color: inherit"&gt;with-syntax&lt;/a&gt;&lt;/code&gt;: it looks more like &lt;code&gt;let&lt;/code&gt;-style thing, and &lt;em&gt;all&lt;/em&gt; the patterns in the clauses must match, when all the pattern variables will be bound.&lt;/p&gt;

&lt;p&gt;So, what about our desirable macros?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;collect&lt;/code&gt; is pretty easy. Here are two different versions. The first uses &lt;code&gt;quasisyntax&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax (collecting stx)
  (syntax-case stx ()
    [(_) #'(void)]
    [(_ body ...)
     #`(let ([r '()])
         (define (#,(datum-&amp;gt;syntax stx 'collect) it)
           (set! r (cons it r)) it)
         body ...
         (reverse r))]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The second uses &lt;code&gt;with-syntax&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax (collecting stx)
  (syntax-case stx ()
    [(_) #'(void)]
    [(_ body ...)
     (with-syntax ([collect (datum-&amp;gt;syntax stx 'collect)])
       #'(let ([r '()])
         (define (collect it)
           (set! r (cons it r)) it)
           body ...
           (reverse r)))]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is pretty nice, I think. Note that you could not do this with &lt;code&gt;syntax-rules&lt;/code&gt;, or at least I can&amp;rsquo;t see how to do it: &lt;code&gt;syntax-rules&lt;/code&gt; is quite a lot less general than &lt;code&gt;syntax-case&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;clet&lt;/code&gt; is harder, because each element of the binding list may be either an identifier or a two-element list. If we insisted on a two-element list it would be easy (see above). Here is the best I can do:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(require racket/undefined)        

(define-syntax (clet stx)
  (syntax-case stx ()
    [(_ ()) #'(void)]
    [(_ () body ...) #'(begin body ...)]
    [(_ (b ...) body ...)
     (let-values ([(vars vals)
                   (for/lists (as vs) ([binding (syntax-&amp;gt;list #'(b ...))])
                     (syntax-case binding ()
                       [(var val) 
                        (identifier? #'var)
                        (values #'var #'val)]
                       [var
                        (identifier? #'var)
                        (values #'var #'undefined)]
                       [_ (raise-syntax-error #f "bad binding" stx)]))])
       #`((λ #,vars body ...) #,@vals))]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Well, this is still quite hairy, but almost all of the hair involves processing the binding list, which is done using &lt;code&gt;syntax-case&lt;/code&gt; again, using an additional feature of it whereby it can use a &amp;lsquo;guard&amp;rsquo; expression to decide whether a clause matches: &lt;code&gt;identifer?&lt;/code&gt; returnt true if a syntax object refers to an identifier. I think there must be a way of using &lt;code&gt;with-syntax&lt;/code&gt; to avoid the &lt;code&gt;quasisyntax&lt;/code&gt; form.&lt;/p&gt;

&lt;p&gt;Even with all this hair, this version of &lt;code&gt;clet&lt;/code&gt; is far easier to read than the previous one, and not harder to read than the CL equivalent.&lt;/p&gt;

&lt;p&gt;A better version of &lt;code&gt;clet&lt;/code&gt; would, I think, need a proper parser for syntax. I think that is what &lt;code&gt;&lt;a href="http://docs.racket-lang.org/syntax/Parsing_Syntax.html#(form._((lib._syntax/parse..rkt)._syntax-parse))" style="color: inherit"&gt;syntax-parse&lt;/a&gt;&lt;/code&gt; is, although I have not investigated that.&lt;/p&gt;

&lt;h2 id="macro-composition"&gt;Macro composition&lt;/h2&gt;

&lt;p&gt;As mentioned above, we don&amp;rsquo;t yet have quite all the tools we need to write some kinds of macros: specifically macros which are intentionally slightly unygienic, such as &lt;code&gt;collecting&lt;/code&gt;. As an example, let&amp;rsquo;s suppose we wanted a general purpose, intentionally-unhygenic, &lt;code&gt;with-abort&lt;/code&gt; macro which provided an &lt;code&gt;abort&lt;/code&gt; function which would, well, abort. Without thinking too hard about the implications of &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/cont.html#(def._((lib._racket/private/more-scheme..rkt)._call/cc))" style="color: inherit"&gt;call/cc&lt;/a&gt;&lt;/code&gt; we could write this as:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax (with-abort stx)
  (syntax-case stx ()
    [(_ body ...)
     #`(call/cc (λ (#,(datum-&amp;gt;syntax stx 'abort))
                  body ...))]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So now &lt;code&gt;(with-abort (abort 2) (end-the-world))&lt;/code&gt; returns &lt;code&gt;2&lt;/code&gt; and does not end the world.&lt;/p&gt;

&lt;p&gt;Well, we might want to use this macro in another macro:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax-rule (while/abort test body ...)
  (with-abort
    (let loop ([r test])
      (when r
        body ...
        (loop test)))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now something like the following will work:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (let ([x 0])
    (while/abort (&amp;lt; x 10) (set! x (+ x 1)) (print x)))
12345678910&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But the whole point was to be able to use &lt;code&gt;abort&lt;/code&gt; in the body, and that &lt;em&gt;doesn&amp;rsquo;t&lt;/em&gt; work:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (let ([x 0])
    (while/abort (&amp;lt; x 10) (set! x (+ x 1)) (when (&amp;gt; x 1) (abort 'done))))
abort: undefined;
 cannot reference an identifier before its definition&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Oh, dear. The problem here is that &lt;code&gt;while/abort&lt;/code&gt; is hygenic, so the &lt;code&gt;abort&lt;/code&gt; binding that is introduced by &lt;code&gt;with-abort&lt;/code&gt; is not visible in the body.&lt;/p&gt;

&lt;p&gt;We could fix this by better design:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax-rule (with-named-abort (abort) body ...)
  ;; a better macro
  (call/cc (λ (abort) body ...)))

(define-syntax (with-abort stx)
  ;; backwards compatible
  (syntax-case stx ()
    [(_ body ...)
     #`(with-abort (#,(datum-&amp;gt;syntax stx 'abort)) body ...)]))

(define-syntax (while/abort stx)
  ;; the end result
  (syntax-case stx ()
    [(_ test body ...)
     #`(with-named-abort (#,(datum-&amp;gt;syntax stx 'abort))
         (let loop ([r test])
           (when r
             body ...
             (loop test))))]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But that&amp;rsquo;s not the solution we&amp;rsquo;re after.&lt;/p&gt;

&lt;p&gt;Racket&amp;rsquo;s answer to this is &lt;a href="http://www.schemeworkshop.org/2011/papers/Barzilay2011.pdf"&gt;syntax parameters&lt;/a&gt;. I don&amp;rsquo;t completely understand these, but they are at least close to dynamic variables, except at macro-expansion time. What you do is to define a syntax parameter, and then rebind it during the expansion: the rebound value is visible to macros which are expanded dynamically within the rebinding form. As with Racket&amp;rsquo;s &lt;a href="http://docs.racket-lang.org/guide/parameterize.html"&gt;ordinary special variables&lt;/a&gt; these look like functions (yet another namespace in disguise).&lt;/p&gt;

&lt;p&gt;So we can define a syntax parameter called &lt;code&gt;abort&lt;/code&gt; using &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stxparam.html#(form._((lib._racket/stxparam..rkt)._define-syntax-parameter))" style="color: inherit"&gt;define-syntax-parameter&lt;/a&gt;&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(require racket/stxparam)

(define-syntax-parameter abort
  (λ (stx)
    (raise-syntax-error #f "not available" stx)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So now any reference to &lt;code&gt;abort&lt;/code&gt; will result in a syntax error:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (abort)
abort: not available in: (abort)
&amp;gt; abort
abort: not available in: abort&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And we can now try to use &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stxparam.html#(form._((lib._racket/stxparam..rkt)._syntax-parameterize))" style="color: inherit"&gt;syntax-parameterize&lt;/a&gt;&lt;/code&gt;, to rebind &lt;code&gt;abort&lt;/code&gt; as a macro:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax with-abort
  (syntax-rules (with-abort)
    [(with-abort) (void)]
    [(with-abort body ...)
     (call/cc
      (λ (a)
        (syntax-parameterize ([abort
                               (syntax-rules ()
                                 [(_ ...) (a ...)])])
          body ...)))]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And this fails horribly, because the outer &lt;code&gt;syntax-rules&lt;/code&gt; thinks it owns the patterns and sees &lt;code&gt;...&lt;/code&gt;s that it does not expect. So much for that.&lt;/p&gt;

&lt;p&gt;Well, we could at least check this works with a specific number of arguments:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax with-abort
  (syntax-rules (with-abort)
    [(with-abort) (void)]
    [(with-abort body ...)
     (call/cc
      (λ (a)
        (syntax-parameterize ([abort
                               (λ (stx)
                                 (syntax-case stx (abort)
                                   [(abort) #'(a)]
                                   [(abort x) #'(a x)]
                                   [_ (raise-syntax-error #f "I give up" stx)]))])
          body ...)))]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But this is obviously just a rubbish answer.&lt;/p&gt;

&lt;p&gt;Well, there is an answer to this: all we really need to do is to make the &lt;code&gt;abort&lt;/code&gt; macro attach itself to &lt;code&gt;a&lt;/code&gt;, and there is a special hack, &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stxtrans.html#(def._((quote._~23~25kernel)._make-rename-transformer))" style="color: inherit"&gt;make-rename-transformer&lt;/a&gt;&lt;/code&gt;, to do this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax with-abort
  (syntax-rules (with-abort)
    [(with-abort) (begin)]
    [(with-abort body ...)
     (call/cc
      (λ (a)
        (syntax-parameterize ([abort (make-rename-transformer #'a)])
          body ...)))]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And this now works:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (with-abort (abort 1 2 3))
     
1
2
3&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And we can use this to write a really robust version of &lt;code&gt;collecting&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(require racket/stxparam)

(define-syntax-parameter collect
  (λ (stx)
    (raise-syntax-error #f "not collecting" stx)))

(define-syntax collecting
  (syntax-rules ()
    [(_) (void)]
    [(_ body ...)
     (let ([r '()])
       (define (clct it)
         (set! r (cons it r)) it)
       (syntax-parameterize ([collect (make-rename-transformer #'clct)])
         body ...
         (reverse r)))]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As far as I can see there is still a problem, however: it is very hard to write macros which expand to other macros which themselves do pattern-matching, since the patterns get acquired by the outer macros. There must be some answer to this, but I can&amp;rsquo;t see what it is.&lt;/p&gt;

&lt;p&gt;On the other hand, this is also extremely painful in CL: here is a version of &lt;code&gt;collecting&lt;/code&gt; where &lt;code&gt;collect&lt;/code&gt; is a local macro:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmacro collecting (&amp;amp;body forms)
  ;; collect lists forwards using a tail pointer
  ;; local macro version
  (let ((rn (make-symbol "R"))
        (rtn (make-symbol "RT"))
        (itn (make-symbol "IT")))
    `(let ((,rn '())
           (,rtn nil))
       (macrolet ((collect (form)
                    `(let ((,',itn ,form))
                       (if (not (null ,',rn))
                           (setf (cdr ,',rtn) (cons ,',itn nil)
                                 ,',rtn (cdr ,',rtn))
                         (setf ,',rn (cons ,',itn nil)
                               ,',rtn ,',rn))
                       ,',itn)))
         ,@forms)
       ,rn)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is not easy to understand.&lt;/p&gt;

&lt;p&gt;Additionally, the problem almost always comes from ellipses, and in many interesting cases they can be avoided by using dotted pairs as patterns &amp;mdash; here is yet another version of &lt;code&gt;with-abort&lt;/code&gt; that does this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(require racket/stxparam)

(define-syntax-parameter abort
  (λ (stx)
    (raise-syntax-error #f "not available" stx)))

(define-syntax with-abort
  (syntax-rules (with-abort)
    [(with-abort) (void)]
    [(with-abort body ...)
     (call/ec
      (λ (a)
        (syntax-parameterize ([abort
                               (syntax-rules (abort)
                                 [(abort . args) (a . args)])])
                             

          body ...)))]))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is clearly better than the CL version.&lt;/p&gt;

&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;

&lt;p&gt;Well, I think I now know enough about Racket&amp;rsquo;s macros to be going on with: I can certainly write the macros I need to be able to write now without it just being cargo-cult programming. There are still things I don&amp;rsquo;t understand, and the whole system smells to me as if, by trying remain ideologically pure, it has become vast and essentially incomprehensible. This seems to be a common problem with Scheme, unfortunately.&lt;/p&gt;

&lt;h2 id="small-notes"&gt;Small notes&lt;/h2&gt;

&lt;p&gt;Macro definitions scope properly, so you can define a local macro the same way you can define a local function, so this works:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define (foo ...)
  (define-syntax-rule (while test body ...)
    (let loop ()
      (when test
        body ...
        (loop))))
  ... (while ... ...) ...)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This makes the equivalent of CL&amp;rsquo;s &lt;code&gt;MACROLET&lt;/code&gt; easy to do.&lt;/p&gt;

&lt;p&gt;For fun, here is a version of &lt;code&gt;with&lt;/code&gt; which can deal with named-&lt;code&gt;let&lt;/code&gt;: There must be a way of implementing this without assignment, but I can never work out what it is.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax (with stx)
  (syntax-case stx ()
    [(_ ())
     ;; all null
     #'(void)]
    [(_ () body ...)
     ;; no vars: trivial case
     #'(begin body ...)]
    [(_ ([var val] ...))
     ;; null body: make sure vars are evaluated
     #'(begin val ... (void))]
    [(_ ([var val] ...) body ...)
     ;; normal let
     #'((λ (var ...) body ...) val ...)]
    [(_ n ())
     (identifier? #'n)
     ;; named null
     #'(void)]
    [(_ n ([var val] ...))
     (identifier? #'n)
     ;; named null body
     #'(begin val ... (void))]
    [(_ n ([var val] ...) body ...)
     ;; named let with arguments
     ;; (is there an implementation without assignment?
     (identifier? #'n)
     #'((λ (n)
          ((λ (l)
             (set! n l)
             (l val ...))
           (λ (var ...) body ...)))
        #f)]
    [_ (raise-syntax-error #f "bad syntax" stx)]))&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="things-i-still-do-not-know-or-understand"&gt;Things I still do not know or understand&lt;/h2&gt;

&lt;p&gt;At this point I&amp;rsquo;m mostly comfortable writing macros in Racket, but there are things I still do not understand:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;protecting and arming syntax objects &amp;mdash; I just don&amp;rsquo;t understand what this is about at all;&lt;/li&gt;
 &lt;li&gt;&lt;code&gt;&lt;a href="http://docs.racket-lang.org/syntax/Parsing_Syntax.html#(form._((lib._syntax/parse..rkt)._syntax-parse))" style="color: inherit"&gt;syntax-parse&lt;/a&gt;&lt;/code&gt; is, I think, not difficult but I have not bothered to learn about it as it seems to add yet another layer.&lt;/li&gt;
 &lt;li&gt;there are probably other things that I don&amp;rsquo;t even know I don&amp;rsquo;t know.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;At some point I might write a further part of this series on some of that.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id="pointers"&gt;Pointers&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://www.schemeworkshop.org/2011/papers/Barzilay2011.pdf"&gt;Eli Barilay&amp;rsquo;s paper on &lt;code&gt;syntax-parameterize&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.greghendershott.com/fear-of-macros/index.html"&gt;Fear of Macros&lt;/a&gt;, again.&lt;/p&gt;</description></item>
  <item>
   <title>Macros in Racket, part one</title>
   <link>https://www.tfeb.org/fragments/2015/01/13/macros-in-racket-part-one/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2015-01-13-macros-in-racket-part-one</guid>
   <pubDate>Tue, 13 Jan 2015 14:45:48 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;I&amp;rsquo;ve written in Lisp for a long time, but I&amp;rsquo;ve never used a hygienic macro system in any way other than the most simple. Here are some initial notes on my experiences learning &lt;a href="http://racket-lang.org/"&gt;Racket&lt;/a&gt;&amp;rsquo;s macro system.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;This is the first part of several: see &lt;a href="../../../../2015/01/28/macros-in-racket-part-two"&gt;part two&lt;/a&gt; and &lt;a href="../../../../2015/12/12/macros-in-racket-part-three/"&gt;part three&lt;/a&gt;. I&amp;rsquo;m not completely fluent with Racket macros yet: there are almost certainly mistakes and confusions here. Despite appearances, I also have no axe to grind: I&amp;rsquo;m learning Racket because I want to and I have time. Finally this is not a tutorial: look at Greg Hendershott&amp;rsquo;s &lt;a href="http://www.greghendershott.com/fear-of-macros/index.html"&gt;Fear of Macros&lt;/a&gt; for something closer to that. This is just some notes which were useful to me, and might be useful to other CL people.&lt;/p&gt;

&lt;h2 id="macros-in-common-lisp"&gt;Macros in Common Lisp&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://www.lispworks.com/documentation/common-lisp.html"&gt;Common Lisp&lt;/a&gt;&amp;rsquo;s macro system is, in essence, simple: it&amp;rsquo;s what you&amp;rsquo;d end up writing if you had to write a macro system for a Lisp. That&amp;rsquo;s not surprising because it &lt;em&gt;is&lt;/em&gt; the descendent of the first macro systems people wrote for Lisp. In CL what happens is this:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;the reader ingests the source text and produces data structures which represent the source of the program;&lt;/li&gt;
 &lt;li&gt;these structures are possibly transformed by macros, which are simply Lisp functions which are given the Lisp representation of the source and return some other representation;&lt;/li&gt;
 &lt;li&gt;once all macros are expanded, then the code is compiled, evaluated or both.&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;(I have missed out some subtleties here, but they don&amp;rsquo;t matter for my purposes.)&lt;/p&gt;

&lt;p&gt;In CL, what the reader produces is exactly what you would expect. If it reads &lt;code&gt;"(defun foo (a) a)"&lt;/code&gt; then, with standard settings, it returns a list whose car is the symbol &lt;code&gt;DEFUN&lt;/code&gt; (in the &lt;code&gt;CL&lt;/code&gt; package) and so on. It is this structure that macros transform.&lt;/p&gt;

&lt;p&gt;CL provides relatively limited support for writing macros: there is backquote, which is critical to being able to write macros which are even slightly readable, limited pattern matching in the form of destructuring, and there are mechanisms to generate unique names as well a few other things. There is a semi-standard way of enquiring about bindings in the environment at macro expansion time, although this is not in the standard.&lt;/p&gt;

&lt;p&gt;In practice, CL&amp;rsquo;s macro system has turned out to work very well; in theory it has all sorts of problems, the most important being that the programmer is entirely responsible for making sure that macros don&amp;rsquo;t introduce or accidentally use names they should not. Consider this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmacro collecting (&amp;amp;body forms)
  ;; collect lists forwards using a tail pointer
  ;; polluting version
  `(let ((r '())
         (rt nil))
     (flet ((collect (form)
              (if (not (null r))
                  (setf (cdr rt) (cons form nil)
                        rt (cdr rt))
                (setf r (cons form nil)
                      rt r))
              form))
       ,@forms)
     r))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This intentionally introduces a function binding, &lt;code&gt;collect&lt;/code&gt;, but also accidentally introduces bindings for &lt;code&gt;r&lt;/code&gt; and &lt;code&gt;rt&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(let ((r 2))
  (collecting
    (+ r r)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Does not do what it should. One right way to write the &lt;code&gt;collecting&lt;/code&gt; macro is like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmacro collecting (&amp;amp;body forms)
  ;; collect lists forwards using a tail pointer
  ;; non-polluting version
  (let ((rn (make-symbol "R"))
        (rtn (make-symbol "RT")))
    `(let ((,rn '())
           (,rtn nil))
       (flet ((collect (form)
                (if (not (null ,rn))
                    (setf (cdr ,rtn) (cons form nil)
                          ,rtn (cdr ,rtn))
                  (setf ,rn (cons form nil)
                        ,rtn ,rn))
                form))
         ,@forms)
       ,rn)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now the above form does not signal an error and correctly returns &lt;code&gt;()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note that the problem is with &lt;em&gt;names&lt;/em&gt; and not just bindings. Consider this CL code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defvar *stashes* '())
(defvar *mark* nil)
  
(defun stash (name thing)
  ;; Stash something under a name
  (setf *stashes* (acons name thing *stashes*))
  (values name thing))

(defun retrieve (name)
  ;; Retrieve the value of a name, dropping everything stashed more
  ;; recently, and stopping at the mark, if any.
  (let ((mark *mark*))
    (labels ((rl (tail)
               (if (or (null tail)
                       (eq (first tail) mark))
                   (values nil nil)
                 (destructuring-bind ((n . v) . r) tail
                   (if (eql n name)
                       (progn
                         (setf *stashes* r)
                         (values v t))
                     (rl r))))))
      (rl *stashes*))))

(defmacro with-marked-stash (&amp;amp;body forms)
  ;; mark the stack of stashes for the dynamic extent of FORMS
  (let ((mn (make-symbol "MARK")))
    `(let ((*stashes* (cons ',mn *stashes*))
           (*mark* ',mn))
       ,@forms)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this code the marks on the stack of stashes established by &lt;code&gt;with-marked-stash&lt;/code&gt; are not bound anywhere: they are just names. But it&amp;rsquo;s important to the correct functioning of the code that they are &lt;em&gt;unique&lt;/em&gt; names. (There are better ways of doing this such as using a fresh cons for the mark: I just wanted an example where a name mattered other than as the name of a variable.)&lt;/p&gt;

&lt;p&gt;The politically correct way of saying that we&amp;rsquo;re talking about names is to talk about &amp;lsquo;lexical context&amp;rsquo; or &amp;lsquo;lexical information&amp;rsquo;: it&amp;rsquo;s the same thing but more confusing to those not initiated into the cult, which is always good.&lt;/p&gt;

&lt;p&gt;The disadvantages of the CL macro system are this problem with hygiene and the lack of any clever tools to do pattern matching on macro forms. The second of these is easily overcome by using any of a number of tools, while the first is generally not a problem in practice: CL being a Lisp&amp;ndash;2 (separate namespaces for functions and variables) helps here.&lt;/p&gt;

&lt;p&gt;The advantage of the CL macro system is that there is no magic: macros get passed the things that the source code looks like &amp;mdash; generally a structure whose interesting parts are lists and symbols &amp;mdash; which you process using the normal list-processing tools to produce some other structure which is the expansion of the macro. It&amp;rsquo;s easy enough that you could write it yourself: there are no special opaque objects being handed around.&lt;/p&gt;

&lt;p&gt;That being said, having a &lt;em&gt;standard&lt;/em&gt; set of tools for pattern matching in macros and a way of dealing with the hygiene problems which is less ugly than in CL might well be worth the cost in transparency.&lt;/p&gt;

&lt;h2 id="macros-in-scheme"&gt;Macros in Scheme&lt;/h2&gt;

&lt;p&gt;I am not a native &lt;a href="https://en.wikipedia.org/wiki/Scheme_%28programming_language%29"&gt;Scheme&lt;/a&gt; person, but it has clearly taken the whole hygiene thing very seriously: Scheme, as a set of languages, treats purity as much more than CL, which revels in being a fairly grungy language, does. However these posts are not about Scheme: the only reason I am mentioning it is to say that I have not cared at all whether anything here applies generally to Scheme or is specific to Racket.&lt;/p&gt;

&lt;h2 id="macros-in-racket-baby-steps"&gt;Macros in Racket: baby steps&lt;/h2&gt;

&lt;p&gt;For a long time the only kind of macros that I&amp;rsquo;ve really been able to define in Racket are annoyingly trivial ones using &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket/private/misc..rkt)._define-syntax-rule))" style="color: inherit"&gt;define-syntax-rule&lt;/a&gt;&lt;/code&gt;, things like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax-rule (while test body ...)
  (let loop ()
    (when test
      body ...
      (loop))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s all very well, but the &amp;lsquo;obvious&amp;rsquo; (and obviously wrong) definition of &lt;code&gt;collect&lt;/code&gt; then looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax-rule (collecting body ...)
  ;; horribly wrong	
  (let ([s '()])
    (define (collect it)
      (set! s (cons it s))
      it)
    body ...
    (reverse s)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(There&amp;rsquo;s no obvious way to build lists backwards in Racket: reversing the list is probably as cheap as anything). This is either introducing a spurious binding for &lt;code&gt;s&lt;/code&gt; or not introducing a deliberate one for &lt;code&gt;collect&lt;/code&gt;, and in fact, of course, it&amp;rsquo;s the latter.&lt;/p&gt;

&lt;p&gt;Quite apart from this, &lt;code&gt;define-syntax-rule&lt;/code&gt; gives the strong impression that it lets you write only the sort of macros that would give people who write C++ great pride: simple ones. (Actually you can do reasonably hairy things even with this because the pattern matching is very competent:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax-rule (mlet ([var val] ...) body ...)
  ((λ (var ...) body ...) val ...))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;is an implementation of simple &lt;code&gt;let&lt;/code&gt;, for instance. Indeed we can defined named &lt;code&gt;let&lt;/code&gt; as well:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-syntax-rule (nlet label ([var val] ...) body ...)
  (mlet ()
    (define (label var ...) body ...)
    (label val ...)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What I &lt;em&gt;can&amp;rsquo;t&lt;/em&gt; work out how to do is to make &lt;code&gt;mlet&lt;/code&gt; do both things: I think this is too hard for &lt;code&gt;define-syntax-rule&lt;/code&gt; although I might be wrong.)&lt;/p&gt;

&lt;p&gt;But for a long time I was stuck with that: whenever I looked at Racket macros in more detail I walked into a wall of opaque terminology and just decided that I had better things to do that year. This year, I don&amp;rsquo;t.&lt;/p&gt;

&lt;h2 id="two-desirable-macros"&gt;Two desirable macros&lt;/h2&gt;

&lt;p&gt;There are many ways people use macros in Lisp: some of them are good. I decided that if I could write two macros &lt;em&gt;and understand them&lt;/em&gt; then I would be well on my way.&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;&lt;code&gt;collecting&lt;/code&gt; / &lt;code&gt;collect&lt;/code&gt;. This is the macro given above in CL. It&amp;rsquo;s interesting not for what it does &amp;mdash; the tail-pointer stuff is less interesting now than it once was and is hard to implement in Racket anyway &amp;mdash; but because it introduces a binding: it is intentionally not completely hygienic, while having an essentially trivial expansion: no complicated destructuring is needed.&lt;/li&gt;
 &lt;li&gt;CL&amp;rsquo;s &lt;code&gt;let&lt;/code&gt;, which I&amp;rsquo;ll call &lt;code&gt;clet&lt;/code&gt;. This is interesting because it requires destructuring of arguments which is not completely simple, but it does not present problems of hygiene. The reason it&amp;rsquo;s not just a subset of Racket&amp;rsquo;s &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket/private/letstx-scheme..rkt)._let))" style="color: inherit"&gt;let&lt;/a&gt;&lt;/code&gt; is that CL allows variables with no initial value, which get bound to &lt;code&gt;nil&lt;/code&gt; and should, I think, become &lt;code&gt;undefined&lt;/code&gt; in Racket. So &lt;code&gt;(clet ((x 1) y) body ...)&lt;/code&gt; should expand to &lt;code&gt;(let ([x 1] [y undefined]) body ...)&lt;/code&gt; or something equivalent to that.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Here is a simple implementation of &lt;code&gt;clet&lt;/code&gt; in CL, missing any error checking:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmacro clet (bindings &amp;amp;body forms)
  (multiple-value-bind (args vals)
      (loop for binding in bindings
            for consp = (consp binding)
            collect (if consp (first binding) binding) into as
            collect (if consp (second binding) nil) into vs
            finally (return (values as vs)))
    `((lambda (,@args) ,@forms) ,@vals)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Like most macros in CL it&amp;rsquo;s not particularly pretty but it is reasonably clear what it does.&lt;/p&gt;

&lt;p&gt;I will use these two macros as examples below.&lt;/p&gt;

&lt;h2 id="phases"&gt;Phases&lt;/h2&gt;

&lt;p&gt;To understand macros in any Lisp you need to develop a strong idea of the various &amp;lsquo;times&amp;rsquo; that things happen and the relationships between them: for CL these are things like read time, macro expansion time, compilation time (compiler-macro expansion time), load time, run time and so on. Racket has formalised the parts of this after read time into a notion of &amp;lsquo;phase&amp;rsquo;:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;phase 0 is run-time;&lt;/li&gt;
 &lt;li&gt;phase 1 is macro expansion time;&lt;/li&gt;
 &lt;li&gt;phase 2 would, I think, be macros used in macro expansion;&lt;/li&gt;
 &lt;li&gt;and so on.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;However I am not sure how this ties in to read time: is that phase 1? For CL read time is &lt;em&gt;before&lt;/em&gt; macro expansion time although the two are, or may be, interleaved at the granularity of forms (rather than a per-file or per-compilation-unit). Also there are negative phases which I don&amp;rsquo;t understand, although I think they must be to do with code which exists at macro expansion time (phase 1) wanting to make things available at run time (phase 0). All of this is integrated into the module system (and CL gets away without it mostly because it does not have a formalised module system).&lt;/p&gt;

&lt;p&gt;Bindings exist at a phase, and the same name can have different bindings at different phases.&lt;/p&gt;

&lt;p&gt;Modules can say what they &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/require.html#(form._((lib._racket/private/base..rkt)._provide))" style="color: inherit"&gt;provide&lt;/a&gt;&lt;/code&gt; at which phase, and, importantly, the &lt;code&gt;racket&lt;/code&gt; module does indeed provide different things at different phases: if you look at it you&amp;rsquo;ll find:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(provide ...
         (for-syntax (all-from-out racket/base)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which means that, at phase 1, what is available is &lt;code&gt;racket/base&lt;/code&gt;: a significantly smaller language than &lt;code&gt;racket&lt;/code&gt; itself. If you need things in macros which are in &lt;code&gt;racket&lt;/code&gt; but not &lt;code&gt;racket/base&lt;/code&gt; you need to &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/require.html#(form._((lib._racket/private/base..rkt)._require))" style="color: inherit"&gt;require&lt;/a&gt;&lt;/code&gt; them:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(require (for-syntax ...))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;An example of this is &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/pairs.html#(def._((lib._racket/list..rkt)._first))" style="color: inherit"&gt;first&lt;/a&gt;&lt;/code&gt; &amp;amp; &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/pairs.html#(def._((lib._racket/list..rkt)._rest))" style="color: inherit"&gt;rest&lt;/a&gt;&lt;/code&gt;, both of which are provided at phase 0 by &lt;code&gt;racket&lt;/code&gt; but &lt;em&gt;not&lt;/em&gt; at phase one: if you want them you need to say &lt;code&gt;(require (for-syntax racket/list))&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id="syntax-objects"&gt;Syntax objects&lt;/h2&gt;

&lt;p&gt;As in CL, Racket macros are source-to-source functions. The difference is that in Racket the source is represented by a &lt;a href="http://docs.racket-lang.org/reference/syntax-model.html"&gt;syntax object&lt;/a&gt; and a macro needs to produce another syntax object, while in CL source is represented as it looks: usually as nested lists.&lt;/p&gt;

&lt;p&gt;So then a Racket macro is simply a function which maps from syntax objects to other syntax objects. The reason for having an opaque syntax object is that it can carry around all sorts of information around with it, and in particular it can carry information about &lt;em&gt;names&lt;/em&gt;, which help the system maintain hygiene. (There is also information about source location and so on, but this isn&amp;rsquo;t so important.)&lt;/p&gt;

&lt;p&gt;So the Racket macro system needs tools to transform syntax objects into other syntax objects, ultimately by digging around inside them to find out what the source code actually was. This is necessarily more complicated than it is in CL both because the objects are opaque and because they contain information which is not present at all in the objects CL macros get.&lt;/p&gt;

&lt;p&gt;Additionally, and mostly independently, there is a layer on top of this which does not exist in CL (without libraries) at all: pattern matching and template filling. This means that for many purposes you can write macros in Racket simply by specifying patterns that the source must match and filling templates with the results of those matches. This is a very nice way of writing macros, although it renders what is actually going on even more opaque. For a CL person, used to feeling the bits between their toes, this can be quite disconcerting at first since what is actually &lt;em&gt;happening&lt;/em&gt; can become entirely obscure.&lt;/p&gt;

&lt;h2 id="syntax-objects-for-the-unwashed-lisp-hacker"&gt;Syntax objects for the unwashed Lisp hacker&lt;/h2&gt;

&lt;p&gt;Well, of course it is possible to ignore all this terrifyingly modern pattern matching stuff and write macros almost the way you do in CL, and it&amp;rsquo;s worth doing that at least once, perhaps. So here is &lt;code&gt;clet&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(require (for-syntax racket/list)
         racket/undefined)

(define-syntax clet
  (λ (stx)
    (define ctx (quote-syntax clet))
    (define top-level (syntax-&amp;gt;list stx))
    (define bindings (second top-level))
    (define body (rest (rest top-level)))
    (define-values (args vals)
      (for/lists (as vs) ([binding (syntax-&amp;gt;list bindings)])
        (define it (syntax-&amp;gt;list binding))
        (if it
            (values (first it) (second it))
            (values binding (datum-&amp;gt;syntax ctx 'undefined)))))
    (datum-&amp;gt;syntax 
     ctx
     `((λ (,@args) ,@body) ,@vals))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So how does this work? Well, it uses some functions provided by Racket to look inside the syntax object (getting the &amp;lsquo;datum&amp;rsquo; in the syntax object) and in turn to construct a new one:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;&lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-~3elist))" style="color: inherit"&gt;syntax-&amp;gt;list&lt;/a&gt;&lt;/code&gt; takes a syntax object which wraps a proper list and unpacks one level of it, returning a list of syntax objects, or &lt;code&gt;#f&lt;/code&gt; if it does not wrap a proper list;&lt;/li&gt;
 &lt;li&gt;&lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" style="color: inherit"&gt;datum-&amp;gt;syntax&lt;/a&gt;&lt;/code&gt; takes a context object and a datum and wraps it into a syntax object, leaving any syntax objects in the datum as they are;&lt;/li&gt;
 &lt;li&gt;&lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/Syntax_Quoting__quote-syntax.html#(form._((quote._~23~25kernel)._quote-syntax))" style="color: inherit"&gt;quote-syntax&lt;/a&gt;&lt;/code&gt; is like &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/quote.html#(form._((quote._~23~25kernel)._quote))" style="color: inherit"&gt;quote&lt;/a&gt;&lt;/code&gt; but it creates a syntax object, and this object contains the lexical information present in the source.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;So the macro pulls apart the syntax object in a fairly straightforward way: making it into a list, extracting the second element and all the remaining elements, which will be the binding specifications, and then grinding over the binding specifications, using &lt;code&gt;syntax-&amp;gt;list&lt;/code&gt; both to work out if the bindings are a list or not and to extract the variable and value if it is, and then reassembles everything as a call to an anonymous function.&lt;/p&gt;

&lt;p&gt;The critical trick is that the context that &lt;code&gt;datum-&amp;gt;syntax&lt;/code&gt; needs &lt;em&gt;is a syntax object&lt;/em&gt; and you need to pick the right one: you can use the syntax object you got given, which provides the context of the place where the macro was expanded, or you can use a syntax object of your own devising which provides that object&amp;rsquo;s context. And in this case we want our own context, not the context of place where the macro was expanded. This is what &lt;code&gt;ctx&lt;/code&gt; is for: providing a suitable context.&lt;/p&gt;

&lt;p&gt;Notice the &lt;code&gt;require&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;we need &lt;code&gt;racket/list&lt;/code&gt; at phase 1 (macro expansion time) because the macro uses &lt;code&gt;first&lt;/code&gt; and so on;&lt;/li&gt;
 &lt;li&gt;we need &lt;code&gt;racket/undefined&lt;/code&gt; at phase 0 (run time) as the expansion of the macro uses &lt;code&gt;undefined&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;So we can try this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(clet ((x 12) y) (values x y))
12
#&amp;lt;undefined&amp;gt;
&amp;gt; (let ((undefined 'hello)) (clet (x) x))
#&amp;lt;undefined&amp;gt;
&amp;gt; (clet ((undefined 'hello)) (clet (x) x))
#&amp;lt;undefined&amp;gt;
&amp;gt; (clet ((x 1)))
λ: bad syntax in: (λ (x))
&amp;gt; (clet (1) 1)
λ: not an identifier, identifier with default, or keyword in: 1&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The second and third examples show why we need the macro context: we don&amp;rsquo;t want a binding of &lt;code&gt;undefined&lt;/code&gt; to alter what the &lt;code&gt;clet&lt;/code&gt; picks as the undefined value. The fourth and fifth examples show that the macro isn&amp;rsquo;t very robust, and has terrible error reporting.&lt;/p&gt;

&lt;p&gt;Some notes:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;I&amp;rsquo;ve deliberately written &lt;code&gt;(define-syntax clet (λ (stx) ...)&lt;/code&gt; rather than the more pleasant &lt;code&gt;(define-syntax (clet stx) ...)&lt;/code&gt; to make it clear that &lt;code&gt;clet&lt;/code&gt; is a function which transforms a syntax object;&lt;/li&gt;
 &lt;li&gt;but I&amp;rsquo;ve used internal &lt;code&gt;&lt;a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit"&gt;define&lt;/a&gt;&lt;/code&gt; where in CL there would be &lt;code&gt;let*&lt;/code&gt; or nested &lt;code&gt;let&lt;/code&gt;s &amp;mdash; I&amp;rsquo;m not sure why other than reducing indentation;&lt;/li&gt;
 &lt;li&gt;the destructuring of the syntax object is done in a way which is primitive even by the standards of CL;&lt;/li&gt;
 &lt;li&gt;it should be evident that the macro is not very robust &amp;mdash; something like &lt;code&gt;(clet ((x 1) 2) ...)&lt;/code&gt; will fail horribly;&lt;/li&gt;
 &lt;li&gt;it&amp;rsquo;s not &lt;em&gt;much&lt;/em&gt; less clear than the CL version, although I think it is a bit less clear.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;I am fairly but not completely sure that this macro is right: I am slightly confused by the handling of &lt;code&gt;undefined&lt;/code&gt;: although it is easy to check, by wrapping &lt;code&gt;clet&lt;/code&gt; into a module, that clients of that module don&amp;rsquo;t themselves need to import &lt;code&gt;racket/undefined&lt;/code&gt; and do get the right initial values in forms like &lt;code&gt;(clet (x) ...)&lt;/code&gt; I am still a bit queasy about what it&amp;rsquo;s doing.&lt;/p&gt;

&lt;p&gt;What is very clear is that this macro is just horrible: even by the standards of CL macros it&amp;rsquo;s horrible, because there is so much explcit unpacking and repacking going on. Things would be even worse if there was any significant error checking. Something better than this is needed to deal with syntax objects, in a way that it isn&amp;rsquo;t needed for CL macros. In &lt;a href="../../../../2015/01/28/macros-in-racket-part-two"&gt;next week&amp;rsquo;s exciting episode&lt;/a&gt; I&amp;rsquo;ll look at ways of making this better.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id="pointers"&gt;Pointers&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://blog.racket-lang.org/2011/04/writing-syntax-case-macros.html"&gt;Writing &amp;lsquo;syntax-case&amp;rsquo; Macros&lt;/a&gt; by Eli Barzilay. This was the article that first helped me understand what was going on.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.greghendershott.com/fear-of-macros/index.html"&gt;Fear of Macros&lt;/a&gt; by Greg Greg Hendershott. This is an introduction to macros, and macros in Racket in particular, by the author of Frog.&lt;/p&gt;</description></item>
  <item>
   <title>The cult of programming</title>
   <link>https://www.tfeb.org/fragments/2015/01/05/the-cult-of-programming/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2015-01-05-the-cult-of-programming</guid>
   <pubDate>Mon, 05 Jan 2015 19:24:26 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;Programming is &lt;em&gt;not meant to be easy&lt;/em&gt; and it&amp;rsquo;s important to make sure that it is as cryptic as possible otherwise people other than cult members might be able to understand it. Of course, you also need to make sure it&amp;rsquo;s &lt;em&gt;pure&lt;/em&gt;, because otherwise cult members will laughingly throw you into a pit full of spikes and the rotting remains of other heretics.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;For instance, you can&amp;rsquo;t be writing this sort of thing:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun ss (n)
  (let ((s 0) (i 0))
    (tagbody
     loop
     (when (&amp;gt; i n) (go done))
     (setf s (+ s (* i i))
           i (+ i 1))
     (go loop)
     done
     (return-from ss s))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is just terrible code. Non cult members may well be able to understand it, and the cultists will have you in the pit before you know it.&lt;/p&gt;

&lt;p&gt;You might think this was better&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun ss (n)
  (loop for i from 0 to n
    summing (* i i)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But in fact it&amp;rsquo;s far worse. Fellow cultists will definitely still be at the laughing and pit-throwing, and the others will certainly understand it &lt;em&gt;and laugh at you&lt;/em&gt; because you don&amp;rsquo;t know the closed form.&lt;/p&gt;

&lt;p&gt;Instead, you must write this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define (ss n)
  (let-values ([(a i l) (call/cc (λ (c) (values 0 0 c)))])
    (l (+ a (* i i))
       (+ i 1)
       (if (&amp;lt; i (- n 1))
           l
           (λ (a i l) a)))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is almost a perfect solution. It&amp;rsquo;s so achingly pure and cryptic that you will be immediately appointed king of the cult and be able to do your own laughing, and throw other members into pits you have first made them dig, for which they will thank you as they slide down the spikes. Non cult members stand essentially no chance of understanding what it does and sniping about the whole silly closed-form thing: certainly the only way they will be able to learn what it does is by first joining the cult, at which point, as king, you can just throw them straight into the pit.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s important you understand this.&lt;/p&gt;</description></item>
  <item>
   <title>Rerooting Frog</title>
   <link>https://www.tfeb.org/fragments/2014/12/29/rerooting-frog/?utm_source=computer&amp;utm_medium=RSS</link>
   <guid isPermaLink="false">urn:https-www-tfeb-org:-fragments-2014-12-29-rerooting-frog</guid>
   <pubDate>Mon, 29 Dec 2014 17:15:25 UT</pubDate>
   <author>Tim Bradshaw</author>
   <description>
&lt;p&gt;&lt;a href="https://github.com/greghendershott/frog"&gt;Frog&lt;/a&gt; wants to create blogs which hang directly under &lt;code&gt;/&lt;/code&gt;. I want mine to live under a subdirectory, and to have all its data living under that directory. I&amp;rsquo;ve made some changes to Frog to support that. As of 20150702 these changes have been merged to the main frog repo: you no longer need to refer to mine, which is obsolete.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;What I did was to add a new parameter, &lt;code&gt;uri-prefix&lt;/code&gt; (implemented in the code as &lt;code&gt;current-uri-prefix&lt;/code&gt;) and write a function which converts between the original name and whatever external name is wanted: at the moment this just adds the prefix but it has ambitions. Most of the problem was then finding all the places where absolute URIs were assumed in the code, and I&amp;rsquo;m not sure I&amp;rsquo;ve done that &amp;mdash; Racket does not seem to have very good tools for understanding the structure of any significant body of code, which I found surprising: perhaps I am spoiled by the very wonderful &lt;a href="http://www.lispworks.com/"&gt;LispWorks&lt;/a&gt; code browsing tools.&lt;/p&gt;

&lt;p&gt;These fixes could be found on &lt;a href="https://github.com/tfeb/frog"&gt;GitHub&lt;/a&gt;, on the &lt;code&gt;uri-root-fix&lt;/code&gt; branch: this is no longer needed as improved versions are now in the main frog repo.&lt;/p&gt;

&lt;h2 id="a-theory-of-names"&gt;A theory of names&lt;/h2&gt;

&lt;p&gt;The underlying problem here is that you need a &lt;em&gt;theory of names&lt;/em&gt; to do this sort of thing: rather than saying &amp;lsquo;things of type x live in &lt;code&gt;/things/x/...&lt;/code&gt;&amp;rsquo; and then discovering that in fact they should live in &lt;code&gt;/x/things/...&lt;/code&gt; or something, the right answer is to keep the location in some representation which:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;doesn&amp;rsquo;t commit you to what the final pathname, URI or whatever is;&lt;/li&gt;
 &lt;li&gt;has all the information you need to generate the final representation, including the ability to carry around completely arbitrary information;&lt;/li&gt;
 &lt;li&gt;can not be confused for the final representation by the program.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Then you can write mapping functions, including extensible mapping functions, to invent the names you actually need from the objects you have.&lt;/p&gt;

&lt;p&gt;Common Lisp&amp;rsquo;s &lt;a href="http://www.lispworks.com/documentation/HyperSpec/Body/19_c.htm"&gt;logical pathnames&lt;/a&gt; are an early effort in this direction: they offer the ability to translate a logical pathname into a physical pathname in various ways. But they&amp;rsquo;re not the right answer simply because they are pathnames: they can (and are designed to) leak into functions which expect pathnames, and can also leak into places where strings are expected, since pathnames have representations as strings. It&amp;rsquo;s important that whatever representation is used for logical names is &lt;em&gt;not&lt;/em&gt; compatible with code which wants, for instance, to emit URIs, so that you are forced to map things everywhere they are needed. In addition the mappings you can define for logical pathnames are not really general enough.&lt;/p&gt;

&lt;p&gt;Note that it&amp;rsquo;s not enough to have a good approach to manipulating structured pathnames, URIs or whatever, because those are the &lt;em&gt;wrong type of thing&lt;/em&gt; to manipulate.&lt;/p&gt;</description></item></channel></rss>