Why Do Some Programming Languages Live and Others Die?

A recent article in Wired with quotes from one of our own. Also, this is a good time to bring up Leo et al. publication draft on Socio-PLT along with their project page and a survey to view and take.

From the article:

But no matter how impressive these new languages are, you have to wonder how long it will take them to really catch on — if they do at all. After all, new programming languages arrive all the time. But few ever reach a wide audience.

At Princeton and the University of California at Berkeley, two researchers are trying to shed some light on why some programming languages hit the big time but most others don’t. In what they call a “side project,” Leo Meyerovich and Ari Rabkin have polled tens of thousands of programmers, and they’re combing through over 300,000 computing projects at the popular code repository SourceForge — all in an effort to determine why old languages still reign supreme.

Edit, abstract from paper:

Why do some programming languages fail and others succeed? What does the answer tell us about programming language design, implementation, and principles? To help answer these and other questions, we argue for a sociologically grounded programming language theory: socio-PLT.

Researchers in the social sciences have studied adoption in many contexts. We show how their findings are applicable to programming language design. For example, many programming language features provide benefits that programmers cannot directly or immediately observe and therefore may not find compelling. From clean water to safe sex, the health community has long examined how to surmount similar observability barriers. We use such results from outside
of programming language theory to frame a research agenda that should help us understand the social foundations of languages. Finally, we examine implications of our approach, such as for the design space of language features and the assessment of scientific research into programming languages

Comment viewing options

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

[meta] Broken link

Could you fix the Wired link?

Fixed, sorry about that! I

Fixed, sorry about that! I really wish we went with some sort of wikimarkup rather than HTML.

It is good to see this.

I have seen so many people arguing that this-or-that programming language is "superior" and "will be adopted" based solely on its mathematical properties or type system, that I have ceased to give such people the respect of arguing with them; these days I tend to just laugh.

It is good to see that some people are doing real research to see why languages are really seen to be superior by engineers (as opposed to just mathematicians) and why they are really adopted.

This is long overdue. Perhaps it will give us something more interesting than (or at least something else besides) type theory to think about.

Socio-PLT for language engineering

My view is more of as an engineer with a new microscope. For example, our study found that programmers anti-correlate types with code reuse. This doesn't mean we should ignore type theory! Instead, it suggests that type theorists are still missing a core piece of the puzzle and that we can start looking at developers to understand where that is. Instead of the POPLMark challenge, imagine a PeopleMark one where feature improvements have an actual sociotechnical basis rather than increasingly ungrounded mathematical ones.

A sliding scale from detailed types to code reusability?

Oddly, I've noticed the same thing. The more semantics the definition of a type carries, the less likely it is that code involving that type will ever be reused. Code that uses "simple" types like numbers and strings and so on (and cons cells in most Lisp dialects) is reused all over the place, readily collected into useful libraries, etc.

But with the possible exception of things like the Standard Template Library, I don't think I've seen much large-scale code reuse, or especially, much code reuse in projects unrelated to the original source, of code implementing operations on types that take more than two pages or so (of whatever programming language) to define.

Type theory is getting good at the ability to define more and more about our data; but this extensively-defined data seems to be very rarely seen to be suited for reuse. Maybe this study will tell us why.

Ray

Unsurprising: complex types are for complex invariants

Your observation (which I'm not sure is the same as leo's remark) is not surprising: you use complex types when you want to capture complex invariants about your domain, they are specialized, and therefore are less likely to be shared widely. It is a good thing that we are able to propose simple interface (therefore simple types) to the widely used code, and those that cannot understandably suffer from less use.

You could say the same things of all kind of communication protocols (inside computers or outside). The most complex ones are generally not the most widely used, and they survive even when they're worth it, in specialized domains.

Without types, you could use

Without types, you could use an abstraction that almost, but not quite, fits your problem domain, and just incrementally adapt the mismatched functionality. This is might be harder to do if the abstraction you want to reuse enforces all sorts of invariants. In this case, you have to understand the full semantics of the abstraction you want to adapt before you can even run your program; not so in the dynamic case. This is a good example of Sean's point that dynamic languages allow easier exploration.

Color me unconvinced. Most

Color me unconvinced. Most libraries that provide rich representations also come with convenience functions to turn them into a less-structured soup of data, because that is also useful for debugging, serialization etc.

Do you have specific examples or use cases in mind? That would be interesting.

It also needs care not to

It also needs care not to let that mathematical line of thinking continue to "The language designers of language X are doing everything right because of theoretical reason Y, the reason that the language isn't widely adopted is just because the engineers are stupid.". I've heard that kind of sentiment expressed many times...

Brain drain challenge

Here is a little challenge. If it is true that programmers who reach my age get lost for their craft and begin to manage programmers ( I have still no idea what this means in terms of a job description, despite being in the industry for 14 years. Three weeks ago I set up a development process for my team. One week later I continued programming ... ), how can this brain drain be slowed down?

Unlike Ray Dillinger I have no interest in playing out engineers against mathematicians. I have also little doubt that Haskell or more generally "type driven programming" has futurity and momentum with respect to PL evolution and Haskell itself has a thriving community despite or because "avoiding success on all costs" but I doubt that PL evolution and the permanent proliferation of new technologies has any intrinsic value. Compared to experience ( including both programming skill and domain knowledge ) it might actually be quite small. However, it depends. Professionally I'm working in a niche which doesn't evolve a lot and could need some fresh air and a generational change while I look at the hyper-mutation spectacle which is web programming with both fascination and disgust.

[...]while I look at the

[...]while I look at the hyper-mutation spectacle which is web programming with both fascination and disgust

Same here!

can you describe the brain drain?

Kay Schluehr: Here is a little challenge. If it is true that programmers who reach my age get lost for their craft and begin to manage programmers (...), how can this brain drain be slowed down?

I don't quite follow, but I might be able to help. Is it an age question? I'm over 50 (might look younger), but still a guy who codes hard stuff, and I'm good at it. I no longer remember everything, and can't recall every bit of my thought process from code I wrote three years ago. I do suffer from falling enthusiasm because I don't learn as much, because I get results I expect, modulo small errors. (I have an idea, and it always works, and it's therefore boring.) That I explain what I'm doing is just as valuable as getting implausibly effective results. Both seem related to my job tasks. Explanations give others confidence in results.

I see folks self-select for management where I work. White-haired folks who want to keep coding do so, without pressure to manage. So it might be job market evolution. (Simulation: start new companies, place older applicants, then see what distribution falls into managment.) Maybe pay scales in different roles play a part. Dunno. When a company is profitable, it can pay experienced folks well.

Can't say exactly why folks want me to do complex parts -- seems related to clarity at both high and low levels. I start with an explanation and end with bit twiddling, and the relation is clear. Last week I needed to improve locality despite concurrent writes in a thundering herd scenario. I describe the problem, write a vague plan, then a highly specific one achieving the vague plan, before coding fuzzy write-wake detection in eight bytes of state including a circular window bitmap of conflicts in the last N operations, plus a bunch of stats elsewhere showing what happened. It's just tedious, rather than hard. I would have found it fun twenty years ago.

Nerds are sophists

In the real world, we have wives and kids.

*Against?!* I do not think you've understood.

I also have no interest in playing engineers *against* mathematicicans. My point was that they ought to be working together. To claim human-level results like "ease of use" is meaningless unless you're getting quantitative feedback from users, in statistically meaningful sample sizes, in some form that can reasonably be interpreted as representing ease of use, like time required to perform a particular task.

On purely mathematical grounds, you can say that things have particular mathematical properties, and prove it. That's not the issue. But if you aren't working with engineers and actually measuring something, then making claims that some set of mathematical properties is essential, or more meaningful or effective than some other, in terms of engineering ease of use is making a claim without evidence.

Scientific publications have rules against making claims without evidence in most fields. Why should Programming Languages be any different?

Ray

A bland article for this hot research

While I generally enjoy reading Wired articles, I found this one quite disappointing. I enjoyed the draft paper on Socio-PLT: it's basically a call for participation to a new¹ research area, with a though-provoking vision and a whole methodological stance (use sociological tools to study PL). The article contained nothing of the sort; it basically reduced it to a popularity/buzz comparison between existing languages (Dart, Go, Scala and C), and platitudes on academic ivory towers.

¹: despite having been informally discussed here on LtU a few times before; this is also related to the work on "Human factors in PL" that Ehud is interested in. I don't know the field well enough to claim that the work here is scientifically novel, but that's at least what I felt, as an outsider.

I think the Socio-PLT draft really deserves a front page story (on LtU) by itself.

It is nice to have a front

It is nice to have a front page article on wired even the popci writing isn't good, for us the paper is much better!

Programmer Perception Questions?

