Ensō Data

I've been busy working on Ensō, but took time out to write something about what we are doing. This post introduces the Schema Schema. Next I'll talk about grammars...

Enso Introduction

I know that this is just a teaser, but it is the introduction of the paper on Ensō that Tijs and I are writing. If you want to know more or see the code, let me know.

Ensō is a theoretically sound and practical reformulation of the concepts of model-driven software development. Ensō is based on first-class structural descriptions, invertable transformations, generic operations and interpretation.

Structures in Ensō are a specialized kind of graph, whose nodes are either primitive data or collections of observable properties, whose values are either nodes or collections of nodes. From a programming language viewpoint this may seem an odd choice for data representation. However, it is essentially the Entity-Relationship (ER) model, also known as Information Models, which is widely used in the design of relational databases and is also the basis for Class Diagrams in the Unified Modeling Language (UML), which describe the structure of networks of objects. The key point is that structures in Ensō are viewed holistically as graphs, not as individual values or traditional sums-and-products data structures.

A structural description, or schema, specifies some of the observable properties of structures. Schemas are used to check the consistency structures. Some properties can be checked while the structure is being created, but other can only be checked once the structure is complete. Ensō allows modification of structures, which is necessary to create cyclic graphs, but also allows valid structures to be sealed to prevent further changes.

Invertible transformations are used to map one structure into another kind of structure, such that mapping can be inverted to (partially) recover the original structure from the result. One common kind of transformation is called a grammar, which is an invertible transformation between structures and text. Text grammars are invertable because they can be used for parsing and also rendering. Other transformations include Diagram grammars, which map structures into diagrams, were edits on the diagram are reflected in the original structure. Grammars that describe the structure and behavior of user interfaces are used to generate very natural applications. Transformations are also used for querying, template processing, and serialization.

Operations can be guided by schemas or grammars, allowing highly generic operations to be defined for comparison, differencing, merging, projecting and otherwise manipulating cyclic structures. These operations are cyclic maps, which correspond to coinductive transformations. Since schemas and transformations are also structures, they can be merged and transformed using these same generic operations. Transformations on schemas can be applied to instances, to support upgrade and change management of data. The resulting system supports powerful modularity constructs, including feature modules, inheritance, and mixins.

Ensō is based on interpretation rather than code generation. While it is possible to define transformations that generate code in conventional languages, this is rarely (if ever) done in Ensō. Instead all structural descriptions and transformations are interpreted dynamically. Although the current incarnation of Ensō does not include it, we have previously demonstrated that partial evaluation can be applied to Ensō-style interpreters to automatically generate efficient code.

Type Inheritance

I recently gave a lecture in my programming language class concluded by explaining that Java does not support inheritance of interfaces. It supports aggregation or composition, but not inheritance. This statement makes no sense unless you understand what inheritance is: consistent modification of self-referential structures. This is why "self" or "this" refers to the subclass in inherited methods. However, these types don't inherit:
interface Stream<T> {
T current();
Stream<T> next();
}

interface BiStream<T> extends Stream<T> {
void insert(T item);
}

The reason is that after applying the "next" operation, the resulting streams do not have "insert" operations. In other words, this program does not type-check.
void pushNext(BiStream<String> s) {
s.next().insert("test");
}

In the literature on static typing of OO languages, what we need here are Self types. Some languages, including Eiffel and Scala, have self types.

Why would you care? Well, there are lots of cases where this kind of modification is useful. Its another concept that is difficult to think about in current languages. The OO example above is nice, but type inheritance also applies to algebraic types (See my "Data Abstraction Revisited" essay for a discussion of the differences). Consider this type, written using Haskell notation:
data Diagram
= Rectangle Int Int Int Int
| Circle Int Int Int
| Composite [Diagram]

If we want to extend this to a new data type, for example, to include polygons and fill colors, we want to say something like this:
data ExtraDiagram inherit Diagram
with Polygon [(Int, Int)]
| Fill Color ExtraDiagram

What this means is Diagram extended with new alternatives, such that the recursive references to Diagram are changed to ExtraDiagram. I've been suggesting a while that functional programming could benefit from inheritance. This is just another example.

Expanded thoughts

A great language should let you think useful thoughts you have never been able to think before. This new project I'm working on, whose code name is "Smalltalk of Modeling", is expanding my mind.

