[HCI] [Tech] Constraint-based systems in Laszlo
http://slashdot.org/comments.pl?sid=129894&cid=10835594
Comments from a cool programmer I know (Don Hopkins), on one of my colleagues (Brad Myers) and on constraints in UI programming.
Comments from a cool programmer I know (Don Hopkins), on one of my colleagues (Brad Myers) and on constraints in UI programming.
Garnet [cmu.edu] is an advanced user interface development environment written in Common Lisp, developed by Brad Meyers (the author of the article). I worked for Brad on the Garnet project at the CMU CS department back in 1992-3.
One thing I like about Brad Meyers is that he's a strong programmer, as well as an excellent researcher, so he had a first-hand understanding of the real-world issues involved in programming languages and user interface architecture, unlike many academics who talk a lot of theory but never get their hands dirty. Brad Meyers understands where the rubber hits the road, and how important it is to have good tires.
At the time I worked on it, Garnet didn't have pretty graphics like Flash, but the underlying programming system had some advanced features that are sorely lacking from most modern user interface development environments.
Laszlo [laszlosystems.com] is an modern open source GUI programming system, with many of Garnet's advanced "natural programming" features like prototypes [osteele.com] and constraints [laszlosystems.com]. Laszlo currently uses Flash as its virtual machine, but it's a much higher level way to program dynamic interactive web based applications, without using the proprietary Flash authoring tool.
Garnet had a true prototype based OOP system (somewhat like Self), which is great for gui programming, because guis have so many objects that look and behave like each other except for a few little customizations (like the layout, graphical style, data source and call-back behavior).
Garnet also had an automatic constraint [osteele.com] system, which enabled you to simply define any attribute as a formula that depend on other attributes, without needing to worry about how and when the values were calculated. Garnet's constraint system automatically figured out the dependences of each formula, and automatically and efficiently recalculated and cached any values that needed to be updated, but only when necessary.
With constraints, you can make a button inside a window, and define its left edge to be ((parent.width - self.width) / 2), and it will automatically remain horizontally centered in the window from then on, without you (the programmer) having to worry about what to do when the parent window's size changes.
Without constraints, you have to manually write all the code that changes the button position whenever the window size changes, which results in code scattered all over the place in different classes and handlers and intermediate objects.
Constraints are much easier to use and more general purpose than resize handlers, springs and struts, complex MVC [osteele.com] updating schemes, and other Rube Goldberg devices.
Constraints are especially useful for user interface programming, because they save you from having to write lots of annoying boiler plate and error prone code for handling updates (registering, chasing down dependencies, detecting changes, notifying updates, all happens automatically).
Constraints make GUI programming much easier, but they're also useful anywhere in your program where one value is defined in terms of other values that might change at any time.
Once you've tasted a programming language with constraints, you will not want to go back. Programming without constraints is like writing in machine language: error prone, low level, tedious, inefficient and mind numbing.
Constraints are like structured programming for variables: In the same way that it's better to use loops and conditionals instead of gotos, it's also better to use declarative programming [ultrasaurus.com] that says what you mean, instead of imperative peeks and pokes and side effects.
Constraints let you write easy to read code, and concentrate on the interesting high level stuff that matters. You can go back later and change the layout of a complex GUI, without rewriting lots of fragile layout and event hanling code. Look at any MFC program to see how bad it can get without constraints.
Constraints are natural and close to the way you think, because they let you declare a variable and the formula that defines its value in one place, instead of scattered all around the code. They off-load the tedious task of tracking down and maintaining all the dependencies from the programmer to the computer, which is much better at that kind of stuff.
Garbage collection is like constraints: the computer can do a much better job than the human at performing the task perfectly, so spending some cpu time on automatic garbage collection and constraint maintenance is well worth the significant increase in programmer productivity and software reliability.
Garnet had a prototype based object system. It was implemented in Lisp with a system called KR (Knowledge Representation, classic AI "frames" with slots and inheritance). KR was extended with an automatic constraint system that parsed the formula expressions (written in Lisp macros), figured out the dependences, wired up and maintained the dependency graph.
An expression like "((parent.width – self.width) / 2)" would depend on self’s width slot, self’s parent slot, and parent’s width slot. If any of them changed, then that formula would be automatically invalidated, and only recalculated on demand when it (or something that depended on it) is required.
The cool thing was that you can make a prototype object, like a button, which has sub-structures like a label, border, drop shadow, etc. The sub-structures can be constrained to the button’s dimensions, the label is centered in the border, and the drop shadow floats below and to the right, so the button's layout is automatically updated when it moves or resizes.
The text color and border fill can depend on the button’s "state" variable, so they automatically switch between bright and dark when you press the button (the input handler just toggles the "highlight" variable, and the graphics that depend on it are automatically updated).
Now that you've composed and constrained a button to look and feel how you want, you can use it as a prototype to make other similar customizable buttons instances. Each instance can itself override the prototype's graphical properties, label text, action, etc.
Instances of a prototype all magically inherit (instances of) the sub-structure of the prototype! It all just works the way you’d expect it to (with a lot of plumbing going on automatically behind the scenes). There’s no need to make a separate class for each different style of button or action – prototypes let you customize any instance itself!
Like Garnet, Laszlo [laszlosystems.com] is an advanced open source user interface development environment that supports prototype based OOP with constraints.
Unlike Garnet, Laszlo deeply integrates recent trendy technologies like XML, JavaScript, Flash, data binding, networking, XML/RPC, SOAP, ReST, Java and Tomcat.
Laszlo has a class/prototype based object system [laszlosystems.com], and it (currently) uses the JavaScript runtime in Flash as its virtual machine. But it's more than just another way to program Flash.
Unlike raw Flash, The Laszlo language is easy to learn [laszlosystems.com] and Laszlo programs are easy to read and write [laszlosystems.com] thanks to prototypes [laszlosystems.com], constraints [laszlosystems.com], declarative programming [laszlosystems.com], and instance-first development [osteele.com].
-Don
Comments