If anyone has any burning questions about programmers they'd like answered, we'd like to know! We've been doing waves of surveys whenever an opportunity presents itself (massive online courses, moments of publicity, etc.), so this is a good chance to scope out any PL hunches :)

Sure, I have many :)

But for now, I would like to focus on this curious statement:

Meyerovich also says the data he and Rabkin are collecting also indicate that programmers aren’t always taking the time to really learn a language when they start using it — and that this trips them up down the road.

You then share an anecdote about ActionScript, but have no hard evidence. What I think you can do, especially for all the C projects on SourceForge, is analyze re-work of particular lines of code over time and look at the tokens in the language being used in that re-work. That way you don't even need to care about the language's semantics first. You're just a boy swinging a hammer looking for nails. Thats the best way to get great insights.

Another way to get great insights is to weight your results via a product-sum algorithm, which I've already recommended to you.

Finally, going back to C, there are a ton of static analysis programs for C. Which projects have the most checkins where the program fails static analysis. If you do a static analysis for every checkin, and the warnings increase, then that particular person checking in the code can be thought to have a "novice to expert" scaled rating. Likewise, there are certain hallmarks of Noobism. The phrase "bug patterns" in the 1980s was coined when there was a lot of research regarding psychology of programming. I believe the researcher's last name was Johnson. He did tons of studies regarding novices ability to understand constructs like for loops. And when I say novices, I mean people like Regis Philbin learning how to program.

Furthermore, something I found fascinating was running Java static analysis tools on code contributed by major companies like Google. You would think they run all the latest and greatest static analysis tools, right? And that they would never check-in code if it failed static analysis, right? Guess again.

So I would say my biggest hunch is programmers continuously overestimate the quality of code released by big companies.

Finally, there is some good research that taps large code bases for figuring out how programmers use libraries. Patrick Lam has done some interesting studies about when do Java programmers chose to use non-standard Java collections.

Edit: I found an early article that coined the term "bug patterns". See: Misconceptions in student's understanding (1979). This phrase is uber-popular today in the software tools community, ever since Eric Allen published Bug Patterns in Java. I also just found An Analysis of Tutorial Reasoning About Programming Bugs, which I think is really cool. Why? Because if you really truly believe we need socially aware languages, then you CANNOT go back on how you view tools like JetBrains Resharper. You have to view them as totally underutilized. Why? Because every time Resharper makes a suggestion the novice commits to, the tool has observed that its code is superior to the programmers. Ergo, if the tool itself was bootstrapping an intelligent tutor system, we could have "status reports" every month of so when the user opens their IDE, reviewing areas they may be weak in.

There are also some old design papers I find interesting, too, but don't have much to do with popularity. Rather, Griswold's paper An Alternative to the Use of Patterns in String Processing, where he makes some very strong usability claims of patterns vs. generators.

I always come back to Sherry

I always come back to Sherry Turkle's software bricolage observations (especially with regards to gender and programming, but also more generally applied also). Really, she had this figured out a couple of decades ago on how many people learn how to program.

You make assumptions that the static analysis tools are actually always useful, whereas they often represent biased "best practices" that are not necessarily shared by everyone. Google has a lot of real gates in place to ensure the quality of their code, like code reviews. Java for example, is notoriously hard for static analysis tools since the strong typing gets rid of a lot of the low hanging fruit.

I went to Patrick's webpage and couldn't find anything related to what you mentioned. Can you give me a more specific reference, I'm very interested in the topic of mining how libraries are used.

DSFinder

DSFinder.

As for big companies like Google knowing better, hmm ;-) I will admit, certain idioms in code may seem strange outside Google, but the most common case would be where a library is optimized for a Google in-house compiler (e.g. I *know* the V8 compiler does certain optimizations, so I *know* certain open source JavaScript Google code will get a free speedup). It should be possible to rule out those static analysis issues with other more alarming issues. Besides, your reaction totally validates that my hunch is interesting if true. And Java tools like PMD and FindBugs get plenty of low-hanging fruit.

As for sherry's work, a few years back you recommended I read tinkering. It was very loaded with thoughts on gender, which although interesting is not what drives me wild. Besides, Marshall McLuhan had way deeper insights in fewer words.

Edit: Some food for thought. When Microsoft released StyleCop (a tool that checks the syntactic layout of C# against various rules), they were shocked users not only wanted to use it, but wanted to write their own style rules with it. Users liked it so much that Microsoft didn't want to support it and instead let the C# community support it. Since then, it is integrated with ReSharper, and also a more powerful rule checker, StyleCop+, has been built on top of it. We use StyleCop+ at work to enforce naming conventions.

Turkle's observations can be

Turkle's observations can be generalized into that people just think/create in different ways. Some are more wired for top-down methodical thinking, some are more wired for bottom-up exploratory thinking, and of course most of us are wired somewhere in between. That there is a gender bias is interesting but not the only think to get out of that.

That users wanted to incorporate their own styles into stylecop reinforces my point about SA tools. There is no standard here, and evaluating code written against one standard according to another isn't going to tell you much.

An aside

My biggest hunch about programming is very meta.

Thomas La Toza, who has done some really good work lately on the HCI side of things, told me that many of his peers working at big companies will do "API Usability Studies" and present the results and recommendations to the lead designers/architects. Yet, they almost always get shot down.

Rather than knowing the relationship between a programmer and his code, I want to know what suggestions programmers will always decline. Also, what kind of API design habits will a programmer make given a constrained set of allowed language features? For example, my hunch is if you don't give users functions with default parameters, then they will write many overloaded functions. I see this in a lot of Microsoft code, like ASP.NET. Function overload madness. Another interesting thing I saw in some ASP.NET code was how they started co-opting anonymous types to make it look like C# supported dictionary literals like Ruby. This encoding, using anonymous types as dictionary literals, is probably something the language designer did not intend or think of. All the programmer was looking to achieve was getting rid of passing an array of params as the last parameter to a function. And then I see this encoding mixed in with overloading. I blogged about how much I disliked this in terms of program comprehension and maintainability when I first saw it, and I still hate it, but it overall fascinates me. Further, it is where my hunch about constrained language features comes from. Users will figure out ways to do things with your language you never imagined, whether it is Todd Veldhuizen for C++ or Oleg Kiselyov for Haskell or Joe Plummer as your user.

Data mining should save us

Data mining should save us here; I think its already heavily practiced at google. User study's often lie in that they are just not empirical enough to be useful. But to go out and see what APIs people are actually using and how they are using them...

I'm an expert at co-opting C# to make it more interesting than it really is. I've got a pattern that allows me to write something like

new XXX() {
  Extend = { A, B, C }
}
new XXX() { 
  Extend = A,
}

And so on...it really saves me a lot of effort when I'm encoding another language in C# without the benefit of a parser.

The average programmer

Isn't it that data mining ( or empirism ) can help decision making in the short term but might be counter productive in the long run?

Suppose you always try to optimize your position in the charts and respond to user desires immediately, you will also break expectations about the reliability of your approach and the strength of your intuition as a "lead designer". Being a Maoist doesn't suffice. Sometimes one has to be Mao himself.

In practice we work around this with some models and tricks. Instead of a "homo economicus" we have the "average programmer" and what is good for the average programmer is also good for you and me. Of course sometimes we want to beat the averages and become a "better programmer" and also offer models and solutions to achieve this e.g. by referring to a master significant such as "science". It cannot go both ways. So it may be more important to determine the "average programmer" and the "better programmer" than to literally adapt to any of those. It is programmers who will adapt.

Don't read too closely into Wired

Two things.

First, Wired practices very fast-and-loose journalism, so take it with a grain of salt. E.g., they consistently misquoted us.

Second:

But for now, I would like to focus on this curious statement:

Meyerovich also says the data he and Rabkin are collecting also indicate that programmers aren’t always taking the time to really learn a language when they start using it — and that this trips them up down the road.

You then share an anecdote about ActionScript, but have no hard evidence.

Misquoted :) I actually said that, according to our study, ActionScript programmers (unlike JavaScript programmers) typically believe they can see underneath the hood. That means programmer understanding of their tools is flawed. In the case of ActionScript, this can be costly if the typical AS dev believes that they can do something like build a game engine or DSP lib. It's possible, but high performance requires a lot of reverse engineering.

(And yes, Patrick Lam is great. Just had dinner with him :) )

Different forms of social optimizations

Because if you really truly believe we need socially aware languages, then you CANNOT go back on how you view tools like JetBrains Resharper. You have to view them as totally underutilized. Why? Because every time Resharper makes a suggestion the novice commits to, the tool has observed that its code is superior to the programmers. Ergo, if the tool itself was bootstrapping an intelligent tutor system, we could have "status reports" every month of so when the user opens their IDE, reviewing areas they may be weak in.

This finally gets into the constructive side of things!

