CodeProfiles.java - CODeDOC 2002

CODeDOC 2002 was a collection of 'software art' projects. One work, W. Bradford Paley's CodeProfiles.java [requires Java support in browser], is particularly interesting because it shows three different ways in which code is "read". The first, and simplest, is a linear scan through the source (the amber highlighting). Second is the sequence in which code was written (white). Third is the execution flow as the program executes.

It's striking how unrelated these three sequences are. Since temporal sequencing lies at the heart of programming, this struck me as worrying. But then, how should they be related? How should the program's structure and creation be related to its temporal flow? And, of course, how does this relate to the language chosen?

For example: if the code were purely declarative then why would there be any correlation between execution and layout? Is my intuition about the importance of any simple relationship between these flows misguided?

Anyway, it is certainly pretty.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Not sure why these should be related

Order of coding would seem to be either order of inspiration, or order of first functionality desired to be demoed. There's certainly no reason that should be related to either static program structure or execution order. As for the relationship between static program structure and execution order, I sort of figured the whole point of "design" was to make static structure as independent from control-flow as possible, through repeated applications of abstraction and chunking. That's the case in both the object-oriented and functional paradigms, as far as my understanding goes. Sizable programs where any of these orders were correlated would probably have to be both pretty poorly designed and very dull.

i think it depends on the sca

i think it depends on the scale, at least for procedural code. at very small scales (with a subroutine, or a sequence of actions added to a monad (or whatever the correct terminology is)) things are related to execution order.

otherwise, i agree with you. yet it still strikes me as odd. after all, ordering of events in stateful code is hugely important - if it's not clear from the source then no wonder it's hard! i realise the party line is that one should therefore remove state, but i, at least, found the whole thing thought provoking.

Code reading

Perhaps I am missing something, but it seems to me that the gap between static and dynamic flow is at the core of what makes reading code difficult (as anyone who took CS tests know, figuring out what a short routine does can be quite confusing because of the dynamic behaviour). It's also the reason why code can be static yet behaviour can depend on input and such (e.g., loops and condtionals). So it's a problem that is here to stay...

As for languages: recursion is one of the key places where dynamic behavior can be confusing. Don't get me wrong - I love recursion. But to say that it makes the static and dyanmic aspects "closer" is far from clear (even if you have RT). You have to remember where to go back to (for non tail calls) and this is a purely dynamic thing.

Lastly, I think Andrew is right in saying that analyzing this tension can thought provoking. The fact that the gap is here to stay, doesn't mean the languages can make it more manageable, and even eliminate it in specific domains and constructs.

the gap

The fact that the gap is here to stay, doesn't mean the languages can make it more manageable, and even eliminate it in specific domains and constructs.

Ehud, does the above line mean that a new language cannot map the static and dynamic aspects of a system? or new languages cannot solve this issue.

I feel the statements that there is tension and that it cannot be resolved by languages makes me feel that i am missing something or the line has a typo(s/can/can't)

Oops

The sentence should read: The fact that the gap is here to stay, doesn't mean that languages can not make it more manageable, and even eliminate it in specific domains and constructs, of course.

Thanks.

Depends on domain

On the other hand, is has been argued (most notably by Dijkstra and Hoare) that the static and dynamic structure of a program should resemble each other. But they were thinking about a different level of static structure. On the higher level, different aspects or features of a program are divided into different modules. And that's good. But on a lower level, when looking at the individual lines of code, the flow of execution should follow somewhat closely the flow of source code.

Of course this applies only to imperative languages. Personally I think it all depends on what you are programming. When you're programming low level code ie. controlling the machine, then static and dynamic flow should be similar. But if your software has nothing to do with computer architecture, then your language should neither.

It can also be that your domain is such that you don't have the luxury of abstracting away hardware, because of performance or immature tools. This was the case for most programming when Dijkstra and Hoare published their opinions.

How should structure and creation relate?

First of all, structure generally does reflect temporal flow on a local basis, i.e., in a local function where statement_n is to follow statement_(n-1), statement_n is usually found after statement_(n-1). On a more global basis, in procedural single-file programs, a lot of code did start with inital contexts at the front of the file and, if the routines were called in a specific order, the ordering of the routines in the file did reflect this ordering (of course, where multiple files were used, local ordering was maintained, but global ordering was not).

As control flow became more distributed, especially in object technologies, the code's physical structure retained little global structure related to control flow. In fact, needing knowledge of control flow started to be seen as bad object design - externally invoked operations were to be packaged so as to seem like atomic actions on the object involved. Any necessary control flow considerations were to be hidden within complete operational abstractions. As such, from a user's point of view, the physical ordering of the code made little difference - each operation was to be complete within itself and able to be called in any order. Internally, the code was less temprally ordered, as well.

With functional and declarative code, again, fewer temporal assumptions should be made - as the control flow becomes less salient and less visible to the programmer, the less ordering on temporal flow will be visible in the physical structure of the source code.

As for creation, when one was doing procedural code design, one had two formal ways to build the code - top down and bottom up. Neither were ideal in all situations. Within single files, the code did tend to physically represent the temporal flow of the design - top down coders had the top-level routines at the top of the file with their low-level routines interspersed between them, while bottom up coders tended to have primitives at the top with higher level routines at the bottom. As OO systems moved away from rigid temporal structuring, high and low-level routines started to have more interspersion. And, as functional and declarative code becomes more common, I would expect to see ordering based on invariants or on other atemporal attributes of the system.

That being said, these are fairly loose observations. In Smalltalk systems, for instance, any notion of code ordering other than local does not exist - methods live under objects they belong to in the image and a tool (the Browser) is provided to view them. In many other cases, especially where good cross-referencing systems were in place, teams structured code in less systematic methods.

When all is said and done, temporal ordering other than at a local level usually doesn't play more than a minor role in code ordering. As the abstraction level of the programming being done increases, the number of temporal cues in the source goes down. By the time you're at OO levels, you should have very few client-visible temporal dependencies. By the time you're at functional/declarative programming levels, there should be none left - as they are not there, they should not effect the source code.

...is most easily read from bottom to top

It's striking how unrelated these three sequences are.

Here is a fresh example from The Next 700 Data Description Languages mentioned here:

The IPADS description of web logs is most easily read from bottom
to top.