The treeshaker thus was not a compiler tool, but a tool to remove what was determined to be unused code of a Lisp heap. Remember, by default such a Lisp image would also contain a compiler, an interpreter and an implementation of a read-eval-print loop. Thus if we break (-> interrupt a thread which then provides a REPL) a running program into such a read-eval-print loop, we could still use all the code, which is in this heap (which was restored from an image). Thus it would make sense to remove the compiler too, and possibly the read-eval-print loop, too.
Lucid Inc. used the word internally at least since 1987, mentioning a treeshaker for Lucid CL 3.0 on the VAX.
"Lisp Systems in the 1990s", Layer/Richardson, 1991 https://dl.acm.org/doi/10.1145/114669.114674
From above: "In contrast, tree shaking uses the approach of eliminating --shaking out-- what is not needed in a static fashion. Programmers specify the requirements of their application and the unneeded parts of the Lisp system are removed using their detailed knowledge of the application. The disadvantages of tree shaking are that it requires programmer intervention and that a function which is shaken out cannot be easily restored."
"Building Common Lisp Applications with Reasonable Performance", Boreczky/Rowe, 1993, https://dl.acm.org/doi/10.1145/1040032.174174
"Lisp: Good News, Bad News, How to Win Big", Gabriel, (not sure from when this version is, the original article is from 1989) https://www.dreamsongs.com/Files/LispGoodNewsBadNews.pdf
From Gabriel's essay:
> "1.6.3 The Treeshaker
> Most Lisp development systems, including Lucid’s, provide all the resources of the Lisp system by default, and this in turn leads to a style of development in which the programmer makes use of whatever tool happens to be most convenient. Because much of the basic Lisp system (or any development system built on top of the basic Lisp system) will generally be unused by a given application, it is very worthwhile to have a tool for excising these unused parts. This tool is called the Treeshaker.
> Treeshaker execution occurs in three phases: walking, testing and writing. In the walking phase, the Treeshaker accumulates a set of objects that need to be included in the saved image. After making this set, the treeshaker runs a test of the application to check that all objects which are used in a typical run have been included. The writing phase then generates an executable image which will run the application.
> To a first approximation, the walk phase is just a matter of computing the connected component of the Lisp image (treated as a directed graph in the obvious way) generated by the application’s toplevel function. However, because of the way that Lisp objects are generally connected this usually includes almost the entire Lisp image including the unused subsystems. Therefore the treeshaker uses several techniques to find connections between objects that do not actually need to be followed in the walk."
> "The name Treeshaker is meant to be evocative of the idea of actually shaking a tree to dislodge dead branches or other trash."
On the more funny side, LispWorks has a keyword to the DELIVER function :shake-shake-shake , which invokes the treeshaker during application delivery.
https://www.lispworks.com/documentation/lw80/deliv/deliv-key...
“Tree-shaking” as commonly used implies that the granularity of the removal is functions, whereas dead-code elimination can generally be at arbitrarily fine levels, for example eliminating branches of conditional expressions, and can be based on all kinds of static program analyses.
Personally, I think it’s an amazing name. The first time I saw the term, I knew exactly what it was without any further research.
You shake a tree to remove the loose things. In this case, it was clear that unused packages are being “shaken” from the tree.
But it's an ok term overall.
and shaking pine tree always showered me with dried needles
so I didn't even think about "shaking for the fruit" association xD
I don't think so. I never considered tree-shaking to refer to the plants, rather the data structure.
If you imagine the diagram of some source code as a physical object, then shaking it would cause anything unreachable from the root to fall away.
I really don't see how reachability analysis is any different. One term just invokes a more spacial sense of reasoning.
There is lots of code (tree).
Some of the code is not connected to the entry point (trunk).
Tree shaking removes the disconnected parts (loose leaves, dead branches).
In contrast DCE usually refers what the JS engine does at runtime, via whatever means. But DCE isn't much discussed, unless one talking about v8 internals or the like.
Indeed, and this has been known since the 80s as dead code elimination. So why are we using a new, less descriptive, more confusing term again?
Some new developers might be introduced to the concept initially as "tree-shaking". It's not wrong; it just differs from your preference.
Tree-shaking is specifically the form of DCE where you remove unreferenced functions/modules.
Especially important is that you can do tree-shaking without analyzing control flow, while by default "DCE" implies you're analyzing control flow.
And I don't think tree-shaking is a misnomer. Depending on how you visualize the metaphor, unreferenced functions are either barely attached or not attached. Shaking them off is simple and sufficiently realistic.
It's more succient I suppose
And what happens when the wind blows?
Shaking and raking are hardly different in kind.
And wind blowing has what to do with compiler optimizations again?
> Shaking and raking are hardly different in kind.
The only way they're similar is that they're both kinda dumb names for this optimization that has had a standard name for 40 years.
The wind blowing shakes the tree.
When the tree shakes, the dead branches and loose leaves are removed.
---
This is similar to when a bundler will traverse the connected code graph and remove the things that are not attached.
It's no wonder naming things is considered one of the hardest things in computer science if this kind of convoluted argument makes sense to people.
Dead code elimination came 20 years later with C compilers.
The problem with treeshaking - I wrote my first for my lisp 30 years ago, it was trivial - is the lack of compile-time evaluation. The more the compiler knows, the more it can prune. Every run-time branch, late binding and esp. dynamic call by string kills it. With simple tricks you can eliminate 90% of your code. IO, error handling, the number tree, lots of slack in the stdlib's. With GUI even more. I heard from CL images shrinked from 2GB down to a floppy disk.
The metaphor we use for optimization is “low hanging fruit” which no orchard owner would ever do. It’s massively wasteful, be you a programmer or a farmer. It’s what amateurs do. I do tree shaking. Pick a tree (subject matter in the code) and get all of the fruit that’s willing to fall off before moving to the next. It’s more efficient, more effective, and more sustainable. It works with human factors instead of against them.
What we call tree shaking is more like tree pruning. Specifically what you’d call thinning (tracing a misplaced or damaged branch back to the parent and cutting it there).
I think the idea behind calling it "shaking" is these branches and leaves that are already cut (inaccessible from the root), and just need a strong breeze to shake the tree and make them fall out.
We had an ice storm this year and there are loads of them all over town still.
This is just over-extending the metaphor.
The term has existed long before software was a thing, and refers simply to grabbing something that's easy. That's it.
The same goes for tree-shaking. The author does the same thing - over-extends the metaphor. Tree shaking simply means giving everything a jiggle and seeing what comes loose. It's easy to understand and shouldn't be read into any more than that.
Regardless, it is a perfect metaphor. You want to eat an apple: which one do you pick? Taking the low-hanging fruit is less work right now and gets you to your immediate goal, but disregards general efficiency. Sure, picking a whole tree is more efficient. But if you want a single apple, taking the low hanging fruit is the fastest approach. The metaphor works because it actually implies that it's not the most efficient approach, just the easiest