In this case, what if a programmer misunderstands the semantics (e.g., writing C in Java), the APIs, ...? What should we do about it? A vague but useful CSCW model is "actor networks", where you essentially can replace people with machines, such as a pair programmer getting replaced by an automated tutor. The model is flawed in the sense of Ackermann's sociotechnical gap: technology augments, so just because a technology (like Resharper) exists, doesn't mean it's good. How the heck do we tell if Reshaper is actually good, and if not, what are good guidelines (design space axis) for doing better?

If you haven't read it, I suggest skimming our draft paper, and the last two big sections in particular. We cut many of the relevant theories and blue sky hypotheticals due to length, but I think you'll enjoy it.

Some thoughts and partial answers

1) Read the paper I linked to about how tutors use consistent patterns for identifying students weaknesses and apply associated consistent patterns to help them. It takes an expert systems approach.

2) The value in using actor networks to solve these sorts of "debugging" problems was first proposed by one of Hewitt's students, precisely for the problem of "automated tutors". Tutors was a big idea at MIT in the 70s -- Sussman did his thesis on tutors as well. Hewitt's student argued that actors could serialize all messages to an external database, and that this database could then be used to provide essentially infinite backtracking in conjunction with forward chaining, to provide rich problem solving capabilities.

3) How do I know Resharper is good?

Uhm, I suggested a way to measure feedback into the system. This isn't exactly what you want, but it is pretty darn good. Compare to that silly Visual Studio Token Economy mentioned on LtU a few months back. At least within the system I sketched out above, users are actually ascending some skill tree. It really shouldn't matter how good the skill tree is, because we're not Michel Foucault ;-)

4) I really want to read your paper, and more of your work in general. When are you going to have a better web page?

assuming more feedback is better than less...

According to the abstract's opening, the focus is socio-PLT, so a fish-out-of-water perspective might be useless. If I care little about social perspective, you might get that. I devote attention to a small number of close associates, so the opinion of others is just information, often cleaving toward least common denominator I dismiss.

(A dozen years ago, a coworker told me a new rule "everyone" had to follow, which I said I planned to ignore. He smiled and asked, "What if everyone did that?" When I criticized the premise underlying that question, he laughed and asked, "What if everyone made fun of the categorical imperative?!" It seemed funny at the time.)

Hypothesis 1. Working on the closure side of the duality increases influence on programming language researchers, but decreases influence on both practitioners and software engineering researchers.

From context I infer "the duality" is closures and continuations in functional langauges vs objects in the form of generators and iterators. You might insert parenthetical "(vs objects)" after the word closure, if you don't want folks to read the preceding section closely to figure out what the duality references.

Some languages (eg Smalltalk and Lisp) have collection methods taking a block/function as a first class argument, applied to every collection member. I like that style a lot. It's clear and small, and can be more efficient. But if the execution can be suspended in the middle, then later resumed, this confuses a lot of people because reasoning about the implicit state has few mental handles to manipulate. But explicitly coded objects to represent iterative state has a place to go consult for study, when reasoning. I know folks who love iterators and hate high-order methods. It's a strong bias.

If we pretend old Jean Piaget research is relevant, the object approach is more concrete and therefore easier. Piaget put a lot of effort into charting normative progress from concrete to abstract, culminating with more abstract operational thinking relevant to mathmetics in a child's early teens (if they get there at all, which I doubt in the case of some folks). Maybe we should assume concrete is mentally cheaper.

In programming languages it's possible for abstractions to fail in support for inspection and verification. A mathemetician would not tolerate mysterious propositions you need not prove, but it's okay to tell programmers they don't need to know? Hmm. Seems kinda patronizing, maybe asking to be ignored.

Hypothesis 2. Both programming language designers and programmers incorrectly perceive the performance of languages and features in practice.

Yes, usually. Designers of low level languages might do better. It's hard to pick a suitable cost model. Intuitive grasp of algebra is necessary to see weighting matters. (Bob drives a compact and Alice drives a hulking 60's gas guzzler; how much total gas is burned in their cross-county race?) And until you check empirically, it's easy to be wrong.

But there I talk about performance cost, and the section containing that hypothesis speaks of cost in a more abstract sense -- something like, "What am I giving up to get this suite of features?" That seems even easier to get wrong. Most people seem to underestimate the cost of dealing with anything present: more is less when each feature F added requires a programmer to think about it, perhaps more than it's worth. That's what you meant, right?

Solutions nearly always bring their own problems. There's a large class of design bugs related to problems caused by solutions. A classic one goes, "This 99% solution makes it impossible to handle the last 1%, because now it's in the way." More subtly, some solutions are all hammers, when sometimes you should really use a screwdriver. Since this is probably a fruitful place to have a long discussion, I won't add more examples. However, it's common in programming that folks want a house but build a shack on the lot first, which is in the way.

Hypothesis 3. Developer demographics influence technical analysis.

