Lambda the Ultimate

inactiveTopic Bricklin: Why Johnny can't program
started 9/17/2002; 11:13:54 AM - last post 9/23/2002; 12:05:25 AM
Ehud Lamm - Bricklin: Why Johnny can't program  blueArrow
9/17/2002; 11:13:54 AM (reads: 2818, responses: 17)
Bricklin: Why Johnny can't program
As a result of the Trellix blogging announcement I have been involved in a flurry of discussions with people about blogging, about various tools and features, and about differentiating the various blogging systems. One thing that came up in a discussion with Amy Wohl, as a follow up to her article about the Trellix offering, was this question: "How do you explain that function accessible through programming and function designed for consumers is not exactly the same thing?" Here are some of my thoughts

This is somewhat related to the idea of end-user programming.

End-user programming, PBD, and direct manipulation languages, are somewhere along the line between programming and conventional user interfaces.

Posted to teaching/learning by Ehud Lamm on 9/17/02; 11:14:27 AM

Michael Vanier - Re: Bricklin: Why Johnny can't program  blueArrow
9/17/2002; 10:33:05 PM (reads: 2138, responses: 1)
The article is well-written and touches on some interesting points. It is fascinating that spreadsheets, which are arguably as complex as many programming languages, are still much easier for naive users to program in. Bricklin hits on many of the reasons for this (instant feedback through visualization of intermediate results, etc.) but fails to point out that most people use spreadsheets in extremely simplistic ways. In other words, there is little real programming going on; it's mostly just data display with a little computation layered on top of that.

Another point that wasn't in the article but that I think is fascinating is this: the things that naive programmers complain about and find difficult or helpful are not at all the things that experienced programmers find difficult or helpful. For instance, it's unlikely that a naive programmer would appreciate the extent to which something as esoteric as garbage collection could dramatically simplify the life of a serious programmer (because of the lack of memory leaks which previously would have required endless debugging time). Most naive programmers have never written a program large enough so that memory leaks are a factor. Thus, the kinds difficulties in programming vary a great deal with the scale of the problem.

At various times I have gotten interested in the notion of end user programming and how it can be made easier. Now I think that those who work in this field are largely deluding themselves. There is a limit beyond which programming cannot be made any simpler, for the following reasons. Let's suppose you are writing a program which has to do some kind of sorting. In order to do this effectively, there is no substitute for understanding sorting algorithms, orders of complexity, and the interaction of sorting algorithms with the data structures that they act upon. This is absolutely fundamental, and no slick novice-friendly GUI-based environment is going to change that. You could make the same comment about understanding data abstraction, modularizing designs, and many other topics that bear on programming. There's nothing wrong with giving naive users better tools to write simple programs with, but the notion that these tools are going to enable these same users to write serious programs without the naive users having to learn anything about the fundamentals of programming is misguided. To do a good job in programming as in any field, you simply have to understand the fundamentals.

I think that the notion of end-user programming comes out of the idea that programming is a simple skill like typing, driving a car, or using a TV. Nobody complains about the fact that people with no knowledge of mechanical or electrical engineering can't design automobiles, but the notion that good programming is a profoundly difficult intellectual activity is one that seems to be very hard for many people to accept. I think this is because programming is a lot like writing; it's very easy to do badly, but very very hard to do well.

Wow, this really turned into a rant! ;-)

Alex Moffat - Re: Bricklin: Why Johnny can't program  blueArrow
9/18/2002; 7:00:15 AM (reads: 2089, responses: 0)
To use the "end user computing" or "you don't have to be a programmer" systems I've seen the user still has to understand the concepts of variables standing for values, conditions, and loops, among others. So, is it possible to remove these requirements, or are they fundamental, and are there users who are unable to understand them? Is there a portion of the population who will never be able to program, or is that just elitest thinking, and it's matter of presenting the information correctly? On the other hand as you make it easier and easier does it cease to be programming? Is "programming" a VCR really programming? Sorry, all questions and no answers.

Ehud Lamm - Re: Bricklin: Why Johnny can't program  blueArrow
9/18/2002; 12:39:30 PM (reads: 2251, responses: 0)
I agree with your sentiments. Indeed, much as I like end-user programming, I have long felt that it should be focused on end users! It shouldn't try to replace 'real programming'.

Never the less, I think end-user programming teaches us interesting things about programming. Mainly, how to develop intuition about processes.

Writing about spreadsheets several years ago, I tried to compare them with language based statistical tools. Here is a rough translation of some relevant paragraphs:

Execution Model. The execution model is the, explanation, most often intuitive, of the behavior of a system based on a declerative language. Since in such languages the programmer doesn't specify the evaluation order, many systems found it helpful to provide a general notion of how evaluation is carried out. This model helps the user understand the consequences of his interactions with the system. Spreadsheets aren't declerative programming languages, but they provide an interesting execution model...

