Blank generation
I belong to the blank generation and
I can take it or leave it each time, well
I belong to the _ generation but
I can take it or leave it each time.
My destructuring-match macro has a notion of ‘blank’ variables: any variable whose name is "_" is both unique and ignored. This is useful because when pattern matching you often only care about some of the thing you matched: the rest is just placeholders. Štar does the same thing.
This idea, and the names of blank variables, is not something I invented. I think I probably stole it from Racket, which I’m sure got it from somewhere else. Lots of people have done this.
Well, a while ago I thought it would be nice if CL didn’t distinguish between binding multiple values and binding single values: why can’t a single form do both? So I wrote let-values which does this. Again, I’m far from the first person to do this, although let-values makes a more serious attempt to handle declarations properly than most, I think.
So, should let-values support blank variables? Well, I thought it should, so I changed it so it did. So, for instance, you could write
(let-values (((_ present) (gethash ...)))
... present ...)
which is nice, perhaps.
I’ve changed my mind: let-values shouldn’t support blank variables, I think. The reasons for this are that it’s a general binding construct, unifying let and multiple-value-bind and their starred variants, and it should compose with other things. Those other things might have their own ideas of variable names, and in particular they might create variables called "_" which are not meant to be blank.
Štar and DSM are not general binding constructs, so I think that blank variables are OK there. But I don’t, now, think they’re something that a general construct should have. Something like
(for ((_ (in-naturals n)) ;bound iteration
(x ...))
...)
is also just a really common thing to want to do: you don’t want to have to clutter up code with ignore declarations in this case. A similar thing applies for DSM.
Later on, after writing the first version of this post, I changed my mind again. let-values now optionally supports blank variables. There is a variable, *blank-variables*, which controls whether blank variables are supported. This matters at macroexpansion time, of course. *blank-variables* is exported from a distinct package, org.tfeb.hax.let-values/blanks so that if you merely use the org.tfeb.hax.let-values package you just get the four names it exported previously. This seems like a reasonably clean compromise.