Here is one idea. Lets generalize the idea of grammars. A grammar is normally used to parse text to create a parse tree. But if you annotate the grammar with constructors then the parse tree can be instantiated create arbitrary information structures, which we can view as the semantics of the text. If you are careful, then you will find that there can be quite a bit of divergence between the syntax and the semantics; for example, while syntax is tree-based, the semantics may be a graph. We can also run the process backwards, where we take some semantic object and render it into the grammar to create a parse tree, which can then be written out to text. This amounts to putting some clothes onto the abstract semantic structure.

Text --parse(Grammar)---> ParseTree --instantiate(Factory)--> Semantic Structure
Semantic Structure --render(Grammar)--> ParseTree --
------display----------> Text

Note that parse and render, which both use the Grammar, are not inverses of each other. Instead, they both output ParseTrees, but they do it from two different directions.

Now the interesting thing is that a Grammar is really just a ParseTree with added structure: to allow for alternation, repetition, and variable data. We don't need to add sequencing, because ParseTree already has that. That is, we can view a grammar as

ParseTreeGrammarStructure = Kleene(ParseTreeStructure)

This is probably not too surprising. The interesting thing is that once we make structural descriptions be values, then we can write the Kleene function, which "grammarizes" any structure. (Its called Kleene after the person who first formalized the idea of alternation, repetition, and sequencing.)

My new language lets me think about, and write down, the Kleene function. And use it in more general ways. For example, I can now contemplate constructing

DiagramGrammarStrucutre = Kleene(DiagramStructure)

This creates a semantic structure for the grammar of diagrams. I can then use it with my generic render routine to create diagrams of any semantic structure:

Semantic Structure ---render(DiagramGrammar)---> Diagram

This brings up the question of parsing diagrams. It turns out that we will edit them rather than parse them, but it will be the topic for a future post.

Smalltalk and the future

I recently said that I'm working on creating the "Smalltalk of Modeling". To me, this means creating an elegant system that is practical but also embodies radical and powerful new ideas. It should also be implemented in itself and also capable of creating real applications.

But there are few things about Smalltalk that I hate. The first is the idea of an "image". I cannot stand it when my program is tangled with the IDE. It makes it difficult to collaborate, do version control, or deploy final products. I'm also not a big fan of read-eval-print loops (REPL). I like to write code in files, compile them into programs, and deploy them to customers. My IDE should help me write and debug my programs, but stay out of my way otherwise. Perhaps I did too much C programming when I was young. Some people love images, but I don't get it.

The second one is model-view-controller (MVC). I love MV, but I can do without the C. I have always suspected that it is an artifact of the Smalltalk runtime model, which was written right on the metal and did its own bit rendering and mouse tracking. I have to admit I'm not as experienced at GUIs as I am at other kinds of programming, but I've done a few. More modern toolkits don't have separate controllers. The controllers are built into the views (widgets). That is fine with me. Every time I see a library that emphasizes its adherence to MVC (with a capital C) I cringe. For example, does it really help web apps to modularize where to go next from a page?

Other than that, I love Smalltalk. On the other hand, I'm convinced that OO has run out of steam, and should be best used as the foundation for the next dominant paradigm. What is the next paradigm? Models. Yes, that's it! Not UML. Not MDA. Not EMF/QVT. Not Rails. These are good hints about what is to come, but they are still not complete. Hence my current project, to create a Smalltalk of Modeling.

Ruby GUI

I'm in Ruby GUI hell.

wxruby
I'm using ruby1.9 so I need the latest gem. But it is not compiled for 64bit architecture, so I have to build it from source. When I compile, I get an error:
SWIG version 1.3.31 is installed, minimum version required is 1.3.37.
But when I used MacPorts to try to upgrade SWIG, it only lets me install version 1.3.31 or 2.0.3_0. But wxruby requires a version between 1.3.32 and 1.3.37 because "SWIG 1.3.39 introduced changes incompatible with swig/fixmodule.rb".

Update: after much pain I got wxruby to run. Here is the post that has the clue. The basic summary is:
1) configure ruby with " --with-arch=x86_64,i386" to get both architectures
2) use Gem to install wxruby-ruby19-2.0.1-x86-darwin-9.gem
3) when you run ruby, you have to say "arch -i386 ruby ...
As I said, I hate OSX every time I have to install software.

shoes
You have to run the shoes application. Its not a library, so I don't think I can use it. But I might have to try.

bowline
Looks interesting, and things seem to work until I try to launch the application:
no such file to load -- rubygems
./bowline_twitter/config/boot.rb:3:in `require'
./bowline_twitter/config/boot.rb:3:in `'
./bowline_twitter/script/init:2:in `require'
./bowline_twitter/script/init:2:in `'
JRuby/swing
I guess I might have to try it...

