Finally, I’d like to share some background on today’s announcement, because this is the 3rd time the PowerShell team has attempted to support SSH. The first attempts were during PowerShell V1 and V2 and were rejected. Given our changes in leadership and culture, we decided to give it another try and this time, because we are able to show the clear and compelling customer value, the company is very supportive.
The most surprising thing about this to me was that the PowerShell team was blocked twice previously by internal teams from implementing SSH support. It doesn’t take much reading between the lines to see that this wasn’t blocked on technical grounds, but on political/ideological ones. I can’t imagine the kind of frustrating meetings that people were in when this decision was made.
Also, given that this announcement was made before discussing it with the OpenSSH community and without giving any clear timelines, it feels like the PowerShell team made this public announcement before someone inside Microsoft could change their mind.
One of the most interesting features of the upcoming Clojure 1.7 release (and ClojureScript 0.0-3196) is Reader Conditionals. These are designed to allow different variants of Clojure to share common logic, while also writing platform specific code in the same file.
Previously this was solved by cljx which processed a Clojure file with a .cljx extension and output multiple platform specific files. These were then read as normal by the Clojure Reader. This worked well, but required another piece of tooling to run, and it wasn’t able to be used in Clojure Core projects.
Reader Conditionals are an answer from the Clojure Core team to that problem. They are similar in spirit and appearance to cljx, however they are integrated into the Clojure Compiler, and don’t require any extra tooling beyond Clojure 1.7 or greater. That bears repeating again, there is no extra tooling required. To use Reader Conditionals, all you need is for your file to have a .cljc extension and to use Clojure 1.7 or ClojureScript 0.0-3196 or higher. Reader Conditionals also have the advantage that they are just data, and can be manipulated like ordinary Clojure data.
There are two types of reader conditionals, standard and splicing. The standard conditional reader behaves similarly to a traditional cond. The syntax for usage is #? and looks like:
One important thing to note is that in Clojure 1.7 a splicing conditional reader cannot be used to splice in multiple top level forms (tracked in CLJ-1706). In concrete terms, this means you can’t do this:
;; Don't do this!, will throw an error
[(defn clj-fn1  :abc)
(defn clj-fn2  :cde)])
;; CompilerException java.lang.RuntimeException: Reader conditional splicing not allowed at the top level.
Instead you’d need to do wrap each function individually:
or use a do to wrap all of the top level functions:
(do (defn clj-fn1  :abc)
(defn clj-fn2  :cde)))
Which one you choose would probably depend on aesthetics, and what your plans for porting these functions to more Clojure platforms were. Let’s go through some examples of places you might want to use these new reader conditionals.
Host interop is one of the biggest pain points that cljx and reader conditionals both solve. You may have a Clojure file that is almost pure Clojure, but needs to call out to the host environment for one function. This is a classic example:
Namespaces are the other big pain point for sharing code between Clojure and ClojureScript. ClojureScript has different syntax for requiring macros than Clojure. To use these macros in a .cljc file, you’ll need Reader Conditionals in the namespace declaration.
I saw Vesa Karvonen had a neat trick for this, taking advantage of the fact you can have multiple :require’s in one Clojure ns form. N.B.: ClojureScript ns forms can only have one :require in them.
Sente uses CLJX for sharing code between Clojure and ClojureScript. I’ve rewritten the main namespace to use reader conditionals. Notice that we’ve used the splicing reader conditional to splice the vector into the parent :require. Notice also that some of the requires are duplicated between :clj and :cljs.
In this example, we want to be able to use the rethinkdb.query namespace in Clojure and ClojureScript. However we can’t load the required rethinkdb.net in ClojureScript as it uses Java sockets to communicate with the database. Instead we use a reader conditional so it’s only required when read by Clojure programs.
Exception handling is another area that benefits from reader conditionals. ClojureScript now supports (catch :default) to catch everything and this may come Clojure too, however you will often still want to handle host specific exceptions. Here’s an example from lemon-disc.
I don’t see a lot of uses yet for the splicing reader conditional outside of namespace declarations, but to get really meta, lets look at the tests for reader conditionals in the ClojureCLR reader. What might not be obvious at first glance is that the vector of [:a :b :c] is actually being spliced into the parent wrapping vector.
There isn’t a clear community consensus yet around where to put .cljc files. For libraries I think in most cases it will make sense to just have one src directory where .clj, .cljs, and .cljc files go. In applications it may end up being simpler to have src/clj, src/cljc, and src/cljs directories.
At the time of writing, I’m not aware of any way to use .cljc files in versions of Clojure less than 1.7, nor is there any porting mechanism to preprocess .cljc files like CLJX does. For that reason library maintainers may need to wait for a while until they can safely drop support for older versions of Clojure and adopt reader conditionals.
UPDATE: There is now a leiningen plugin cljsee which can preprocess cljc files in the same way that cljx did, to output .clj and .cljs files. This might be a good option if you want to keep backwards compatibility with older Clojure versions.
If you have any other interesting uses for reader conditionals, let me know and I’ll update this post to add them.
Lastly I’d like to offer my congratulations to everyone who worked on Reader Conditionals, and its predecessor Feature Expressions. There was a lot of thought, effort, and discussion put into this, and I think that it has produced something useful, extensible, and long-lasting.
James Mickens works at Microsoft Research. Amongst his more serious work, he has written some hilarious papers for Usenix, and given some funny talks. I’ve collected a selection of my favourite quotes here, but you should really read and watch them all from start to finish.
When you debug systems code, there are no high-level debates about font choices and the best kind of turquoise, because this is the Old Testament, an angry and monochromatic world, and it doesn’t matter whether your Arial is Bold or Condensed when people are covered in boils and pestilence and Egyptian pharaoh oppression. HCI people discover bugs by receiving a concerned email from their therapist. Systems people discover bugs by waking up and discovering that their first-born children are missing and “ETIMEDOUT ” has been written in blood on the wall.
Listen, regardless of which Byzantine fault tolerance protocol you pick, Twitter will still have fewer than two nines of availability. As it turns out, Ted the Poorly Paid Datacenter Operator will not send 15 cryptographically signed messages before he accidentally spills coffee on the air conditioning unit and then overwrites your tape backups with bootleg recordings of Nickelback. Ted will just do these things and then go home, because that’s what Ted does. His extensive home collection of “Thundercats” cartoons will not watch itself. Ted is needed, and Ted will heed the call of duty.
So, your phone just starts doing stuff, all the stuff that it knows how to do, and it’s just going nuts, and your apps are closing and opening and talking to the cloud and configuring themselves in unnatural ways, and your phone starts vibrating and rumbling with its little rumble pack, and it will gently sing like a tiny hummingbird of hate, and you’ll look at the touchscreen, and you’ll see that things are happening, my god, there are so many happenings, and you’ll try to flip the phone over and take out the battery, because now you just want to kill it and move to Kansas and start over, but the back panel of the phone is attached by a molecule-sized screw that requires a special type of screwdriver that only Merlin possesses, and Merlin isn’t nearby, and your phone is still rumbling, and by this point, you can understand the rumble, it’s a twin language that you and your phone invented, and the phone is rumbling, and it’s saying that it’s far from done, that it has so much more that it wants to do, that there are so many of your frenemies that it wants to “accidentally” call and then leave you to deal with the social ramifications, and your phone, it buzzes, and you think that you see it smiling, and you begin to realize that land-line telephones were actually a pretty good idea.
My point is that security people need to get their priorities straight. The “threat model” section of a security paper resembles the script for a telenovela that was written by a paranoid schizophrenic: there are elaborate narratives and grand conspiracy theories, and there are heroes and villains with fantastic (yet oddly constrained) powers that necessitate a grinding battle of emotional and technical attrition. In the real world, threat models are much simpler. Basically, you’re either dealing with Mossad or not-Mossad. If your adversary is not-Mossad, then you’ll probably be fine if you pick a good password and don’t respond to emails from [email protected]biz.ru. If your adversary is the Mossad, YOU’RE GONNA DIE AND THERE’S NOTHING THAT YOU CAN DO ABOUT IT. The Mossad is not intimidated by the fact that you employ https://. If the Mossad wants your data, they’re going to use a drone to replace your cellphone with a piece of uranium that’s shaped like a cellphone, and when you die of tumors filled with tumors, they’re going to hold a press conference and say “It wasn’t us” as they wear t-shirts that say “IT WAS DEFINITELY US”.
Perhaps the processor could run multiple copies of each program, comparing the results to detect errors? Perhaps a new video codec could tolerate persistently hateful levels of hardware error? All of these techniques could be implemented. However, John slowly realized that these solutions were just things that he could do, and inventing “a thing that you could do” is a low bar for human achievement. If I were walking past your house and I saw that it was on fire, I could try to put out the fire by finding a dingo and then teaching it how to speak Spanish. That’s certainly a thing that I could do. However, when you arrived at your erstwhile house and found a pile of heirloom ashes, me, and a dingo with a chewed-up Rosetta Stone box, you would be less than pleased, despite my protestations that negative scientific results are useful and I had just proven that Spanish-illiterate dingoes cannot extinguish fires using mind power.