[1] https://ericlippert.com/2015/04/27/wizards-and-warriors-part...
[2] https://ericlippert.com/2015/05/11/wizards-and-warriors-part...
The abstraction he offered, of having a tree and then visiting every node in that tree, made the most sense.
> One of the most common usages of this pattern is for the scenario where you’ve got a complex tree where tree nodes can be of many types, and you wish to traverse the tree — that is, visit every node in the tree — taking some actions or performing some computations as you go. The “double dispatch” part of it is that the actions you take as you visit nodes in the tree can depend on the runtime types of both the nodes in the tree, and the code performing the action.
That sounds like a parser. It accepts an AST and evaluates productions on its way through. Saying "actions you take ... depend on the runtime types of ... nodes ... and the code performing the action" sounds similar to sorting out how to mash tree-traversal and productions together.
In my compilers class we first wrote a code linter for our "Wombo" language (a simplified Java). Then we wrote something that built an AST. The core tree traversal code was the same, but the "productions" paired with nodes were different.
A DSL is a language with only a handful of users, each of which is usually in the normal path of employment (obvious exception: Chuck Moore). As soon as someone in a team that relies on a DSL leaves the loss of knowledge is immediate. Unlike any other language that you may have picked up in some other organization the DSL has instantly lost a sizeable fraction of those versed in it. It doesn't take many losses like to kill such a project.
Another problem is that even if the original authors hang around, the chances that they will stay fluent in their own DSL diminishes with increasing intervals between work on a particular project. If the code would be written in a 'normal' language then they would stay fluent.
So DSLs are not a good match for how we normally think about software, even though there is a 1:1 correspondence between the words in your typical DSL (say a FORTH word) and a function call. Functions tend to be written in terms of other functions, just like FORTH words are written in terms of other words, and yet, the standard library is never far away whereas with FORTH words it could easily be 30 words down before you hit the actual language.
I'd love to see something like a DSL based language but with longer term prospects, for a long time I hoped that Smalltalk would be that language but I have mostly given up on that.
Forth does less compile-time checking than any other language I could name. It doesn't have a type system of any sort, not even a dynamic one. This makes it very flexible, but ties its hands when it comes to easy/automatic correctness-checking of DSLs. You'd need to implement your own checker.
There are also valid criticisms of Forth's stack-oriented nature regarding readability and maintainability:
1 2 3 INITIALIZE REPEL_VOGONS FINISH
At a glance, you have no idea of the stack effects of those 3 words. This simply isn't an issue in conventional languages.(For context, I rather like Forth as an interesting and very unusual kind of language, but I don't think it's the future of mainstream software development.)
> the standard library is never far away whereas with FORTH words it could easily be 30 words down before you hit the actual language
Forth famously encourages writing short words, but 30 still sounds extremely deep.
With a threaded-code interpreter, yes, Forth's overhead is considerable, but with a native-code Forth compiler, performance is generally only slightly worse than C.
This is presumably because modern optimising C compilers are incredibly sophisticated, whereas modern Forth engines tend to be essentially one-man projects, even the commercial ones.
I've built a couple of projects both in C and Forth, the latter usually to prototype and once I had a good understanding of the problem space the final version in C. Typically the C version outperformed the Forth version by 3:1 or better, and I would not have known how to bridge that gap.
Well written C is quite performant and Forth's overhead (which is relatively small, but it is there) translates into Forth's threaded interpreter executing a JMP instruction at least once per Forth word and that alone is probably enough to explain a good chunk of that gap. FWIW, my experience with Forth is limited to one implementation and a whole bunch of applications (after being introduced to the language by a veritable Forth wizard in 1985 or so, Hi, LS). Even the code of experienced Forth programmers was no match for my then 6 year old experience with C. Nowadays with far larger caches Forth might do better, I haven't really worked with it for years.
> Typically the C version outperformed the Forth version by 3:1 or better, and I would not have known how to bridge that gap.
With a threaded-code Forth interpreter I'd expect the C version to outperform it by something closer to 5:1, so 3:1 doesn't sound too bad. The only way you can close the gap is with good quality native-code compilation.
> Nowadays with far larger caches Forth might do better, I haven't really worked with it for years.
It's interesting how advances in CPU architecture change the relative performance of the different threading strategies. This has been nicely studied by the gforth folks. [0][1] Threaded-code interpreters still easily lose to optimising native-code compilers though, [2] and I expect they always will.
More on how Forth collides with low-level CPU matters: [3][4][5]
[0] https://www.complang.tuwien.ac.at/forth/threading/
[1] https://www.complang.tuwien.ac.at/forth/threaded-code.html
[2] https://github.com/ForthHub/discussion/issues/88#issuecommen...
[3] The Behavior of Efficient Virtual Machine Interpreters on Modern Architectures - https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.12...
[4] Branch Prediction and the Performance of Interpreters - Don't Trust Folklore https://hal.inria.fr/hal-01100647/document
[5] Optimizing Indirect Branch Prediction Accuracy in Virtual Machine Interpreters - https://www.scss.tcd.ie/David.Gregg/papers/toplas05.pdf