And all the others... I haven't heard much good about them.
Its at times like this that I pine for my Windows box. It may be ugly, but there is a much better change that things will "just work" than on Un*x or OSX.

New programming model

Last week I started tweeting about a new programming language/model that I'm working on with Tijs van der Storm. If you've talked to me about software in the last 10 years, you've probably been exposed to some of my ideas on this topic. I've been trying to make sense of it for a while, but now I'm pleased to say that it is coming together in a concrete way. We aren't ready to announce anything yet, but I can give you some idea of our guiding principles.

* Program with forests, not trees
The idea here is that all data/information should be represented explicitly as semantically integrated networks of typed values with attributes and relationships. There are two important aspects to this idea, which immediate distinguish our approach from both OO and FP. In contrast to OO, we declare structures on a larger level of granularity, to capture semantic integrity of collections of objects, rather than on individual objects. An OO programmer sees individual objects (the "trees") but cannot really see the "forest". Relative to FP, we allow explicit cycles, so that our representation is graph-based, rather than being based on trees as in FP. I know that lazy functional programs can express cyclic structures, but the cycles are not observable. We tend to call our forests "models" although it is best not to import too many assumptions from MDD or UML when we use the term.

*Support many languages. This means that we support domain-specific language. In effect, every information model you create is a language. It can have multiple interpretations. The distinction between textual and visual languages is unimportant, because text and graphics are just two different presentations of an underlying information structure.

*Dynamic checking
The structure of a model are described by other models, which represent structural and behavioral constraints. That is, all data is described by metadata. And the metadata can be more interesting than just structural types. At the top we use the typical self-describing models. However, since everything is a value, all checking is done dynamically.

* Generic operations
Because our "types" have lots of useful information in them, and can be manipulated just like any other value, its easy to write very generic operations, including equality, differencing, parsing, analysis, etc. We do extreme polytypic/generic programming, but don't worry about static checking. We'll worry about that later :-) Richer metadata (aka types or meta-models) means more powerful generic operations.

* Use code for transformations, but never generate code
We like code. Its great for projecting models onto models or computing analysis of models. We are developing a family of cyclic maps, which are like FP maps but they work on our circular structures. But you should never ever explicitly generate code. This is the big mistake of a lot of work on model-driven development. Instead, we use partial evaluation to generate code. Partial evaluation is great because it turns interpreters into compilers automatically (if you are careful!). Model to model transformations are fine and can be written in either code or as an interpretation of some other transformation language. But requiring all transformations to be models (not code), or generating code from models, is bad. I know others might disagree, but this is what we believe.

*Extreme feature-oriented modularity. That is, every idea should be written once. Allow mixins and inheritance/composition at all levels. These are very natural operations on models: to compose them and merge them. Its not easy, but we think we can make it work. You have to compose the syntax and the semantics cleanly. We are inspired by Don Batory's work here.

Our goal is to create "Smaltalk of Modeling". That is, a simple and elegant system that is based on models all the way down. It has a small well defined kernel and we are working on building real applications too, as we build the system. We are implementing in Ruby, although this is just because it is such a great language for this kind of reflective exploration. Our new system is not object-oriented, it is model-oriented. But we are looking for the key ideas in the modeling world, and not necessarily adopting any conventional wisdom. We are exploring!

Paul Graham on Objects in Arc

I just realized that Paul's note is about 10 years old. I'll leave my comments here, but I'm sure a lot has changed since then.... I just read Paul Graham's explanation for why Arc isn't especially object-oriented. My comments below correspond to his points:
  1. "Object-oriented programming is exciting if you have a statically-typed language without lexical closures or macros." Smalltalk, Ruby, C#, Scala, and Python all have lexical closures, and their use of objects is quite exciting (lexical closures are being added to Java real soon now). All Smalltalk control structures are user-defined as well, although it doesn't have full macros. It is true that objects can be used as a stand-in for closures, so there is a little truth to this comment. On the other hand, object-oriented programming is quite popular in dynamically typed languages, so I'm not sure why Paul thinks OO is tied to static typing.
  2. "Object-oriented programming is popular in big companies, because it suits the way they write software." This is ridiculous. Smalltalk, Ruby, PHP, Python, and Lua (to name a few) are all quite popular but are not tied to "big companies". Lots of people like C++ too, at big and small companies. I think that Paul is showing a surprising lack of awareness of reality here.
  3. "Object-oriented programming generates a lot of what looks like work." Object-oriented programs are often more verbose than other styles. Partly its all the types, which means that Smalltalk, Ruby, Python etc are more concise than Java. But partly it is because OO languages encourage (require?) programmers to create modules and put in extensibility hooks everywhere, and these take up space. These hooks are called classes and methods. Haskell programs are usually concise, but are often not very extensible or interoperable.
  4. "If a language is itself an object-oriented program, it can be extended by users." "Overloading"? This has nothing to do with objects! What are you thinking, Paul? Overloading is about selecting an appropriate method based on its static type.
  5. "Object-oriented abstractions map neatly onto the domains of certain specific kinds of programs, like simulations and CAD systems." Yes, OO abstractions map very neatly into certain kinds of programs, like GUIs, operating systems, services, plugin architectures, etc. They are not good for everything, certainly, but they are good for lots of domains.
