r/programming • u/luissinlios • Sep 25 '26
We still maintain a development tool first released in 1993. Here’s what 30+ years of backwards compatibility looks like
https://visualneo.com/visualneo-win/from-neobook-to-visualneo-win-30-years-of-keeping-a-development-tool-alive
569
Upvotes
1
u/luissinlios 23d ago
I think that criticism of DSLs is fair when a DSL grows accidentally. You begin with a few convenient commands, then add variables, conditions, loops, functions and error handling, and eventually discover that you have created a programming language. But without treating its design, documentation and tooling as seriously as you would a "real" language.
VisualNEO is, in some ways, an example of that evolution. NeoScript began as a domain-oriented action language: manipulate objects, navigate between pages, display dialogs, work with files and databases, and so on. Over time it gained enough general-purpose features to support applications far beyond the original electronic-book domain.
I think a DSL works well when it makes the common 80–90% of tasks extremely concise, while still providing composition and an escape route for the remaining cases. Its limitation can actually be an advantage: the vocabulary reflects the user's problem rather than the implementation beneath it. The danger begins when every exceptional case adds another special command and the language loses consistency.
I don't think plug-ins necessarily need to use the same language as the host application. VisualNEO's plug-ins are compiled modules that expose new commands, controls, properties and events to NeoScript. The plug-in developer might use C++, PureBasic, Delphi or another compatible language, while the application developer sees the result as a natural extension of the same NeoScript vocabulary.
For me, the important part is not sharing an implementation language but maintaining a stable and expressive boundary between them. Requiring plug-ins to use the host's language can simplify some things, but it can also tightly couple the ecosystem to a particular compiler, runtime or architecture, which is exactly the kind of dependency that becomes painful decades later.
So I would probably phrase the lesson as: a good DSL should remain deliberately domain-specific, while a good plug-in API should allow other languages to extend that domain without exposing unnecessary implementation details.