• the user interface of a call center scheduling system (my own GUI, built on X11 but it looked and worked a lot like Copland. All layout was constraint based and used lpsolve to figure out where everything went. You should try that sometime, very expressive.)
• a code generator to build sane C++ business objects mapped to a ridiculously normalized physical database. (A 20+ way join for the most common query. Bureaucrats for the project kill!)
• generating dynamic web pages. I made a template based system, very much like PHP, but before PHP was popular, even before I was aware of PHP.
These were all done with "mindy", the CMU dylan interpreter. It was a byte code compiled interpreter, but its compiler was so fast you never noticed the "make". Very fast startup time on the executables as well. You would need a stopwatch with milliseconds to tell the workflow from a "edit-run-repeat" scripting language. Mindy was later abandoned because it didn't have macros and it was deemed too much work to add it.
The rub is, Dylan macros will hurt your head. They are not easy to understand, ludicrously difficult to implement (been there), and I suspect frightening to extract coherent compile time error messages in a large system. I rather liked the language without them, though I can also see the appeal of a language with them (or a similar extension mechanism).
Overall I can recommend it for:
• Good compile time detection of many stupid errors.
• Excellent readability. (It is verbose, e.g. "end method frabulate-widget;", but that is a single keystroke in the emacs mode, the "end whatever the heck I'm in" key.)
• Safe.
• Powerful.
• Multimethods. Dispatch guided by both type and singleton values. Once you get the hang of this, and design your frameworks with it in mind, you will cry when you have to go back to a language without it.
Things which are concerns:
• Multimethods. Once you have built a system that is extended in different places by overriding multi methods, and you ask yourself the question: "What happens when I call XYZ(a,b,c)?" You don't really know where to look to find the answer. It could be anywhere. If you write a library, you can't really know what a call to XYZ(a) will do. It could be overridden in some flakey user code. (there are various sealing declarations to prevent extension on methods and types, but then you lose the advantages of extension)
• Macros. I doubt I could have taught one in twenty of our engineers to be proficient in the macro system. I can see what the language designers were aiming at with it, but I think they over estimated the abilities of the population.
Regarding the user interface using lpsolve, This sounds very interesting, using a full constraint solver to layout a UI. Are you aware of anything else or public that uses a similar approach?
No, I've not seen anyone else doing it. For anyone trying it, I can recall…
• It was fast enough to be undetectable. This was in the days of 50MHz 486DX chips and struggling to fit on a 16MB machine. It used to do the solve on every window display. I think that the system of equations was always easy for the algorithm. (By contrast, the call center work could run into the minutes to solve.)
• lpsolve is more complicated and capable now, but still LGPL.
• As we move to retina displays, the need for integer variables goes away and things get easier. Rounding becomes acceptable.
• Alignment of elements in unrelated boxes was trivial. Rather like designers use grids to enforce order on disparate elements. You could just say "the left edge of this checkbox lines up with the left edge of the section title"
• Somewhere along the years I've misplaced the code.
• I used data structures to express the relationships between elements. This would have be an outstanding use for macros in Dylan to add a syntax for describing user interfaces, but the mindy interpreter didn't support macros.
• It is especially handy in themeable systems, which were all the new thing at the time, since your elements could have different dimensions as needed. I had both Copland and a slightly more compact traditional X11 look.
• Not terribly related but from the same project: if you are using a blocking garbage collector on a GUI, if you can tell when garbage collection will be required soon, then it works well to force a garbage collection at times when the user will not notice it. For instance, after they click an action that takes time you can sneak in a collection and they'll never know. What you want to avoid is something like a menu coming halfway down then a collection triggering.
That's really cool, I've been interested in using a constraint solver to solve some unrelated problems, but not considered doing it for UI.
One problem I see is that much modern UI is being done on mobile devices, including the ipod which afaik have licenses that are incompatible with the LGPL, and there doesn't seem to be a more liberally licensed constraint solver.
• the user interface of a call center scheduling system (my own GUI, built on X11 but it looked and worked a lot like Copland. All layout was constraint based and used lpsolve to figure out where everything went. You should try that sometime, very expressive.)
• a code generator to build sane C++ business objects mapped to a ridiculously normalized physical database. (A 20+ way join for the most common query. Bureaucrats for the project kill!)
• generating dynamic web pages. I made a template based system, very much like PHP, but before PHP was popular, even before I was aware of PHP.
These were all done with "mindy", the CMU dylan interpreter. It was a byte code compiled interpreter, but its compiler was so fast you never noticed the "make". Very fast startup time on the executables as well. You would need a stopwatch with milliseconds to tell the workflow from a "edit-run-repeat" scripting language. Mindy was later abandoned because it didn't have macros and it was deemed too much work to add it.
The rub is, Dylan macros will hurt your head. They are not easy to understand, ludicrously difficult to implement (been there), and I suspect frightening to extract coherent compile time error messages in a large system. I rather liked the language without them, though I can also see the appeal of a language with them (or a similar extension mechanism).
Overall I can recommend it for:
• Good compile time detection of many stupid errors.
• Excellent readability. (It is verbose, e.g. "end method frabulate-widget;", but that is a single keystroke in the emacs mode, the "end whatever the heck I'm in" key.)
• Safe.
• Powerful.
• Multimethods. Dispatch guided by both type and singleton values. Once you get the hang of this, and design your frameworks with it in mind, you will cry when you have to go back to a language without it.
Things which are concerns:
• Multimethods. Once you have built a system that is extended in different places by overriding multi methods, and you ask yourself the question: "What happens when I call XYZ(a,b,c)?" You don't really know where to look to find the answer. It could be anywhere. If you write a library, you can't really know what a call to XYZ(a) will do. It could be overridden in some flakey user code. (there are various sealing declarations to prevent extension on methods and types, but then you lose the advantages of extension)
• Macros. I doubt I could have taught one in twenty of our engineers to be proficient in the macro system. I can see what the language designers were aiming at with it, but I think they over estimated the abilities of the population.