Changing one cell causes recalculation of all dependent cells. Since a formula may depend on other formulas, the recalculation process isn't trivial, and can indeed be quite slow....

The kind of statistical analysis is determined by the choice of formulas. This model is almost the opposite of the declerative model, since the user must know exactly which formulas to use, on what data, and what to expect as a result (one number, a vector etc.) This model is almost an imperative, low level, compuational model. There are two main differences. The secondary being that the user can use high level formulas, like "average of a and b" and doesn't need to specify how to calculate this value. The main difference between the spreadsheet model and an impperative programming model is that the order of evaluation is determined by the system, as explained above...

In this way to user does not have to discern all the data dependencies, and can request an average of averages, before calculating the averages themselves...

The nesting level is potentially infinite, since there is absolutely no difference between using input data, and using the result of a previously calculated formula.

jon fernquest - Re: Bricklin: Why Johnny can't program  blueArrow
9/19/2002; 2:10:13 AM (reads: 2042, responses: 1)
The author doesn't seem too favorably inclined to strong typing in languages. It is true that:

End-user programs are usually small and conceptually simple, almost synonymous with scripts written in scripting languages.

Most "real programmers" work in teams on complex products with many features in systems programming languages such as C++ or Java. Cardelli's paper Typeful Programming makes the point that it is these large complex software systems that need types.

But some types of end-user programming could probably benefit from types.

End-users doing large complex simulations: Symbolic Simulation of Microprocessor Models using Type Classes in Haskell (1999)

The parsing of natural language: HPSG

I'd bet that as more software models of complex systems come into use, typeful end-user programming will become more important. Domain experts specify the complex system with a typeful end-user program executed by a DSL compiler or interpreter written or generated by a "real programmer", i.e. a programmer with a background in computer science. (There's a Division of Labor (Adam Smith))

Ehud Lamm - Re: Bricklin: Why Johnny can't program  blueArrow
9/19/2002; 3:02:32 AM (reads: 2126, responses: 0)
You know, a langugae can be typed, and programmers may not even know it. You just have to produce good error messages

I can imagine DSLs for which I'd choose this approach.

jon fernquest - Re: Bricklin: Why Johnny can't program  blueArrow
9/20/2002; 3:05:16 AM (reads: 2000, responses: 1)
> You know, a language can be typed, and programmers
> may not even know it.
> You just have to produce good error messages
> (I can imagine DSLs for which I'd choose this approach)

Sounds great, but isn't the amount and earliness (compile time) of type checking and the error messages generated when the casual programmer has been a little lazy going to be directly proportional to the language's annoyingness as far as casual end user programmers are concerned? Is there really anyway around this?

You can usually get a once off script to run quickly a few times... maybe forever if it isn't too complex....but if it grows bigger or if there is some unforeseen input?

Also IMHO all the runtime automatic type conversions that are very popular in end user scripting make scripts a little dangerous when they grow in size and complexity and range of input.

The generalizations that Caredelli sprinkles his "Typeful Programming" paper with give you a lot to think about:

Cardelli on Scale.

One should worry about the organization of large programs, both in terms of notation and in terms of language constructs. Large programs are more important than small programs, although small programs make cuter examples. Moreover, most programs either go unused or become large programs. Important scale considerations are whether one can reuse parts of a large program, and whether one can easily extend a large program without having to modify it. A surprisingly common mistake consists in designing languages under the assumption that only small programs will be written; for example languages without function parameters, without proper notions of scoping, without modules, or without type systems. If widely used, such languages eventually suffer conceptual collapses under the weight of ad hoc extensions.

For scripting languages, small programs are more important, I would guess, but do they scale well? Could you create a huge feature bloated program like MS Word in a scripting language or would the whole thing collapse under the complexity of the task?

Ehud Lamm - Re: Bricklin: Why Johnny can't program  blueArrow
9/20/2002; 3:25:37 AM (reads: 2081, responses: 0)
Oh, I agree. I wrote about me experience with Python, a few months ago. It is a lovely language, but discovering simple mistakes after the program runs two hours is really really annoying.

We should make clear what we are talking about. Are you thinking about untyped (aka unityped) languages or aobut languages with dynamic or latent typing?

Michael Vanier - Re: Bricklin: Why Johnny can't program  blueArrow
9/20/2002; 3:52:21 AM (reads: 2004, responses: 1)
In practice, most "untyped" or unityped languages do in fact have dynamic typing (e.g. scheme). One of the very few truly untyped languages I know is Forth. Similarly, B (the predecessor of C) was apparently truly untyped, whereas C is only untyped when the programmer wants it to be ;-)