(The comment in that section on modularity bugs at human communication boundaries might explicitly reference Conway's law.)

It sounds like you're saying it's dangerous to pool results into commentary on what "average developers" do when it might only be a subset of developers involved. In short, you need a histogram. (Those are pretty important in display of patterns in statistics for stochastic systems like networking code.) Sounds good: avoid lying to yourself with statistics.

Hypothesis 4. Programmers will abandon a language if it is not updated to address use cases that are facilitated by its competitors.

There is competition, yes, so features cannot be weighed in a vaccuum. (This amounts to: context matters.)

Here's a personal example. I have used more C++ than anything else, but as C++ heads to higher level, I plan to go back to C because any new hand-holding is in my way. That's competition. More generally, your installed base competes with anything new you want to do, and your community might not follow.

Hypothesis 5. The productivity and correctness benefits of functional programming are better correlated with the current community of developers than with the languages themselves.

That is such a good hypothesis. (One that must be asked; I don't know if it's right.) It turns out you can write spaghetti code with anything. So it's worthwhile to look at features with an eye to what will happen when someone uses them in spaghetti code, because they will.

Hypothesis 6. The diffusion of innovation model better predicts language and feature adoption than both the diffusion of information model and the change function.

(This is a side note you can ignore. But here's a pattern to note. Ted tells Alice, "Bob says XYZ is really cool." But Alice replies, "Well, Bob's an idiot." Which generalizes to House snarking, "Well, everyone's an idiot." Sometimes you want to know the histogram of who thinks an idea is really stupid.)

I'm not quite sure I get the point of this hypothesis. I'm guessing it's this: "If your model has even more steps where adoption failure can occur, it might predict failure better." That sounds right. (I spend a lot of time thinking of everything that can go wrong before I think new code will likely work.)

Hypothesis 7. Many languages and features have poor simplicity, trialability, and observability. These weakeness are more likely in innovations with low adoption. [Typo: weakness.]

Hey, that's my song; I'm glad to see it here. From a social perspective, you might work up some kind of challenge-response model to predict more adoption failure when advocates cannot defend against critical challenges. Ted says, "This language sucks because X happens when I do Y!" But Alice counters, "No it doesn't, and here are clear examples showing what actually happens." From a non-social perspective, individuals want fast turn-around hypothesis testing.

Hypothesis 8. A significant percentage of professional programmers are aware of functional and parallel programming but do not use them. Knowledge is not the adoption barrier.

Plausible to likely as not an adoption barrier. I have trouble making statements of larger scope though. (To me they sound like, "But my friends and I know what we're doing!", which is suspect because it's self-serving, and there's lot of evidence everyone enjoys flattering lies.)

I see functional and parallel programming tactics go up as folks get more experience, especially with anything managing data, but it's done in the context of imperative languages like C, rather than using a functional language. The benefit of immutable data -- when it's shared by multiple control flows -- is so high that designs must explicitly revolve around when and how data becomes immutable.

(In practice, folks either cheat, or code too casually. So it's necessary to audit that data does not change when it should not. An api can announce, "If you pass me immutable data, I promise not to change it and I'll let you know when my last reference goes away." Then the caller changes the data while the callee is using it. Bad caller, bad. :-)

Hypothesis 9. Developers primarily care about how quickly they get feedback about mistakes, not about how long before they have an executable binary.

I compile far more often then I want to actually run a unit test, because I want feedback about whether I have started propagating bad code among several locations I edit. This would be painful if compilation was so slow it interrupted my train of thought. Library size can be used to limit max compile time when libraries can be compiled separately.

Hypothesis 10. Users are more likely to adopt an embedded DSL than a non-embedded DSL and the harmony of the DSL with the embedding environment further increases the likelihood of adoption.

Yes, because control over the top level environment is slight where there's a team and huge inertia in existing code. Since the top typically cannot be changed, the only way a new language can be used is via embedding, and only if the DSL knows it is secondary and has to behave within bounds established by the top layer.

Hypothesis 11. Particular presentations of features such as a language-as-a-library improve the likelihood of short-term and long-term feature adoption.

Almost tautological if phrased, "When a language says my-way-or-the-highway, sometimes a programmer chooses the highway." (But Neo has been there before, of course.)

Hypothesis 12. Implementing an input-output library is a good way to test the expressive power and functionality of a language.

It might also go hand-in-hand with trialability and observability when i/o is the only way to inspect.

Hypothesis 13. Open-source code bases are often representative of the complete universe of users.

Umm. I'm guessing probably not. But maybe close enough for what you want, or maybe you don't mind disservice for closed-source users.

(I must be thinking something will appear in closed-source that doesn't appear in open-source, and that maybe there's a correlation.)

Hypothesis 14. Most users are tolerant of compilers and interpreters that report back anonymized statistics about program attributes.

Sounds plausible, but will they believe it's anonymized without auditing it? Or if auditing is too much trouble and folks assume the worst? (Think about the challenge-response cycle with paranoid folks here.) Being able to turn that off would improve adoption.

Hypothesis 15. Many programming languages features such as modularity mechanisms are tied to their social use.

Features correlating with human communication boundaries, like modules, should interact with social forces and could affect adoption. (Ted tells his boss, "We can't use that on our team because of how it manages modules.") Some features can have an even bigger social than technical role when they facilitate Conway's law.

Agreed on many points. A few

Agreed on many points. A few things stand out --

Hypothesis 1. Working on the closure side of the duality increases influence on programming language researchers, but decreases influence on both practitioners and software engineering researchers.

I know folks who love iterators and hate high-order methods. It's a strong bias.
...
A mathemetician would not tolerate mysterious propositions you need not prove, but it's okay to tell programmers they don't need to know? Hmm. Seems kinda patronizing, maybe asking to be ignored.

We recently started polling developers on thoughts about OO vs. FP. In particular, about how interchangeable HoF are with objects. There was a lot of confusion.

A lot of techniques pioneered in the FP community work just as well in the OO one, and vice versa. If you believe social use advances invention and innovation, the perceived distance between HoFs and objects is problematic. The OO vs. FP divide is therefore inefficient in the social sense, and particularly troublesome given that practice is on one side and research on the other.

Hypothesis 6. The diffusion of innovation model better predicts language and feature adoption than both the diffusion of information model and the change function.
...
I'm not quite sure I get the point of this hypothesis. I'm guessing it's this: "If your model has even more steps where adoption failure can occur, it might predict failure better."

Having more steps is actually surprising. A cynic has more surface area to attack, finding things that are wrong, contextual, or should at least be deemphasized.

I found it useful in that diffusion of innovation is a rich working model, which we now know to 1) examine (falsify/refine) and 2) build upon for downstream PL research. For example, I hadn't really focused on observability until I saw it.

Hypothesis 8. A significant percentage of professional programmers are aware of functional and parallel programming but do not use them. Knowledge is not the adoption barrier.
...
Plausible to likely as not an adoption barrier. I have trouble making statements of larger scope though

Ah, but this is useful. It helps shifts the blame away from teaching / promoting PL concepts. Now we know to look further out.

The actual numbers get rather funny in our surveys. Many people claim to know about threads and tasks, but many less know about determinism. So, I'm not 100% on that hypothesis (and many others, such as the 13, which sounds very wrong). However, like the HIV prevention folks, we can actually start to analyze the situation and act on it in an informed way rather than adopting education policies, research trends, etc. that are not grounded in reality.

I think I can expand a bit more:

lmeyerov: We recently started polling developers on thoughts about OO vs. FP. ... There was a lot of confusion.

There's a concept "knowing what you know" I have heard used in the context of grasp of grammar. A person can know the rules of grammar, but not be able to cite them; so they can perform but not articulate. I think a lot of programmers don't know the terms used to describe some high level things, like closures and high order functions. I guess I'd be surprised if a majority of imperative coders knew words for HoF, but I'd expect most to recognize what's happening. (It's considered slightly weird if you do it in C, though, but folks rarely object enough to ask you to stop doing it when it makes sense.)

The point of abstraction is the ability to swap parts on one side, when details are hidden, because you couldn't depend on them anyway. I rarely see folks swap things though, even when testing. (But I think people in test-driven environments do, a lot more, especially when mocking interfaces.) So it's possible to use abstract or high level code and just ignore that aspect. Cut and paste doesn't require knowing what you're doing. What was my point? I don't see a lot of self-conscious review in coders.

There has been research done on how quickly folks perceive patterns (in decks of cards with different probabilities of yielding good or bad results in a game), and they see subjects appear to anticipate unconsciously well in advance of forming a conscious opinion. So a programmer can dislike something unconsciously for reasons they can't articulate in a poll. (Wow, that sounds a lot like BS; there's almost no way to test that, sorry.)

Having more steps is actually surprising.

I'm used to more steps yielding less pleasing results, especially in schedule estimates, which become longer the more explicit detail is noted. Nothing takes zero time.

It helps shifts the blame away from teaching / promoting PL concepts.

I don't know how long it takes before folks learn it in practice. There could be a shortfall in grasp of functional concepts just after basic learning. Everybody with ten years of experience who knows what they're doing says, "Yeah, yeah, I know," when you go through the immutable data parts of problems. And they actually do know, based on good planning and design. But I have a poor sample set size, and I'm not sure how the knowledge is acquired. Seems to be direct finger-burning experience with mentor debugging.

but many less know about determinism.

There's a problem with grasp of (non)determinism even when someone has lots of experience. It's worse in optimistic people with a natural expectation events converge, and a notion: "The world tends to be a nice place, left to it's own devices." An extreme variant -- rarely in a programmer -- is what I call a "one context" person who believes only one thing is true, and it's true everywhere, and exceptions are aberrations. Once familiar with what's "supposed to happen", they have trouble perceiving faults and their causes. People who are good at processing rules might expect rule-driven systems to actually behave according to the rules. :-)

Pessimists seem better at expecting non-determinism and its conseqences, especially if they expect divergence is natural, and believe in Murphy's law, etc, so things going according to plan is the exception.

Measure, don't assume.

I think a lot of programmers don't know the terms used to describe some high level things, like closures and high order functions. I guess I'd be surprised if a majority of imperative coders knew words for HoF, but I'd expect most to recognize what's happening.

From the trenches, I'd be surprised if even a quarter of professional programmers knew what's happening. And that number is as high as it is (at time of writing) only due to LINQ and jQuery.

But that's the thing; part of this research will hopefully involve objective views of what programmers know, and what they are even capable of using.

I'm all for measuring

RM Schellhas: From the trenches, I'd be surprised if even a quarter of professional programmers knew what's happening.

When I said my sample set size was poor, I meant non-representative. And it's currently biased as well as small: systems programmers where several have 30 years of experience.

I was addressing this implicit hypothesis: "If programmers only knew about functional programming, they would give up their wicked ways and follow the true light." (Other than hyperbole, did I get that right for some folks here?) But I know some coders who understand the ideas really well, and the result is using related techniques in C, since we ship in C. The idea of having a revolution and talking everyone into using a functional language doesn't reach the question stage. So despite my crummy sample size, I thought it worth reporting this particular "If A then B" proposal sometimes had B false when A was true.

Nobody understands JQuery

Have you actually read the code?

And LINQ is not all too easy to read, it just tends to be easier than for loops. Richard Hale Shaw, who is an extremely well-knowned .NET teacher, has a number of good talks on LINQ details with regards to common misunderstandings he sees on how iterators work and how they are resumed in concurrent settings.

Awareness != understanding

I am aware of the Large Hadron Collider, and to a certain extent I know what it does and how it does it. I doubt I would be able to use it, though.

I strongly suspect the same goes for the majority of programmers who are 'aware' of functional or parallel programming.

Simon.

People think sequentially ?

Regarding "burning questions", I'd like someone to tackle the belief that people think sequentially or find it intuitive.

It's something I hear repeatedly but I'm skeptical about. I am inclined to believe a claim that our language centers are mostly sequential, due to our limits of one mouth and tongue. But spoken language is not how we think, rather a constraint on how we express some thoughts. (Notably, experts rarely use their language centers to facilitate their thinking compared to beginners in a skill, at least in Chess.)

