
Google Common Lisp style guide - fanf2
https://google.github.io/styleguide/lispguide.xml
======
kazinator
> _You must not use INTERN or UNINTERN at runtime._

I.e. you must not read Lisp data at run time, if it contains symbols, because
that will call _intern_.

> _You should avoid using a list as anything besides a container of elements
> of like type._

Good-bye, code-is-data.

I could reduce this guide by a good 30% with "You should avoid using Lisp as
anything as Go or Java".

But that could be seen as defining a macro, which you must seldom do.

~~~
Spivak
I really don't think that this is bad advice in general. Mess with the code
all you want at compile time, but don't touch it at runtime is the good kind
of boring. CL is an extremely powerful language, it doesn't mean you should be
using it all the time in your day-to-day work.

~~~
kazinator
The thing is, you usually shouldn't be calling INTERN even at compile time. A
better rule is this:

 _Don 't use code to calculate character strings, which are then converted to
symbols via INTERN. The main exceptions to this rule are structs (which
generate slot-reader functions by combining the structure name and slot
names)._

Macrology which calculates names using code, which are then supposed to be
explicitly referenced in code, is pretty stinky.

E.g.:

    
    
      (define-blob foo ...)
    

Here, you're suposed to Just Know that the above is referenced as _blob-foo_
and not _foo_ , because internally it catenates "BLOB-" onto (symbol-name
'foo), and calls intern on that.

~~~
dreamcompiler
Above is one of the many reasons I prefer defclass to defstruct. Defclass
doesn't do this ridiculous nonsense.

~~~
tgbugs
Many times when working with code that uses structs in Racket I have found
myself fruitlessly grepping for the definition of some mysterious and
troublesome function before eventually remembering to check whether there is a
struct named foo with a member named bar somewhere. Normally this is not a
problem so long as the file can make it far enough through the syntax phase
that you can resolve the names. Yet somehow when the code is well and truly
broken then somewhere, somehow, a struct will be involved without any way to
resolve the member name. I say this having written my own symbol creating and
binding macros before I realized the pitfalls and now dread having to go back
and fix it. It seems like such a cool idea in principle.

~~~
dreamcompiler
It's a cool idea for programming and a terrible idea for software engineering.

------
Syzygies
> Symbol guidelines: You should use lower case

Like flipping through for the soft porn in a friend's "romance" novel, I must
confess I searched straight for this guideline.

It astonishes me that Lisp systems still default to all caps. Of course one
can quickly disable this, but why send the old gheezer "GET OFF MY LAWN!"
message? That's exactly what people do, get off Lisp's lawn. They don't even
get to the part where the parentheses (completely unnecessary for representing
a tree in 2020) are a hazing exercise / loyalty test.

I love Lisp, but its public relations is the poster child for "How can people
who are so smart be so dumb?"

~~~
sahil-kang
Can you share more info about the parentheses being a hazing test? I’ve seen
Dylan syntax [1], but is there something else that shows the parentheses to be
unnecessary in 2020?

[1]
[https://en.wikipedia.org/wiki/Dylan_(programming_language)](https://en.wikipedia.org/wiki/Dylan_\(programming_language\))

~~~
praptak
I've had good experience with Closure's cautious approach to parentheses.

It's not radical, in that it's still basically parentheses but their nesting
is greatly reduced by combination of tricks:

Flattening, if reversible. E.g. if something's always a list of pairs, then
it's represented as a flat list with pairing inferred.

Having shorthands in syntax, i.e. [a b c] is (vec '(a b c)).

~~~
WalterGR
In my admittedly limited experience with Clojure a few years ago, IIRC it
seemed like it just replaced some parentheses with square brackets, but did
not actually reduce the number of total brackets by much.

------
_bxg1
> Macros bring syntactic abstraction, which is a wonderful thing. It helps
> make your code clearer, by describing your intent without getting bogged in
> implementation details (indeed abstracting those details away). It helps
> make your code more concise and more readable, by eliminating both
> redundancy and irrelevant details. But it comes at a cost to the reader,
> which is learning a new syntactic concept for each macro. And so it should
> not be abused.

I really think this just applies to any kind of indirection - classes,
functions, even named constants (vs literals).

~~~
dreamcompiler
> I really think this just applies to any kind of indirection - classes,
> functions, even named constants (vs literals).

Disagree. Macros are fundamentally different in that they can change the
syntax of the language. As such, they can inhibit the code's readability in
ways the other defining forms cannot. Looking up something by name in CL is as
simple as meta-dot. But you cannot meta-dot syntax. (Well, you could on a Lisp
Machine, but not so much on current CL implementations.)

~~~
fiddlerwoaroof
> you cannot meta-dot syntax

I don't understand this? Besides the macrostep expander, meta-dot works on the
macro name: reader macros _are_ harder to debug, but they're generally
discouraged.

~~~
dreamcompiler
It requires more cognitive load to interpret new syntactic constructs. See
brundolf's comment herein.

------
dreamcompiler
> You should favor iteration over recursion

I take slight issue with this. It's one of the ways Scheme programming style
differs from Common Lisp style in general, and it makes sense. But I find the
LOOP macro obtuse and ugly and many algorithms are simply clearer with
recursion, so if I can write it tail-recursively and I know the implementation
supports tail calls (most do), I often do that instead of using LOOP.

The other handy case for recursion is "try foo, and if it doesn't work tweak
this argument and try foo one more time." There tail calls don't matter
because max iteration count is 2.

LOOP is still critically important but sometimes it impedes rather than
assists clarity.

~~~
remexre
Have you tried iterate (wrt the loop sucks problem)

~~~
dreamcompiler
Yes but I've never used iterate enough to get comfortable with it. Maybe I
should.

------
dang
If curious see also

2012
[https://news.ycombinator.com/item?id=4639490](https://news.ycombinator.com/item?id=4639490)

Not Google's, from last year:
[https://news.ycombinator.com/item?id=20505807](https://news.ycombinator.com/item?id=20505807)

~~~
airstrike
Beat me to it! Link to the article in the 2012 submission is broken, so here's
a web archive copy: [http://web.archive.org/web/20130114221734/https://google-
sty...](http://web.archive.org/web/20130114221734/https://google-
styleguide.googlecode.com/svn/trunk/lispguide.xml)

Seems like the exact same document which harks back to the ITA Software
acquisition per comments at the time of that submission

------
ch_123
I assume (perhaps naively) that Google must have a non trivial amount of CL
development if they have a style guide for the language... anyone know what
they use CL for?

~~~
carry_bit
My guess: Google bought ITA Software about 10 years ago, and their search
engine was written in Common Lisp.

~~~
danielam
Yes. The authors of this document were all engineers who worked on QPX/QRES.

------
alaaalawi
YMMV but i do prefer the following:
[https://www.cs.umd.edu/~nau/cmsc421/norvig-lisp-
style.pdf](https://www.cs.umd.edu/~nau/cmsc421/norvig-lisp-style.pdf)

------
jimbokun
Is it weird that I enjoy reading this, even though I haven't programmed in
Common Lisp for a long while?

------
twblalock
Who here can talk about how widely used Lisp is at Google, and what it is used
for?

------
butterisgood
Went looking for advice on concurrency/parallelism and error handling.

~~~
danielam
FWIW, speaking from memory, if QPX, Google's (previously ITA's) low airfare
search engine, is any indication, then the lack of any real mention is not
surprising because QPX did not make use of parallelization or concurrency. The
way it was written made that move very difficult. From what I recall, there
was interest in parallelizing some bits of the computation, but I don't recall
it ever really going anywhere. (QRES, ITA's reservation system, which was also
written in Common Lisp, may have made use of concurrency or parallelization in
some way, but my knowledge of that system is limited.)

N.b., QPX did not quite follow all of these recommended practices during my
tenure (e.g., ubiquitous SETFing of object slots).

------
rurban
nconc over append, lol. You cannot use append when the first list is long,
it's way too slow.

The rest all makes sense.

------
lordgrenville
Slightly off-topic but is this official, and if so...why is Google hosting
stuff on Github Pages? Seems sort of amateurish. Not to mention it belongs to
a rival of theirs.

~~~
cbarrick
Google moved a lot of their open source projects to GitHub after they shut
down Google Code. That was before the MS acquisition.

You can find a lot of smaller projects at
[https://github.com/google](https://github.com/google), and obviously there
are some big ones like
[https://github.com/tensorflow/tensorflow](https://github.com/tensorflow/tensorflow).

Notable exceptions are Android and Fuchsia, which have their own hosted git
repos at
[https://{android,fuschia}.googlesource.com](https://{android,fuschia}.googlesource.com).

~~~
lordgrenville
Thanks for clarifying. It makes sense to host repos on GitHub - it's so
widespread - but what struck me as weird was using the.github.io domain, which
I usually associate with amateur bloggers who don't want the hassle of
registering a domain.