I agree with everything Cardelli says, and I also agree with you about python. I really like python, use it all the time, and consider it an excellent language for teaching programming, but for large projects the lack of any static type system is a pain. I feel the same way about scheme, although I like scheme more because of the higher-order features. My observation is that for programs of over 1000 lines, I really want static type checking.

Dylan and maybe common lisp are the only languages I know of that seriously try to straddle this divide between dynamically-typed-and-good-for-small-programs languages and statically-typed-and-good-for-large-programs languages. I've never really used either for serious work (the development environment for dylan on unix, at least, is pretty weak). I think this is an interesting approach and I hope more languages adopt it. It would be even better if it was possible to put in pragmas that say something like "this module has to be statically typed all the way down" so you could really enforce static typing when you wanted to.

Ehud Lamm - Re: Bricklin: Why Johnny can't program  blueArrow
9/20/2002; 4:03:25 AM (reads: 2087, responses: 0)
I wrote about this approach. However, I don't really find explicit unit declarations (connecting an interface and an unrelated implementation module) pretty:

What we are suggesting, in essence, is to allow implicit connection between interfaces and implementations, while using the type system to ensure consistency....We think that having interface relations explicit, while allowing the implements relation to be inferred (via logical rules) strikes a good blanace.

I started thinking about these issues after I realized that contary to waht you'd expect, there's more reuse going on in dynamically typed languages with weak abstraction facilities, than in languages that are designed to ease code reuse.

Now obviously there are many reasons for this, some of them sociological, but an important point is that these language make it easier to break abstraction boundaries, which is often something you have to do if you want to resue a previously designed abstraction.

jon fernquest - Re: Bricklin: Why Johnny can't program  blueArrow
9/21/2002; 4:02:33 AM (reads: 1969, responses: 0)

Constrast what Cardelli has to say with what Paul Graham has to say on scalability:

A throwaway program is a program you write quickly for some limited task: a program to automate some system administration task, or generate test data for a simulation, or convert data from one format to another. The surprising thing about throwaway programs is that, like the "temporary" buildings built at so many American universities during World War II, they often don't get thrown away. Many evolve into real programs, with real features and real users. ...

Another way to get a big program is to start with a throwaway program and keep improving it. This approach is less daunting, and the design of the program benefits from evolution. I think, if one looked, that this would turn out to be the way most big programs were developed. And those that did evolve this way are probably still written in whatever language they were first written in, because it's rare for a program to be ported, except for political reasons. And so, paradoxically, if you want to make a language that is used for big systems, you have to make it good for writing throwaway programs, because that's where big systems come from. [Being Popular, Paul Graham]

This seems compatible with your point:

"...there's more reuse going on in dynamically typed languages with weak abstraction facilities, than in languages that are designed to ease code reuse...these language make it easier to break abstraction boundaries, which is often something you have to do if you want to resue a previously designed abstraction."