I've observed my own approach to programming, planning, building arguments - and it is certainly not linear. I sort of seed a program with different thoughts or goals, then meld them together. I've been designing paradigms and languages around this style of thinking - i.e. that support what I describe as "stone soup" programming: components and agents each contribute a few small skills or features, and they are merged together through common environment, discovery, and blackboard metaphors. The cost is that expression of linear behavior is somewhat awkward to express - still easily achieved, but in terms of rules with shared state. I think this is okay, since I believe very few problems are truly linear (we can't walk through the door before we open it, but opening and walking through a door involves a dozen concurrent challenges - like maintaining balance and avoiding obstacles).

Similarly, I disfavor many structured editors because I don't believe people think in a very structured manner. I would like enough structure to support multiple views with bi-directional editing (since I believe people think from multiple views at once), so there's a balance to be achieved.

Guess what a common complaint is when I try to explain this? That people think sequentially, and therefore (well, they don't say this explicitly, but bear with my inference) people won't ever rise above imperative programming. Ugh.

How people approach problems has a huge impact on how our IDEs and programming languages should be presented. I'd love some solid empirical evidence about how people approach non-sequential programming, especially beyond toy problems.

I've brought this up before,

I've brought this up before, and you made a fairly convincing argument against my perception that most people think about a solution in the form of a recipe or directions.

I would perhaps not be surprised if beginners' thinking (and thus language adoption) was starkly different than someone who is comfortable with a language. Certainly a good thing to measure.

I can't even remember that.

I can't even remember that. But it came up a few times more recently for me. It's getting to be a pattern.

Red Herring

The question of whether people think sequentially seems to me to be a red herring.

I am inclined to believe a claim that our language centers are mostly sequential, due to our limits of one mouth and tongue.

But then why do we read sequentially? Or maybe you'll argue that at a small scale, we don't and that we pick up parts of the sentence we're reading in parallel. Rather than try to answer this, I would ask, who cares? How does the answer affect how we program? I don't think it really does.

Parallel programming is in some sense harder than sequential programming because one technique for understanding programs -- thinking through traces of programs -- becomes much more difficult in a parallel setting whereas any technique that would let you understand a parallel program would also work if it happened to be implemented sequentially.

How much more difficult it is depends much on the extent to which you rely on this technique of thinking through program traces. If you're primarily using other modes of reasoning to establish the correctness of your programs, then it might not be much harder.

Do we read sequentially?

Do we read sequentially? I don't know, but I do know that at a high level (e.g. browsing Wikipedia) my reading experience is clearly non-sequential, and that at a low level it is quite irritating and difficult to read through a peephole even if it kept up with my eyes. I know from observation that I don't write sequentially. I tend to hop around, adding to sentences and paragraphs, modifying them. This leads to all sorts of tense and plurality and referent errors, trying to squeeze my thought patterns into a linear medium like text. I would not be surprised to learn that many others are similar.

It seems strange, to me, that you assume how we think and read would not affect our programming experience. How could it not?

any technique that would let you understand a parallel program would also work if it happened to be implemented sequentially

I believe this untrue. Knowing that two computations are computed "independently" in parallel - i.e. that one computation does not wait on another - is valuable for certain classes of reasoning (e.g. about denial of service, progress, fairness, latency). If we sequentialize a parallel program, we have difficulty reasoning with respect to divergence.

How much more difficult [parallel programming] is depends much on the extent to which you rely on this technique of thinking through program traces.

I do observe that adding parallelism to a paradigm designed for sequential expression and reasoning (imperative) has not been a pleasant experience for most developers, whereas modeling sequential actions on languages designed for concurrent reasoning (temporal logics, FRP, etc.) is relatively easy.

I don't see why would you

I don't see why would you expect the physical process of programming to have such an effect on what we're programming. In the real world, we're accustomed to time passing and things changing, but it's still easier to reason about things that aren't changing. Similarly, I think sequential is just fundamentally easier than parallel, regardless of how familiar it is.

any technique that would let you understand a parallel program would also work if it happened to be implemented sequentially

I believe this untrue. Knowing that two parallel computations are computed "independently" - i.e. that one computation does not wait on another - is valuable for certain classes of reasoning (e.g. about denial of service, progress, fairness, real-time properties for subprograms).

But you can compute independently in sequence, which was my point. You can always sequence a parallel process, and your reasons for why it works will still be valid. The other direction is problematic.

I don't see why would you

I don't see why would you expect the physical process of programming to have such an effect on what we're programming

Because naively, it seems as though there would be more 'waste heat' (for lack of a better term) or error chance the more the programming medium is different than our mental models. That likely causes some impedence which shows itself as a number of adoption, usability, or accuracy symptoms.

Category error

The relevant mental model is how we understand parallelism, not whether parallelism is present in our thinking. If you're working on an interrupt driven architecture, would it be helpful to be interrupted every few minutes? Of course not.

Dual arguments...

Programming is humans interacting with a computer to express their interests, policies, intentions, and obtain feedback, intelligence. The issue isn't how we understand parallelism, it's whether parallelism is present in our natural form of expression and interaction - i.e. does the computer language adapts to our needs, or must we adapt to the computer?

If we think or act in terms of interrupts (perhaps to cancel or undo) and wish to control systems by that means, then our PLs and IDEs and UIs - our programming experience - should make it easier to do, to live program in that manner.

[edit] I'm guessing you got confused about the different topics of "how we think" vs. "how we mentally model parallelism". Even if we don't understand parallelism (because our languages make it painful), I believe we think non-sequentially (i.e. forwards and backwards chaining, inside out, outside in, flitting from one subject to another like butterflies).

Programming Experience

In live programming it becomes obvious that there is no clear dividing line between UI and PL (and it becomes obvious that this is true for more than live programming). There is no clear distinction between the physical process of programming, how we express ourselves, and what we express. There is only the programming experience - how we interact with our computers to extend human reach and intelligence.

The traditional program life cycle, i.e. involving a frozen program and separate compilation, has bought us much pain and accidental complexity (primarily with regards to distribution, upgrade, persistence, security, debugging, and language integration) and a few dubious benefits. Things don't need to be that way.

I agree that it's easier to reason about things that aren't changing. It's easy to lie to ourselves and pretend things aren't changing. It would be better, IMO, to model this explicitly, i.e. via a staged interpreter, so we later can easily repair the program (live upgrade) when we find things have changed.

sequential is just fundamentally easier than parallel, regardless of how familiar it is

If the problem is such that there is a unique, predictable, sequential solution for it, this might be true. But most problems don't seem to fit the sequential mold very well.

you can compute independently in sequence, which was my point. You can always sequence a parallel process

Counter example: If you have parallel non-terminating processes, sequencing them will not result in the same system behavior as would running them in parallel.

What assumptions are you making that would make your claim valid?

Programming in the matrix

You don't need live programming to adopt a view of programming languages as user interfaces. The traditional program life cycle needs to be carefully extended to support live programming. If you just jump head first into the pool, though, you'll probably end up with something like smalltalk. Your "staged interpreter" comment seems to imply you have something more sophisticated in mind, but I'm still not on board with your desire to get rid of libraries. But we're heading off on tangents, as usual.

I agree that it's easier to reason about things that aren't changing. It's easy to lie to ourselves and pretend things aren't changing.

It's not always a lie. There are plenty of applications which have no need for persistence. You run your program and if it doesn't work you kill it and start over. When that approach works, it's simpler and probably superior.

Counter example: If you have parallel non-terminating processes, sequencing them will not result in the same system behavior as would running them in parallel.

What assumptions are you making that would make your claim valid?

I really just had in mind that hardware parallelism can always be emulated by task switching paralellism, but I think a suitable assumption would be that all processes terminate.

You don't need live

You don't need live programming to adopt a view of programming languages as user interfaces.

Of course. Live programming just makes this obvious, deep, strips away the illusions that there is a distinction between them (other than bad practice).

There is a difference between knowing this as an intellectual curiosity and knowing it viscerally, as a fundamental truth. Sort of like the difference between knowing people play football and actually playing football. To you, the relationship between PL and UI is still an intellectual curiosity. You don't really understand it.

It's not always a lie. There are plenty of applications which have no need for persistence. You run your program and if it doesn't work you kill it and start over. When that approach works, it's simpler and probably superior.

Did you just provide an example of a killable application (state change) that can be started over (state change) from a source (associated persistence) which was possibly modified (state change) as an example that things aren't changing and don't need persistence? I don't find it very convincing.

We can model things as constant between changes. And we can model a system as "static" if it changes at a much slower rate than the observer. These are convenient abstractions. But they're lies.

Failing to address the nature of change and program life cycle formally, and simplistic solutions like you suggested, are significant sources of accidental complexity and pain in our programming experience and HCIs. This isn't a subtle problem, but is so pervasive and systemic that it's difficult to recognize. We shouldn't need to restart our applications and operating systems to upgrade them. But we do, because that's the solution down at the lowest layers.

I really just had in mind that hardware parallelism can always be emulated by task switching paralellism.

Sequential would mean you can give an ordering to the processes as a whole, not to each tiny atomic sub-process.

When I spoke of people not thinking or approaching problems sequentially, it hardly matters to me whether it's parallel or fast "attention" switching, just that it isn't easily ordered on any particular dimension. I expect we do both.

Apologies in advance for the sarcasm

Live programming just makes this obvious, deep, strips away the illusions... viscerally ... fundamental truth ... heathen ... don't really understand it.

Claiming a deep connection between disconnected things seems like a great way to increase my profundity, so I'll go ahead and stake the claim that live programming, programming language design, and user interface design are actually all the same thing under the Curry Howard isomorphism.

I actually think the connection between PLs and UIs is quite important and have explored many related ideas over the years. I just think that connection is mostly orthogonal to live programming (which is also important).

Did you just provide an example of a killable application (state change) that can be started over (state change) from a source (associated persistence) which was possibly modified (state change) as an example that things aren't changing and don't need persistence? I don't find it very convincing.

Let me follow the reasoning: live programming encompasses all of the important activities we've been doing without live programming, and is thus indispensable. Hard to find a flaw.

Re: Apologies

The connection between PL and UI can be discovered without a good live programming experience. I agree. I've already said as much. However, my argument is that human ability to really grasp this relationship does not seem to be orthogonal to live programming - to experiencing it, or designing for it.

I actually think the connection between cargo shipping and the economy is quite important. I know it to be true. But my knowledge is shallow, based on History channel documentaries and armchair reasoning. I expect someone who actually understood shipping or economics would pick up on this pretty quickly, if I were to discuss the subject with them.

Let me follow the reasoning:

I'm not sure where you came up with what you wrote after the colon, but it certainly wasn't the reasoning. I'll offer you a better summary:

YOU: it's easier to reason about things that aren't changing
ME: sure, but everything changes. we should acknowledge this in PX.
YOU: untrue. we can model programs as constant between changing them when they're broken. oh, and restarts are often superior.
ME: the body of your argument contradicts your claim, and supports mine. oh, and restarts are a source of much trouble and pain.
YOU: you're just promoting live programming! here's a straw-man summary and some sarcasm. false apologies in advance.
ME: I poke holes in your argument and promote live programming. In parallel, BTW.

Maybe not too far apart

Live programming is probably a good setting for understanding many things better, but I think most people would have no trouble grasping a language that did a good job of UI as PL, even if it didn't support live programming.

I guess the rest of the apparent disagreement is just my misunderstanding of what you mean by Live Programming. I still don't fully grasp what you're arguing, but I'm guessing it's reasonable and I just don't get it.

UI as PL

Every UI is already a language - with a grammar of checkboxes, textboxes, buttons, and so on. Many UIs make bad PLs, or very domain specific, or both - the PL equivalents of HQ9+. (Some days it seems we're at the level of: "Jump up and down on your seat to honk your horn!")

To do a good job of live programming requires doing a good job with the UI experience - i.e. maintaining stability across edits, ensuring consistency between system behavior and code, not losing important work. Conversely, live programming enhances the UI experience with a good PL experience - flexible abstraction, composition, extension; good debugging and testing or error prevention; etc..

It seems to me that "good job of UI as PL" implies live programming, and vice versa. You indicate that the concepts might be separated, but perhaps we have different ideas of what "good job" means. Hypothesis: any example of `UI as PL` that is not live programming will be inferior in both roles.

There aren't three problems - UI, PL, Live Programming. They're different perspectives on the same problem.

Maybe we're not so close

Every UI is already a language - with a grammar of checkboxes, textboxes, buttons, and so on.

This seems confused or at least stated poorly, but maybe we have completely different things in mind as "UI as PL". Here's my take: Any particular UI can be viewed as a user control for manipulating a data value. The UI as PL point of view comes from treating that data value as a program to be interpreted. A UI with two checkboxes and a textbox doesn't correspond to a language with checkboxes and textboxes as its grammar. It corresponds to a language with a single AST node annotated with two booleans and a string. The language that has a grammar of checkboxes and textboxes corresponds to a special UI for building UIs, not any particular UI.

"Live programming" to me mainly consists of solutions to the schema update problem. My view seems close to the one Jules just posted about in a sibling post to yours. I still see it as orthogonal.

UI with two checkboxes and a

UI with two checkboxes and a textbox doesn't correspond to a language with checkboxes and textboxes as its grammar. It corresponds to a language with a single AST node annotated with two booleans and a string.

That's one valid perspective. Another is that the UI - a GUI in this particular case - is a system that interprets gestures from the mouse and keyboard. And the language is, therefore, the system of gestures that it interprets.

This gesture interpretation does not reveal anything more than your own, might even seem to obfuscate, if faced with two checkboxes and a textbox. But as we see buttons, canvases, drag-and-drop, animations (with associated timed inputs), I think it will seem more legit.

My dictionary describes a language as any formalized communication system considered in abstract. There is no reason that an AST is the only valid abstraction with which to consider a language. Abstracting language in terms of a grammar of widgets (with associated gestures) works relatively for GUI.

"Live programming" to me mainly consists of solutions to the schema update problem.

Well, solving the schema update problem is certainly a big part of live programming.

I see

Another is that the UI - a GUI in this particular case - is a system that interprets gestures from the mouse and keyboard.

One thing I don't like about this approach to definitions: look at what it would mean if applied to the UI for a text programming language. The corresponding language wouldn't be the original language, but some new obfuscated language of keystrokes and mouse clicks.

But anyway, that explains what you meant above, I think: you meant a grammar of textbox manipulations, checkbox manipulations, etc.

Grammar of Blubs

One thing I don't like about this approach to definitions: look at what it would mean if applied to the UI for a text programming language. The corresponding language wouldn't be the original language, but some new obfuscated language of keystrokes and mouse clicks.

I don't see a problem. I have no difficulty understanding "the UI for a text programming language" as having a language of its own, distinct from the "text programming language". It's a valid abstraction, though perhaps not a useful one in the cases you have considered.

We can design text programming languages for streaming interpretation, for manipulating and maintaining system behaviors primarily in terms of appends. I.e. consider something like a textual command-line language, perhaps even a declarative command line. In this case, the relationship between the programming language and the UI language would not obfuscate; I expect it would actually reveal a great deal about the design and purpose of each.

I assume the "text programming languages" you are imagining are not designed with an effective, consistent UI experience in mind beyond a myopic view of notation - and hence the result is a more complex UI and UX, difficult debugging or testing, and awful UI-as-PL that only obfuscates. It's all accidental complexity, the cost of being simpler than possible. That's what we get when we don't take UI as PL seriously.

I think: you meant a grammar of textbox manipulations, checkbox manipulations, etc.

I meant a grammar of widgets where I described it thus. To consider widgets as an abstract means of communication from human-to-computer and computer-to-human - language for influencing systems in both directions - is valid. A grammar of widgets does, of course, admit a corresponding language of "manipulations".

Live vs modal

I'm a bit new to this, but it might help to see "live programming" as a gradual rejection of modal programming, where either we're in the text editor, we're in the REPL, we're in the debugger (at a particular source location), we're running the program (navigating its own modes), etc. Live views help us without obstructing the other helpful parts of the UI.

Different language semantics and programming styles might be conducive to different programming experiences, including live views, so live programming concerns are relevant to language designs in general.

If for some reason we only care about developing a program to do a one-shot calculation, that hardly matters. We still build that program in a gradual way, so the UI we're using has plenty of opportunity to clarify and streamline our work as we go along.

RE: Live vs. Modal

This is an interesting view that I hadn't considered, Ross. I like how it tastes, but I'll need more time to chew on it.

Perhaps dmbarbour means

Perhaps dmbarbour means something like this:

All programming languages are UIs, even C with a text editor. By taking the viewpoint of programming languages as UIs seriously, we can improve the UI aspect of programming languages. Live programming is an UI aspect. If you have live programming, the UI aspect of programming becomes more obvious: it's not just the code on disk that matters, but how you interact with it. Conversely, if you take the viewpoint that programming languages are UIs, then you'll inevitably be led to live programming.

But such abstract discussions are mostly discussions over the meaning of words, rather than about the meat of the matter. I think a discussion on how this live programming might work is more useful. The central problem seems to be state. Live programming implies that when you modify some code, the application keeps running with the same state. The state being retained is the difference with restarting the application.

Smalltalk keeps all state. Live programming in Smalltalk is swapping a method another while the application is running. This can easily break invariants. From a theoretical viewpoint it's surprising that this works at all. On the other end you have languages that throw away all state and restart the application from a fresh state. That doesn't break any invariants but isn't live programming either.

Perhaps a model to get to a more useful place is explicit migration of state. There is an explicit procedure to extract state from the application before the edit, a procedure to compute the new state based on the old state plus the edit, and then you run the new application (with edit) with the new state. At least you have a handle on the problem rather than randomly swapping out a pointer. The question is what should these procedures be?

It seems to be a good idea to extract the state at the point where no application code is running anymore. So you first let any event handlers run to completion rather than modifying the code in the middle of an event handler. If you've done that, the only problem that remains is if the programmer changed the representation of data. Some changes can be handled fairly easily, for example deleting a property from a data type. Adding a property is more difficult, because the old state doesn't have a value for that property. Even more difficult is if the representation is changed, but when this isn't visible in the data type definitions. For example the application before the edit might be working with a list of things, and after the edit it's working with a set of things.

We could of course ask for programmer intervention in these cases, but it's difficult or impossible to detect some of them and it defeats the purpose of live programming. How to solve this?

Well said, Jules. I agree

Well said, Jules. I agree with your summary of my meaning and the description of (part of) the problem. There are some related problems, too, such as stability of the UI (especially in a concurrent edit scenario) - can't have an icon jumping out from under someone's mouse, for example.

I've found it useful to model certain things explicitly.

Rather than "freezing" the app to wait for some event handlers to run, I add temporal tags to everything - the events have tags, so does the code update. Locally, there is an atomic switch in the code at a given logical instant. I also model the propagation of code changes in a distributed system formally - i.e. in terms of dynamic behaviors and signals literally carrying code from place to place.

Stability client-side (assuming that the developer isn't the only client of his code) is achieved by using intermediate state anywhere stability is needed - i.e. to freeze icons under a client's pointer.

Other aspects I've found useful to avoid.

Significant changes in state representation I avoid by eliminating internal state from my model, shoving everything into external state models. Of course, that doesn't avoid the problem entirely, but it does simplify the remaining parts of the problem: (a) by designing the state models appropriately, I can make them robust to most schema changes in terms of extensions and abstractions (i.e. SQL-like views coupled to the state). (b) if schema change is necessary, the developer can add a transition path, i.e. create an agent to systematically translate old data into new data, or add extra code to the observers to interpret old data as new data.

To help with the issue of recognizing a problem and alerting the developer before it grows: I expect analysis could recognize most cases. But I also support anticipation with the possibility to observe a behavior and abort if it seems problematic (I recently blogged on the issue of avoiding commitment). Either would allow a developer and user agent to get a transition path in place before there is a problem.

Explicit schema migration is

Explicit schema migration is a good option for migrating a web application to its next version, and this is also an interesting problem as you don't want an edit to causes O(n) of downtime where n is the size of your state. But I don't think it's a good fit for live programming. When live programming the data isn't that valuable, and I think it's better to have some heuristics and restart and have a quick way to get back to the same situation in the new application than always try to migrate the old state explicitly. For example if you are developing a game, and you change some aspect of the world representation in an incompatible fashion, it makes more sense to just throw away the game state and restart. In addition it might be helpful to have quick ways to get to the same state. For example by automating the UI like Selenium tests.

The goal of live programming is to let you quickly see the results of code changes. For this it is often helpful to have more than one live program. For example if you are making a web application, and you're changing some aspect of the layout or some other cross cutting aspect, it's useful to see what the effect is on multiple screens. For example you could record a bunch of sessions of a human interacting with the application in some way. Then on a code edit it would replay those sessions and highlight the ones that your edit affected. You'd need a way to easily keep the scripts that control the UI up to date with the new code. For example you don't want to redo all your test scripts if you introduce a margin around an UI element that results in tons of the automated scripts clicking the mouse in the wrong place. So you'd need to find the right level of abstraction to express the test scripts.

If you take the FRP view then the mouse/keyboard input is the first layer, and the time-varying application state is the bottom layer. A program is something that translates the mouse/keyboard input stream into an application state stream. What I'm saying is that for live programming you don't necessarily want to migrate the bottom layer (by writing an explicit migration), but on the other hand you don't necessarily want to migrate the top layer either (by redoing the recorded session). Finding a way to express the right tests at the right layer and a way to migrate that layer after a code edit is, I think, the key to something that easily lets you see the results of an edit.

Live programming vs. continuous testing

I'm uncomfortable with the general focus on "live programming" as the ultimate goal of "interfaces to PL" work displayed in this thread. I personally expect to see more productivity benefits from a systematic reduction of the edit-feedback loop (syntax checking, type checking, and tests) than funny and not-well-defined ways to "interact live" with the program.

In my view, the tests that should be run continuously along the program and reported through a good UI are an extension of static checking (enriched with checks best expressed by programs, rather than type-level specifications), rather than a dynamic affair.

"Live visualization" of the running program seems useful for some problems domain only, where correctness of a change is very hard to test automatically, and easy to test for an human (eg. aesthetic of a web design, naturalness of a body animation, etc.). I believe they could we huge wins there, but am not convinced this is so useful in general -- automated testing looks easier to handle for a good UI and more conductive to productivity benefits. Maybe what you call "live programming" in this case is the way tests results are reported (things turning green or red in a corner of the screen, plus good UI to get explanation of what was tested and what the results were).

In any case, the kind of language feature that need love for such a "continuous feedback" scenario seems to be exactly those that languages interested in interactive/live programming have focused on. When a change a function, I want only tests that possibly involve this function to be re-run, to get feedback earlier. This requires a dependency analysis informed by my language semantics. If I understand correctly, such dependency analysis is also a very important aspect of live program modification. So I believe the two views/motivations are quite compatible and converge toward a general goal of more tool-able languages.

I don't think anybody is

I don't think anybody is saying that live programming is the ultimate goal of interfaces to PL. Rather that the goal of live programming, namely reducing the time it takes to see the effect of a change, is a very important goal in interfaces to PL. I probably didn't make it sufficiently clear, but I actually tried to advocate moving *away* from live programming to continuous testing as a method to achieve that reduction in feedback time. Of course static analysis is a totally valid approach too, and it is even complementary to testing in a precise way (finding a proof vs finding a counter-example).

Visualization is very useful in almost all areas. Applications that have a user interface encompass maybe 95% of all programs. For those programs seeing the program run is not just useful for judging aesthetics: it's also useful to see if it's working correctly. For example for a LtU-like website you want to see that if you post a reply by typing something and clicking the "Post comment" button, that the reply actually appears in the thread. You could of course test this programatically by inspecting the generated HTML, and this is sometimes done. But in my experience most people just fire up their browser and test it there. [btw, for some cool stuff see Visual Studio 11 for ASP.NET: if you hover your mouse over a line of code the browser highlights the elements that were affected by that line, and if you hover your mouse over an element in the browser the IDE highlights the code that generated it -- Google "visual studio page inspector"]

That doesn't mean that programmatic tests are useless: for less mundane things they are very useful (but keep in mind that most code is mundane). Even for those things, like sorting, function minimization and linear programming, visualizations can be incredibly helpful. Seeing the steps of the simplex algorithm visualized so that you see the algorithm jump from vertex to vertex (or not, if the program has a bug) is very useful. Conventional testing tools just have a tiny communication channel to the programmer: a list of booleans that say which tests failed/passed. Should we cram all useful information about the workings of a program through that channel? I think the approaches are complementary: first find an input that leads to incorrect output of your sorting routine with a quickcheck-like tool, and then view a visualization of the sorting process.

The goal of live programming

The goal of live programming is to let you quickly see the results of code changes.

While this sort of productivity is a nice consequence of live programming, it is not what motivates my pursuit of live programming (not my goal). I seek live programming because it leads to a better user experience for all users, not just the programmers:

  • it explains software upgrades in a formal and securable manner
  • allows us to model UI as live programming, making UIs more mashable, extensible, and programmable
  • subtly teaches regular users programming concepts in a consistent manner from a young age, just using PL as UI
  • live programming is more concrete, easier for young people to grasp, like a craft
  • progressive disclosure to anyone who cares to look more deeply or tune their UIs
  • avoids accidental complexity at certain boundaries, i.e. service oriented architectures generally have no restart button

Live programming is a necessary (though not sufficient) condition for my vision. A similar requirement is a gradual learning curve (no big discontinuities, not too much abstraction).

just throw away the game state and restart

What you're really saying is "let's leave this to the OS and external tools". You thus incorporate a user and programming experience of dubious quality and security, outside your control, poorly integrated, and imprecise and inconsistent with your language semantics.

I don't mind modeling restarts explicitly. Making it explicit allows me to restart specific subprograms or extensions, and results in a more consistent experience. (Many other process control patterns also benefit from explicit modeling.)

Hmm, any thoughts on how to

Hmm, any thoughts on how to ask these? We can get at perceptual bias -- whether programmers would agree with you without any proof. Getting at the underlying process is much trickier.

Btw, in terms of thinking, many researchers believe mental processes do have a sequential basis. Jeff Hawkins pop sci book clearly builds upon many neuro+cog sci theories to discuss how the brain (often) processes in terms of stories. For example, prediction is imagining a new story, while remembering is playing an old story. There is tension with other theories such as parallel association (see Big Book of Concepts for a very readable cog sci literature survey on learning), but the dischord often isn't too great. E.g., parallel association still works under his model because the model is hierarchical: stories might compete up the hierarchy for attention and down for action.

Testing

Hypothesis: people are a lot less aware of how they think than they believe they are.

For testing, it would be useful to record how people move between reading and editing different parts of a program, mean number of statements or words read between changing tasks, mean number of tasks per period, etc..

Note: sequential bias would suggests something stronger than "imagining a new story"; it would mean "imagining a story in sequential order". I expect that in practice we imagine many temporal points at once (i.e. know the ending of a scene before we know the middle) then chain them together.

For testing, it would be

For testing, it would be useful to record how people move between reading and editing different parts of a program, mean number of statements or words read between changing tasks, mean number of tasks per period, etc..

Ah, I should clarify: we've been doing surveys, with ~400-1500 people at a time. So anything that would fit under that model :)

I expect that in practice we imagine many temporal points at once (i.e. know the ending of a scene before we know the middle) then chain them together.

Yes, I did mean "imagining a story in sequential order" (or in jumps, with each jump to another sequential segment). The jumps themselves may also be abstracted into a sequential sequence. ("I did this, [ruminate on what that was], which led to that"). This seems related to the hierarchy notion as well (it's not "just" stories).

As an application, this is somewhat related to ideas on organizing IDEs based on working sets. The sequencing part of the hypothesis would suggest such researchers should investigate temporal working sets: one view/workset should lead to another.

Temporal Working Set

researchers should investigate temporal working sets: one view/workset should lead to another

That's an interesting observation. Though I'd ask instead how we can support developers in achieving spatial and temporal working sets without thinking about it. I expect Code Bubbles would be a good place to start.

I think the problematic and

I think the problematic and implications of our mind's functioning even stretches way beyond a mere sequential bias vs. parallelism bias of perspective.

Of course, to achieve a most often underspecified goal we make lists of things to perform in sequence. Be it conscious or not. Of course we're also able, at any single point in time, to keep open ten or so "ontological handles" (re: our problem solving analysis and/or strategies) all available for simultaneous/parallel use, or even sometimes overuse (cf. David's "don't forget to kill your darlings" metaphor).

But there is likely so much more to that alone. Be you well educated from academia, or self taught, or some mix thereof in between, there's always this overwhelming tension between the amount of effort we eventually figure we had to spend in trial and error processes, tedious, often sequential, and all these much more rare aha! moments where several things finally and simultaneously fit together and teach us how much accidental complexity has distracted us from the solution.

We apply divide and conquer all the time, on many different levels of abstraction. It's what I like to call the unique zoom in / zoom out computational feature of our brain. It s of course largely un- deterministic but is stunningly powerful:

this allows us from one second to the other to switch our mental mode in such a way that we go from considering something, say, as an implementation issue, to a more likely design flaw after reminding ourselves what were the premises for the objectives we had settled to achieve.

I would put what we traditionally oppose as of sequential nature vs. of a parallel one on two axis. Let's pretend the dumb Turing machine lives in Flatland and can't see the world other than thru seq vs par lenses.

My best guess is our brain, permanently sliding up and down a third axis, motivated by invention or standardization, or whatnot, is able to look down sometimes too close, sometimes from too afar, and also sometimes finally decide it got the big picture clear enough for a given milestone. I think it's because our natural language is able to manipulate languages as first class values that we agree upon to list in dictionaries for (of least possible ambiguity) references.

I suspect that human's

I suspect that human's working memory is 7 +-2 paper (and it's criticisms) would touch on similar sort of investigation. What people keep in working memory when coding is likely related to what information they need/use to create an implementation?

Interesting paper and nicely

Interesting paper and nicely made survey.

I enjoyed taking the latter.

This is a great paper. Just

This is a great paper. Just one small point: I think you mean duality between ADTs and objects, not closures and objects? Although AFAIK objects like in Java and C# don't cleanly correspond to either side.

My hypothesis for Question 1 is that multi-shot continuations don't interact well with state. For example if you implement the classic `amb` operator and then do:

filter(xs, x -> amb(true,false))

This computes the powerset of xs and works perfectly if filter is implemented in a purely functional way. But if filter is implemented like this:

def filter(xs, p):
  ys = []
  for x in xs:
    if p(x): ys.append(x)
  return ys

Then it fails horribly. This is because calling a continuation doesn't revert imperative updates. With continuations the implementation details of internal state leak out and become global state. Continuations are just not useful enough to make the trade-off between being able to use internal state and being able to use multi-shot continuations. Co-routines are useful since they remove the need for turning your code inside-out when you want to make it asynchronous (which is why some form of coroutines was added to C#). I do not think there is any particularly social reason for why we don't see continuations used a lot.

In fact, backtracking with

In fact, backtracking with state reversing has been studied (eg. it's at the core of the notion of "worlds" in Oz, if I remember correctly; or at least there's a lot of examples of it in Peter Van Roy's excellent CTM book).

If you make state explicit using monads for example, you would have to decide how to compose those two effects. You can have continuation as the "outer" effect and state as the "inner" one, or the other way around. In Haskell with monad transformers this is quite clear; but other notions of effects speak about this (difficult) composition as well, see for example Andrej Bauer and Matija Pretnar's introduction to eff.

In your example, you appear to live in a language where both states and backtracking are ambiant effects, so indeed you are probably bound to the language designer's choice of how to interleave them. But that's maybe not a facility, you could think of effect annotations to say "here i'm speaking of the backtracked state".

Choosing how to compose state

Generally state is used to make code run faster (for example filling in an array with filter instead of functionally building up a list). In that case the state layer has to be the lowest layer, because it has to the the state natively provided by the machine. In particular it has to live below any (delimited) continuation effects. Backtracking state is expensive. It would be nice if we could keep the efficiency of state in the places where it is not used along with backtracking, while also having backtracking be reasonably efficient (in particular copying the whole heap is not good enough). Perhaps Oz worlds and maybe work on software transactional memory in imperative languages helps here.

Eff is very interesting work on the theoretical side. Indeed if you build state on top of their handlers, then any internal state is automatically backtracked over. This is not the case for their resource based implementation of state; that has the same problems as conventional state. For eff to become practical I think two things are required: (1) Efficient implementation (probably a lot of the work on implementing delimited continuations applies fairly directly) (2) General effects have some of the problems of fexprs, namely that fewer terms become contextually equivalent. So we need idioms, library design principles, and rules for reasoning about effects, perhaps formally in the form of a type system.

This is a great paper. Just

This is a great paper. Just one small point: I think you mean duality between ADTs and objects, not closures and objects? Although AFAIK objects like in Java and C# don't cleanly correspond to either side.

Not so complicated, I just meant in the sense of Guy Steele etc. An object can encode functions by having only one method, apply. A pure function can encode stateful objects by having any state modification return the updated record (a la one of the early chapters of TAPL). If mutation exists, closures would make this more faithful.

There seem to be a lot of theories about the adoption of continuations :)

I'm not sure if there really

I'm not sure if there really is a strict duality here. The difference between what you call OOP and what you call closures seems to be support for records vs no support for records. In Cook's treatment at least, objects = records + closures. Of course you can encode a value as a record containing just that value. But perhaps I was the only one confused by the word "duality". Duality to me suggests a two-way mapping such that if you go from one side to the other side and then back you end up with the same thing.

My reason for the non-adoption of continuations is pure speculation of course. Whether you can talk about reasons in a non-repeatable experiment also raises philosophical questions. Even if you ignore that issue there are multiple levels of reasons. For example the reason why Java programmers don't use conitnuations is because Java does not have continuations. But why doesn't Java have continuations? etc. My far-fetched theory says: Although Java's original designers were familiar with Scheme/Lisp, and were inspired by its semantics (and copied a lot of its semantics into Java: pass by reference, garbage collection, etc.), they didn't copy continuations because they didn't see any important applications in the Scheme programs they were familiar with, and because continuations were difficult to use in conjection with mutation (which is especially problematic in a language like Java because mutation is used so much). So not very useful + has problems with mutation => no continuations in Java ;)

Objects and closures are the same in lexically scoped languages

This is the point behind the title of this website. But it is further exemplified by the prototype-based approach to programming, where you essentially create closures from other closures.

As for why Java doesn't have X, there is no need for a far fetched theory. Gosling, as well as former Sun researchers who tried to shove X, Y and Z into Java, will all tell you that Gosling had a golden design rule: If more than 2 people didn't ask for a feature, he would not do it, no matter how much sense it made.

Gosling's design rule

Gosling sure could have coupled that golden rule with an eye towards sample size and bias.