Object-oriented programming is different from normal programming. There is so much confusion about objects that I begin to wonder if very many people really understand what object-oriented programming is. Certainly there isn't much in Paul's comments to provide evidence that he really understands it.

Here is a quick dictionary to translate OO names into Lispish descriptions.
  • "Dynamic dispatch" is just calling an function value.
  • "Polymorphism" is two different function values that have the same interface.
  • "Objects" are just functional representations of data.
  • "Classes" are just functions that create collections of first-class functions.
OK, so my definition of "object" looks funny. But most common definitions are wrong. Objects are just collections of first-class functions (you might call them "multi-closures" since they are closures with multiple entry points). Go back and look at how SIMULA was implemented -- it just captured the current environment and returned it as a value.

It is interesting to note that OO programs make more use of higher-order first-class functions (because all objects are collections of first-class functions) than most functional programs. This is another reason that OO is hard to grok. But Paul shouldn't have a problem with that.

As a small example, which do you think is a better approach to files? Here is the conventional approach without objects:
(define (scan stream)
(if (not (at-end? stream))
(print (read stream)))
(scan (open-input-file "testdata.txt"))
This is very limiting, because it requires a global read function that can understand how to read from every kind of stream! If I want to create my own kind of stream, I'm out of luck.

Now here is the OO version:
(define (scan stream)
(if (not (stream 'at-end?))
(print (stream 'read)))
(scan (open-input-file "testdata.txt"))
This is very nice, because anyone can implement a function that understands the 'at-end? and 'read messages. Its immediately extensible!

Remember Paul, that the lambda-calculus was the first object-oriented language: all its data is represented behaviorally as objects. Are you sure you aren't using objects?

ACM Digital Library Top 20 most frequently used search terms

I was poking around the ACM site and ran into this list. Its too bad the only
include "terms" not entire search strings.

The following are the Top 20 most frequently used search terms over the past 90 days: (occurances of term)
1. security (30,608)
2. object (24,393)
3. database (22,965)
4. dot com (19,605)
5. data mining (19,532)
6. web (19,040)
7. software (18,928)
8. design (18,239)
9. internet (18,152)
10. wireless (17,914)
11. mobile (16,218)
12. usability (16,125)
13. computer (15,963)
14. xml (15,465)
15. network (14,937)
16. proceeding (13,865)
17. java (13,099)
18. XML (13,034)
19. management (12,932)
20. information (12,907)

PLDI reviewing

I'm on the PDLI external reviewers committee this year. I've never published a paper at PLDI but I have attended. This is also my first time reviewing papers. I thought the quality of the papers I was given to review was quite high. They were also on a surprisingly broad and interesting range of topics. Unfortunately there was a inverse correlation between paper quality and how interesting I found the topic. In other words, the more radical and creative papers were in general much less well executed than the ones with more incremental results. Surprisingly, about 30% of the papers I read had no evaluation at all! I think that there are lots of valid kinds of evidence for the correctness of a result, including proofs, implementation, case studies, even subjective critique and commentary. But if the authors don't make any attempt to evaluate or critique their work, I don't see any way that a paper can be accepted today. Yes, I've published papers in the past that have little or no evaluation, but things have changed.

Academic Ancestors

A student sent me a link to my academic genealogy page. Mine goes like this:
Peter Wegner, Maurice Wilkes, John Ratcliffe, Edward Appleton, Lord Rayleigh (discovered argon), ..., Isaac Newton. One thing that's interesting is how few students the great minds had in the 1700s and 1800s.
Some rants about conference names:

PLDI: the only PL conference with "Design" in the title is also the least likely to accept papers about design of PLs,

OOPSLA: a conference originally about objects, but now part of SPLASH because objects are everywhere

ICFP: was once a conference about programming with functions, but now that almost every modern language has first-class functions, its about pure functional programming, or programming without implicit mutable state.

ICSE: does the "E" stand for "Empirical"?

POPL: no, the "O" does not refer to "Objects"

Matlab annoyance

I am really annoyed at Matlab. It keeps a record of all your old commands. At least, that's what it seems to do. Gives you a nice good feeling that "nothing is ever lost". However, it turns out that it only saves a certain amount of history, and then it starts throwing away commands. I didn't lose anything critical, but it certainly makes me unhappy that I cannot go back and see what I did a few months ago.

Calendars on iPhone, iPad, Mac

I finally found out how to sync all (ten) of my secondary Google calendars into iPhone and my Mac:
  • iPhone: Just go to http://google.com/calendar/iphoneselect . Forget about adding multiple CalDAV calendars. That was not a fun prospect.
  • iCal: Go to Preferences/Accounts/Delegates. Sure, this makes no sense. And it doesn't work until you close and load preferences creating the account. But it works great.
Happy Calendaring!

PS: Now if we could just solve the problem of multi-person event scheduling (a la Exchange) in a distributed and open way, I'd be happy. We do have an Orc app that does it :-)

The future of programming

I just took at look at The future of programming by Tony Wasserman and Steven Gutz. I've never met him but his article made some fairly accurate projections. Note that we are now in the "Medium Term" period. But we are starting the transition to the "Long Term".

Mysore Park

I just go back from a trip to India/Madrid/Delft. I was at the First Mysore Park Workshop on Building and Programming The Cloud. Then I went to POPL. Finally, I visited Eelco Visser and his group at TU Delft. Very productive! India was great and the food was quite good in Delft. I was less impressed overall with Madrid, although the museums are fantastic.

Data Abstraction blog-roll

Here are some other comments on my essay:
In other news, Matt Might talked discussed Fixed-point combinators in JavaScript: Memoizing recursive functions, which is related to my article with Dan Brown on Monadic Memoization Mixins at SBLP last year.

Note on ECOOP banquet talk

The ECOOP banquet talk was delivered during dessert on the lawn of a nice Italian villa on the hill overlooking Genova. When I started the talk I was wearing this dark Zegna suit I got to wear at the IPO of my company. Unfortunately I never got to wear the suit for that event.

You have to realize that banquet talks are about entertainment, not technical details. Everybody was full of good food and wine.

About halfway through the talk I took off my coat. Then my tie. It was difficult because I was trying to talk at the same time and also holding a microphone. Then I took off my shirt. This didn't seem too strange because it was a warm night. I had a "leave no trace" t-shirt on underneath.

Then I talked for a while more. They assumed I was done. But then.. yes... I undid my belt and dropped my pants, to started chuckles and giggles from the crowd. Fortunately I was wearing shorts underneath. I eventually managed to say something like "see, now I'm an academic" as I stood in my shorts and t-shirt. I was trying to illustrate how difficult the transition from industry to academia is... but at least I got a laugh out of them, even if the point wasn't clear.

Guy Steele loves tail calls

My recent essay seems to be causing a big stir. I am pleased because I love it when my work has impact. The only funny thing about it is that I've known all this stuff for 20 years. I guess I just haven't communicated it clearly enough. And the essay is not an easy read, even still. Some people have suggested I need to write a book. We'll see.

Guy Steele pointed out that a pure OO approach to data only works if your language has tail call optimization. This is related to a comment I made in the essay about how objects use recursion everywhere (at both the type and value level).

samskivert gave a very condensed summary and some nice comments.

Andrew Black at Portland State (previously at OGI) said he used my slides in his class. One student found a bug in the essay: I say that ADTs are not possible without a static type system, but I also say that Smalltalk has some primitive ADTs for numbers. I should have said that without a static type system you cannot have the kind of user-defined ADTs that you find in CLU, ML or Ada. There are two ways to get ADTs in a dynamic language: one is with some kind of dynamic sealing (or encryption) and the other is to build them into the language runtime. The basic ADTs using in Smalltalk are built into the runtime.

And Jonathan Aldrich at CMU listed the essay as one of his select "classic papers" on object-oriented programming, saying "This is a (very!) recent paper, not a traditional classic, but it is the best summary I know of what makes objects unique."