The wrappers in Knit look like a good way to impose extensive and early (compile time) type checks on this throw away code, but this seems to be what you are saying in the quote from your paper. IMHO code decay (code's throw-away-ability) in large systems could be prevented by this kind of type checking. Units probably make testing (not just unit testing) smoother also.

Paul Graham on Brevity

Brevity is one place where strongly typed languages lose. All other things being equal, no one wants to begin a program with a bunch of declarations. Anything that can be implicit, should be.

Type declarations make any unit of abstraction less concise and so they are annoying to both hackers and end-user programmers (the article expressed this annoyance).

Paul Graham on Libraries:

Programming language design will not be about whether to make your language strongly or weakly typed, or object oriented, or functional, or whatever, but about how to design great libraries. The kind of language designers who like to think about how to design type systems may shudder at this. It's almost like writing applications! Too bad. Languages are for programmers, and libraries are what programmers need. ...Libraries need to be designed using a small set of orthogonal operators, just like the core language.

OK. Nowadays, The most useful, extensive, and innovative libraries are written in dynamic languages nowadays: Perl, Python, Lisp.

But logic, math, and rigor influence the design of programming languages via type theory (see Simon Thompson's book).

I think it is a tragic waste of human resources that almost all code that has been written is ultimately disposable or "throw away". Math is permanent. If a set of library functions are also a set of proofs for that domain then you're finished and you have something permanent. Math will probably also give the "smallest" most "orthogonal" set of operators also.

Michael Vanier - Re: Bricklin: Why Johnny can't program  blueArrow
9/21/2002; 9:36:01 PM (reads: 1961, responses: 1)
Paul Graham is right that it's very, very common for a program to start off as a throwaway program and then grow, and grow, and grow until it's not throwaway any more. This is why optional static typing (like in common lisp or dylan) can be a big win. The Gwydion Dylan project (now at had as its explicit intent the notion of evolutionary programming i.e. allowing programs to start small (and presumably untyped) and then grow to larger (and presumably typed) versions. Another quite different approach, of course, is languages with type inferencing, where you get all the benefits of strong static typing with a minimum of (physical) typing (horrible pun -- sorry). The problem with type inference is that even trivial overloadings (using + for adding integers and floats) become much more complicated. I think Haskell has a nice intermediate approach: systematic overloadings using type classes, and restricting type inference to the inside of functions; the signature of a function is always explicitly typed. Personally, I hate declaring types inside a function but I like declaring them in a function's signature.

jon fernquest - Re: Bricklin: Why Johnny can't program  blueArrow
9/22/2002; 3:48:03 AM (reads: 1934, responses: 0)
> I think Haskell has a nice intermediate approach: > systematic overloadings using type classes, and
> restricting type inference to the inside of functions;
> the signature of a function is always explicitly typed.
> Personally, I hate declaring types inside a function
> but I like declaring them in a function's signature

IMHO the way haskell *keeps things out of the inside of the function* with pattern matching and type declarations makes Haskell functions seem a lot more *lightweight and readable* compared to Scheme and Lisp where there's always some large conditional unravelling the function's arguments and making the next control flow decision.

Thanks for the references to "evolutionary programming" .

pixel - Re: Bricklin: Why Johnny can't program  blueArrow
9/22/2002; 9:22:50 AM (reads: 2027, responses: 0)
Haskell has a nice intermediate approach: systematic overloadings using type classes, and restricting type inference to the inside of functions; the signature of a function is always explicitly typed

uh? Haskell has a complete type inference (well nearly complete, eg: [] == []), and doesn't force you to explictly type functions!

Michael Vanier - Re: Bricklin: Why Johnny can't program  blueArrow
9/22/2002; 6:03:31 PM (reads: 1942, responses: 0)
Actually, I wasn't sure about whether full type inference was possible in Haskell (I'll take your word for it), but I know that the accepted style in Haskell is to write the type declaration for a function above the function e.g.

    factorial :: Int -> Int
    factorial 0 = 1
    factorial n = n * (factorial (n - 1))

BTW the dylan term is not "evolutionary programming", as I mistakenly said above, but "evolutionary development". Here's a link to some information about the original project goals.

jon fernquest - Re: Bricklin: Why Johnny can't program  blueArrow
9/22/2002; 11:50:38 PM (reads: 1939, responses: 0)
Another perspective on languages and libraries by Henry Baker. Everytime someone creates a cool library they seem to create another look alike language:

"Most 'popular' languages started life as highly specialized (i.e., 'limited scope') languages that had access to some peculiar library -- e.g., graphics, type-setting, wimp, linear algebra (matlab), symbolic algebra (macsyma, etc.). People then found out that any language with sufficient power (i.e., not brain dead) was Turing complete, and the converts to these new languages then discovered that they would do _more_ than 'just' graphics, type-setting, etc., etc. Of course, many of these converts had been exposed to only one language, and this language was so much better than that silly Fortran, Pascal, (insert your favorite dog to kick here) language that had been forced upon them in engineering/math/physics/.... school, that they touted it as the next best thing to sliced bread.

The truth is that there isn't more than an ounce of spit in the differences among most of these languages _with the exception of the specialized libraries that they are hooked up to_, so most of this variation is non-productive.

There are major exceptions to this assessment, to be sure. The appearance of soft/dynamic typing, garbage collection, EVAL, sophisticated data structures, dynamically compiled/linked code, etc., etc., quickly separate the sheep from the goats.

So the language theorists focus on the _library-independent_ issues such as typing, data structuring, control structuring, etc., instead of on building large numbers of specialized libraries. The ability of a language to continue growing out of its original niche depends critically on this more balanced view, but this view is seldom to be found in the initial enthusiasm of creating the first Turing-capable interpreter for one's new graphics/type-setting/... library.

The few languages that do manage to leave the premordial slime and move onto dry land (Lisp, Prolog, Smalltalk, ML, etc.) are laughed at by those still in the slime for sloughing off their specialized libraries, even though by doing so, they can now do all of the specialized things from not only their original area of expertise, but also many other areas, as well."


From: Henry Baker ( Subject: Re: Ousterhout and Tcl lost the plot with latest paper Newsgroups: comp.lang.scheme, comp.lang.scheme.scsh, comp.lang.lisp, comp.lang.tcl, comp.lang.functional, comp.lang.c++, comp.lang.perl.misc, comp.lang.python Date: 1997/04/22 Complete Thread (165 articles)

Michael Vanier - Re: Bricklin: Why Johnny can't program  blueArrow
9/23/2002; 12:05:25 AM (reads: 1926, responses: 0)
What a great passage! You've got to admire hostility that deep. It has backbone ;-) It's even better because it's all so true. I love the expression "languages that manage to leave the primordial slime"...