Kent M. Pitman's Second Wind
12) Good texts for learning Scheme?
by drenehtsral
I have recently been working on learning Scheme in my spare time, with the eventual goal of writing a scheme based scripting system to run the guts of a massive adventure game/graphical mud sort of system, everything from environment simulation (predator/prey cycles, etc...) to 3d models (i.e. models will be geometry glued together by scripts so you could have trees that by a random seed and a growth level variable have grown over time and are unique to provide interresting landscape features). Scheme is appealing because it's simple, powerful, and adapts well to the idea of a threaded interpreter.
To further my goal of learning Scheme inside and out, I've been reading "The Little Schemer," as well as "Structure and Interpretation of Computer Programs." Do you have any other recommendations for good Scheme programming texts?
Kent M. Pitman: You can get a list of textbooks from Schemers website. If you can articulate a particular need or preference that you think should help narrow down the many available choices, I'd suggest posting a more specific inquiry to the comp.lang.scheme newsgroup.
13) Overlooked practical aspects of Lisp
by hding
Why do you think that people so often overlook many of the wonderful things in Common Lisp such as unwind-protect, the whole condition system (which you are of course closely associated with), and so on - things that make it very useful for day-to-day programming, and are there any such things that you'd particularly highlight, or conversely that you wish had become part of the standard but did not.
Incidentally, thank you for all of the insight so generously and regularly poured forth in comp.lang.lisp.
KMP: Well, people program with tools that are familiar to them. Unless Common Lisp is someone's first language, it'd be easy for them to overlook the things it contains that are not like the things they're familiar with. There's a certain irony here because often the reason people will leave a language for another language is that they've reached the limits of what they can do with the first language and they need more power. So you'd expect that they'd aggressively look for features of the new language that were different than the things they've used before. And probably some do. But you're right that others cling to the safety and familiarity of the operators they could just as well have found in the old language they left behind, and so in the process they miss out on what the language can offer them.
Fortunately, unwind-protect is finally (pardon the pun) present in Java. And some hints of the Common Lisp condition system made it into Java as well. So probably people who come to Common Lisp from Java will be inclined to seek out those capabilities. But there's a lot of other stuff there and I hope new users will indulge their curiosity and take the time to explore.
As to what we should have in the language, the main omission of note is some sort of system definition tool (the in-Lisp analog of make). It was a shame that we did a feature-freeze on ANSI Common Lisp in 1988 but didn't get the standard out until 1994, and the suggestion of including such a tool didn't come until the after-freeze period. All vendors offer such a facility, but programs would be more portable if there were a uniform solution.
There are also quite a number of things about Common Lisp that are available in the same or similar forms in nearly all implementations. Multi-tasking, sockets, database access, external function call, windowing, and so on. It wouldn't be bad to have included any of these, but the fact is that they weren't ready for standarization in 1988. At this point, though, I think other mechanisms than standards are the right way to proceed.
The Lisp community used to expect the delivery mechanism for new functionality to be a new language spec. But that requires working through consensus standards bodies. The problem is that, by their nature, standards bodies are synchronization mechanisms. The problem with synchronization mechanisms in a massively parallel world is that they slow things down. The world is not going to wait for us to slow down, so I think we need to evolve mechanisms that will keep up better with a degree of pace that is externally dictated.
I think this is an area where Lisp as a community has been slow to respond. There need to be community mechanisms for sharing the many great commercial and private packages people have been creating in Lisp, so that we can properly reap the cross-product benefits of our community's productivity. I see evidence that this is changing. The Common Lisp Open Code Collection (CLOCC) is one such mechanism that addresses open source code. I'd like to see similar mechanisms arise for the exchange of proprietary products as well.
As to my posts on the comp.lang.lisp newsgroup, thank you. I'm glad you enjoy them. Frankly, I always consider it a victory to hear I haven't bored everyone to death. In background I've been working on putting together several books on Lisp, but one never quite knows if one will finish such things. I regard comp.lang.lisp as a kind of insurance policy, assuring that at least some piece of what I have seen and done in my career gets transferred from individual memory to global group memory.
I think preserving individual experiences for history is quite important. In the future, this will happen naturally due to logs kept by online collaboration tools. But I'm especially worried about the records of what happened between about 1960 (the birth of programming languages) and 1994 (the birth of the web). Most of everything in that time range is recorded on paper and will eventually be lost. Looking back from the future, I expect it to be as confusing to figure out how the information society was born as it is to look back in a telescope to see the birth of the Universe. You'll get very close, but then you'll get to a point where you can see nothing. The informational big bang. I've been working on webbing all of my old hardcopy papers, and I hope others of that era will commit to doing the same.
14) Lisp - Scheme - ML
by Tom7
I know a lot of big academic (erstwhile) lisp shops, such as CMU, have transitioned away from lisp to ML [standardml.org] and relatives [inria.fr]. Some of the reasons we might give are:
- Sophisticated type systems, catching most bugs before your program is run, ensuring safety, etc.
- Much more efficient (http://www.bagley.org/~doug/shootout/craps.shtml), partly due to compilation strategies using types
- Increased modularity and abstraction
- Pattern matching, (subjectively) more natural syntax
In fact, I'm one of those people. I've been scoffed at by lisp fans, but most had never used ML. But I have an open mind, so, in the face of more "modern" languages, what advantages do lisp and scheme offer? Do you think that these advantages are fundamentally impossible to achieve in a typed setting?
KMP: First, I assume by "typed" you mean "statically typed." I think of Lisp as "dynamically typed." I think of most machine languages as "untyped." I've heard statically typed languages sometimes called strongly typed, and I sometimes use this terminology myself out of habit, but I've grown to dislike it because it seems to me that the issue of strength ought to refer to whether you check types, not when you do. The terms "static" and "dynamic" seem to me to better get to the heart of the matter.
To quote Abraham Lincoln, admittedly somewhat out of context, "People who like this sort of thing will find this the sort of thing they like." So to somewhat flippantly re-interpret Lincoln's remarks in a modern context, applying perhaps just a bit of obligatory political spin to the result: The fact that functional languages appeal to people who like functional languages is not a proof that functional languages are of general purpose appeal.
I think the real reason that CMU (or any university with a grant-based funding model) changed its direction is good sources of funding in research depend on saying you're doing something "new and different." Such a shift doesn't imply that the thing left behind wasn't "tried and true," but only that "tried and true" is not what gets research dollars. Research must constantly stir the mix, but that doesn't imply obsolescence to what came before. So don't read too much into that.
Answering each of your points in detail might require a whole article, but I'll touch on each in brief:
- Sophisticated type systems, catching most bugs before your
program is run, ensuring safety, etc. Much more efficient partly due to
compilation strategies using types.
Actually, it's funny that you both mention the CMU project and then make this comment. Before moving away from Common Lisp, the CMU crowd was successful in demonstrating to the Lisp community's satisfaction that there were enormous opportunities offered by the Common Lisp language design in terms of type inferencing that still today go untapped by implementations. This is really a market issue, not a language design issue. The fact is that although other languages do a lot more type inferencing, vendors are not getting huge numbers of bug reports saying that better type inferencing is what stands between programmers and the commercial success of their product. Over time, I think you'll see more and more interesting type analysis done, but such work is always balanced against other needs of users, such as CORBA, COM, RMI, and web interfaces, for example, such as UI toolkits and debugging options. When I observe, as I often do, that languages are political parties, this is what I mean. They are each responsive not to the needs of the world, but to the needs of their constituencies. And the Lisp constituency, while it is not oblivious to the value of type inferencing, does not see that issue as its number one priority.
- Increased modularity and abstraction.
This is quite a multidimensional space. I think Lisp provides great opportunities for modularity and abstraction that other languages do not. And yet, there are sometimes things I can't abstract as well as I wish. An example of a minor omission: Common Lisp's CLOS doesn't do protocol abstraction as well as Zetalisp's New Flavors; among other things, one can't declare that certain unimplemented methods are required. But with the use of the macro system and the Meta-Object Protocol (MOP), one can add this kind of thing. Further, the package system is missing certain kinds of inheritance capabilities I've often wished for, but I recently sat down and did the work of writing my own versions of defpackage for my own use, adding the capabilities I wanted in a way that my own tools can use, and I had no difficulty. For the most part, I've found the limitations of Common Lisp's abstraction capabilites to be incidental, and not deep, and I've found its syntactic reorganization capabilities more than capable of making up for it.
-
Pattern matching.
I think you're right that Lisp doesn't do pattern matching. Whether or not that's a good or bad thing is subjective. I think there are people who like pattern matching and people who don't. In fairness to Lisp, though, on the few occasions in my career where I've felt a strong need for pattern matching, I've been able to implement it easily. And, importantly, Lisp's syntactic adaptability has allowed me to make my personal implementation look as natural in the programs I write as if it were natively provided by the language; most other languages don't give me the syntactic control to be able to add new functionality in a way that feels appropriate to the language. So personally, I don't find this a strong negative; rather, I see it as an opportunity for you to create a layered library that supports the needs of yourself and others like you.
-
(Subjectively) more natural syntax.
I don't think you can make the case that much of any language has "natural" syntax. COBOL and HyperTalk gave this the fairest shot and there's a big difference even between them and any natural language. I personally find Lisp syntax remarkably natural in that it focuses on symbols that you could say out loud, marking them minimally to indicate grouping. Other languages contain lots of special-purpose markers like commas, semicolons, asterisks, and braces/brackets/parens that are used in quite nitpicky ways. All this to say that you're right on this one: it's subjective. And as such, I hope I can fairly dismiss this as an even draw.
15) Lisp in Mathematics Programming
by An Anonymous Coward
Gregory Chaitin has a book called "The Limits of Mathematics." In it he claims that mathematicians should love Lisp because Lisp is basically set theory, and all mathematicians love set theory. I wholeheartedly agree with this, one only needs to look at Chaitin's Lisp programs to realize how quickly and succinctly one can arrive at astonishing incompleteness results in mathematics. So we know Lisp is great for stuff like this, really researching a mathematical subject. Do you see Lisp continuing in this direction, showing and discovering theorems, or will it move into industry? Or has it moved into industry, and we just don't know it? Do the likes of NASA and JPL use Lisp and Scheme religiously? I would bet so.
KMP: Lisp may have started out as a way of addressing abstract topics like math (logic, calculus, prime numbers, etc.) and artificial intelligence, but it long ago made the transition to commercial applications. Both Scheme and Common Lisp have been and continue to be used in real-world applications that might surprise you. These include (but are certainly not limited to) applications in airline scheduling, commercial database manipulation, computer operating systems, bioengineering, web services, document format translation, and, yes, even space exploration. Franz, Inc. has created quite a nice page of Lisp success stories that I think expand on this much better than I could in the space I've allowed myself to answer this question. And speaking of NASA/JPL, they did a comparative study of Lisp vs Java and C++ that some might find interesting.
16) Scheme in CS
by An Anonymous Coward
It seems many of the more popular CS programs in the world use Scheme as a teaching language. A lot of times, students complain about this, saying they'd prefer to learn about C or another language that is considered "apt for industry." I used to be like this too, but have now discovered the error of my thinking. How have you convinced others that while the latest programs might not be written in Scheme, that it is worth a student's time to learn Scheme. Many seem stuck to the point that if they won't use it outside of school, they shouldn't learn it. How can we convince them otherwise, to become scholarly citizens instead of drones?
KMP: I think the thing to explain to a student is that the world is ever changing and that one cannot put ones eggs all in one basket. Furthermore, modern environments are often quite heterogeneous, with different languages and systems being used together cooperatively. Especially for a CS student, who often has the luxury of time that a person in the job world does not, I think it's worth taking time to learn as many different languages as possible. This not only exposes the students to alternate ways of thinking, but it also prepares the student to quickly change modes of thought or languages of expression later. Once on the job, one often can't afford the ramp-up time to learn a new language at the point it becomes necessary to use. Better to already know it and just have to "brush up".
One is much more likely to consider alternative approaches if one has a sense of what is involved in them; it's very easy to fear the unknown, even when the unknown might be of great help. So get to know as many things as you can while you can. Common Lisp and Scheme, which I regard as two very different languages, by the way, should definitely be among the things every student studies. But they should not be the only things the person studies. Like it or not, there is a lot the professional programmer needs to know to be really successful not just tomorrow, but for a lifetime.
As Oliver Wendell Holmes is often quoted as saying, "A mind stretched to a new idea never returns to its original dimensions." In order to stretch a student's mind, I recommend they make a list of "kinds of languages" and then learn as many different kinds as they can. Here are some that come to mind, though I'm sure others with different experience than me might reasonably contribute still others.
- A block-structured language, such as Algol or Pascal or Scheme.
- A line-oriented language, such as Fortran or BASIC.
- A rule-based logic language, such as Prolog or EMYCIN.
- An Englishy language such as HyperTalk or Cobol.
- A "stack" language such as PostScript.
- A "line noise" language (heavy emphasis on one-letter operators) like APL or Teco.
- A dynamic object-oriented language, such as Common Lisp or Smalltalk .
- A strongly-typed, statically analyzed language such as ML or Haskell.
- A dynamically-typed functional programming language, such as Scheme.
- A string or macro processing language, such as Perl or m4 or TeX or Teco.
- A database access language, such as SQL.
- An abstract high-level, assembly language, such as Java.
- A concrete high-level, assembly language, such as C.
- A low-level, traditional assembly language.
- A scripting language, such as Javascript.
- An interface-definition language such as Visual Basic, HyperTalk, or Javascript.
- A document-structuring language such as XSL or TeX.
- A language with a modern error system, such as Common Lisp or Dylan.
- A reflective/introspective language such as Common Lisp or Java.
- A symbolic programming language, such as Common Lisp or Scheme.
- A security-oriented language, such as Java or MOO.
- A language where both programs and data are fully persistent, such as MOO or HyperTalk.
17) A question for Kent
by MarkusQ
Do you have a maclisp manual I could borrow?
KMP:For those not familiar with Maclisp, it's a defunct dialect of Lisp that predated and strongly influenced the design of Common Lisp.
I've been working on webbing The Revised Maclisp Manual, which I had published on paper back in the early 1980's. It's not quite ready to go out yet, but should finally be ready sometime in the not terribly distant future. Probably a month or two. Watch the site maclisp.info for more information.
18) Open Implementationsby Martin Pomije
What is your opinion of the idea of Open Implementations from Gregor Kiczales? Do you think that his idea could help Lisp be more widely used?
You can see him giving a lecture about this idea here. [microsoft.com] The video is only available in Windows Media format on this site.
KMP: I hadn't seen Gregor Kiczales's talk on Open Implementations, so I enjoyed watching it. Thanks for the pointer!
The talk made me think back to various related ideas I've seen batted around for a long time, the earliest of which that I can recall is a short paper on something called "Capsules" (an object system where classes were allowed to have multiple implementations) by Richard Zippel back in the late 1970s or early 1980s at MIT. Often, especially in a university environment, people will make up such a concept, bat it around for a bit, and then go on to something else. There are some very interesting ideas there and I'm glad to see that they're being pursued seriously, especially by someone as thoughtful and talented as I know Gregor to be.
As a formalized area of study, this topic of "aspect-oriented programming" is new to me. It reuses some old ideas in new ways, and introduces some new ones along with it. I'm only just barely becoming conversant in the terminology, so I can't really speak to it from a theoretical point of view. But it looks promising. And from a practical point of view, I can note that I'm getting daily on-the-job training in it through my consulting relationship with The Software Smith. They're using Lisp as a vehicle to apply the principles of aspect-oriented programming, and the results they get are quite spectacular.
19) What was up with CLisp's "loop" form?
by Jayson
Did you can have anything to do or know who had anything to do with the "loop" form in Common Lisp? Why does it look and feel just like a FOR loop on C (from the Graham book):
(loop for x = 8 then (/x 2)
until (< x 1)
do (princ x))
This is one of by biggest minor nags about CLisp and I am very curious what was going through the committee's collective head. Didn't anybody balk at this enough to at least get the syntax cleaned up?
KMP: The example you cite is quite simplistic and if this were the only reason for using LOOP, we wouldn't have it. Lisp has a number of other iteration operators for doing simple loops like this. However, the reason for using LOOP is that it can represent much more complicated arrangements of iteration paths and collection techniques. I used to grumble a lot myself about how "un-Lispy" LOOP seemed, but over time I come to the belief that the benefits outweigh the costs. A loop like this:
(loop for x from 0
for y in some-list
when
(good-result? y)
collect (list x y))
is easy to write and maintain, and much easier to explain than the equivalent, but more Lispy:
(do ((x 0 (+ x 1))(y-list some-list (cdr y-list))
(result '()))
((null y)
(nreverse result))
(let ((y (first y-list)))
(when (good-result? y)
(push (list x y) result))))
The Common Lisp community likes to offer the traditional Lispy notations for places where they enhance readability, but we also offer alternative notations for situations where we've learned there's a call for it. We leave the choice of which style to use up to the individual taste of the programmer. Common Lisp is not a minimalist language offering only one way to do things or rigidly attempting to force people into a single programming paradigm.
By the way, this is a fundamental difference between the ANSI Common Lisp design philosophy and the Scheme design philosophy. The introduction to the Scheme specification states:
Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary. Scheme demonstrates that a very small number of rules for forming expressions, with no restrictions on how they are composed, suffice to form a practical and efficient programming language that is flexible enough to support most of the major programming paradigms in use today.By contrast, the charter for X3J13, the group that designed ANSI Common Lisp, stated the following in the X3J13 charter:
It will codify existing practice, provide additional features to facilitate portability of code among diverse implementations, and establish normative Common Lisp programming practice. The committee will begin with the language described in Common Lisp: The Language by Guy L. Steele Jr. (Digital Press, 1984), which is the current de facto standard for Common Lisp. Whenever there is a proposal for the standard to differ from Common Lisp: The Language, the committee shall weigh both future costs of adopting (or not adopting) a change and costs of conversion of existing code. Aesthetic criteria shall be a subordinate consideration.
In other words, the Scheme community is a very conservative community that is highly focused on keeping its language specification as highly aesthetic and minimal in size as possible. By contrast, the Common Lisp community is an industrial standard that is concerned with messier issues of compatibility, portability, and commercial need; while the Common Lisp community cares about aesthetics, it does not allow aesthetics to dominate practicality as a design criterion.
The relevance of this here is that the Lisp family of languages is made up of a number of smaller communities who share a few core ideas, but really have some very divergent points of view. Each is worthy of study in its own right. One should not, having looked at Scheme, assume they have good intuitions about Common Lisp, nor vice versa.
One-offs and small utilities are all fine and dandy, but are there really people implementing large systems using Lisp?
(result '()))
((null y)
(nreverse result))
(let ((y (first y-list)))
(when (good-result? y)
(push (list x y) result))))
Who the hell can read this shit? Give me C/C++ any day.
The quality of the information you've given in your answers here and in your other responses is really fantastic. This is infinitely more effective than most language "advocacy" and it has been really interesting.
Now before I get modded down, I be to remind whoever might read this that what I am saying is FACT. - bogaboga
Nobody claimed that this language was superior to another language. What about the flamewar? What about 4000+ comments? For the love of god, this is slashdot!! GIVE ME BACK MY FLAMES YOU BASTARD! :)
Trapped in Time... Surrounded by Evil... Low on Gas.
This guy is kept away by lisp. Imagine if he was ;P
a bored AC like the rest of us? "slashdot overload" would have an entirely different meaning
Are all lispers this articulate? Is it a requirement to being a good lisper?
Yeah, sure, Grandma is going to understand Ctrl-M Alt-X Ctrl-N Alt-O Alt-N Alt-F to save the file. Elitists ??? vi is about four thousand times simpler than Emacs.
is it frees up a *ton* of time for doing other things.....
/. interviews.
Like writing thesi^H^H^H^H^Hreplies to
You use a programming language for one primary reason: you believe most other people in your domain space are using it. This is why C will be around for at least another fifty years, Java will unfortunately be around for at least twenty, and perl will probably last another fifteen.
No one cares how useful a programming language is - they care how many competent programmers they can hire who can code with it. This is why Lisp, ML, Haskell, Prolog and the rest have been consigned to the dustbin.
Pitman's answered 19 questions so far, and I can't help but wonder if this second 'leg' is the final. Does anybody know how many more is he going to answer?
This is the best interview I remember reading here, and I definitely want more of the same (and thanks to whoever decided to post in in sections - it's been easier to digest it this way).
"Trust me - I know what I'm doing."
- Sledge Hammer
I must have...the book is sitting there on the shelf right next to my Prolog manual and my Abstract Non-Linear Algebra book.
Wait a minute.
Painful memories returning
Feelings of hopelessness returning
Confusion taking over
O god. What have I done
"The market alone cannot provide sufficient constraints on corporation's penchant to cause harm." -- Joel Bakan
Thanks again for your two part series. As someone who took to scheme immediately as soon as I saw it, and moved into Common Lisp with enthusiasm when I found it, I am familiar with these types of questions.
:-)) but when I approach a problem I always think to myself "what is the best way to look at this problem to make it simpler to solve". Often LISP lets me express that solution better than other systems.
I especially think your description of a list of language types to learn is valuable to those who haven't had the experience of learning multiple languages.
I want to address a few questions I've heard frequently myself.
1) Why learn XYZ it won't help me get a job or won't be used on the job.
The fact of the matter is that the more you know about how computations CAN be described, the more you will know about what the right way to describe a *particular* computation is. This means when someone comes to you with 150 pages of code in straight C that implements a simple data format parser, or a preferences file reader, or a layout engine for a diagram editor or whatever, if you have seen 5 or 6 different styles of languages and techniques for programming, you will be able to decide how best to attack the problem that needs solving.
Often with the right point of view, a problem becomes an order of magnitude simpler. The beautiful thing about LISP is that it gives you the ability to take so many different points of view within a single language.
I still use flex/YACC, and M4, and sed, shell scripts, and will occasionally write some C/C++ (usually to link into lisp at a hotspot
This approach is basically the same approach a mathematician takes to proofs and problem solutions. Make the problem smaller, make it more like something we know how to solve...
Here's the other one I hear often:
2) We can't use XYZ there aren't enough people who know XYZ to support it. Go back to (or stick with) C/C++/Java/Perl!
This simply is a way to dodge having to rationally consider a different language or system. The fact of the matter is:
a) Just because you can hire someone who claims to know C/C++ or whatever, doesn't mean you can hire someone who can solve your problem! Programming involves a lot more than just knowing the syntax of a given langauge, and some of the features the library offers.
b) If by switching to something else you can make your problem several times easier, then the cost of training every good candidate vs. sticking to your old ways is essentially negative!
Most of the time, spending a few weeks of training your new candidate in how your system works will pay off big-time when it comes to debugging, quality assurance, adding new features, and even implementing the feature you initially hired them for. Why? Because understanding the PROBLEM and the solution method is much harder than understanding the language syntax, or even most language semantics.
I run my own business, it's just me. My ability to understand a problem, work with people to figure out good implementation strategies, and write code in LISP to rapidly create the products and services I want to provide are all advantages that I got by learning many languages, and especially LISP family languages.
thanks again Kent!
((lambda (x) (x x)) (lambda (x) (x x))) http://www.endpointcomputing.com a scientific approach to custom computing.
Sad.
I'm not that impressed with the NASA study linked. Anyone who has done any Lisp programming in school will know that Lisp is a great language for algorithmic problem solving, and the problem used in the study really plays to that strength in Lisp. Perl would also likely kick C++ and Java's ass in this task. That doesn't mean that Perl or Lisp would necessarily be as good a choice as C++ or Java in a wide range of problem domains.
Lisp is a great language, but it traditionally has not interfaced as well with the Real World as a number of other languages that were more practically oriented.
I know that people absolutely rave about the pleasures of programming on all-Lisp machines, but most of us don't have those, and without either having a Java-style complete set of API's for doing GUI and system interfacing, or having C's ability to directly call system API's, one is left without the tools to directly influence the environment. And, yes, I'm sure there are implementations that have those things there, but without them being absolutely standardized, you can wind up locked in a ghetto of your own making.
As a side note, Kent, don't you think it a little churlish to denigrate Java as merely 'an abstract, high level assembly language'? ;-)
- jon
Ganymede, a GPL'ed metadirectory for UNIX
oh... you said, "SECOND" wind... I thought you said "BROKEN"
I really liked the idea of learning a plethora of languages while in school. Some schools do a good job, but others are rather pathetic.
I remember when I was in school, taking a databases class where one of the requirements for the last project of the semester was to program it in a language/system we had never used before. It was actually kind of fun (I chose PHP).
I have seen way too many recent college grads who are proficient in little more than VB. I'm sure they were exposed to C/Java/What-have-you, but man, to say all they needed to do was "brush up" would have been a long stretch.
So to any professors out there, encourage your students to get some breadth when it comes to languages. The experience will prove invaluable.
-- yawn. --
author unknown - I copied this long ago:
You Work in a Fashion Industry
I've spent the last several years trying to explain to colleagues why
they should start using another obscure-but-good language, Eiffel, to no avail.
Here is what I have learned. Note that this is not about the pros and cons of
particular languages or paradigms, its about the way the programming language
industry actually works.
The language industry is dominated by network effects. There are major
costs with using a minority language, and for an individual project these
completely outweigh the benefits, even when the benefits are very large. Hence
it is generally far better to stay with a majority language. The costs of a
minority language include:
Support. Sure, you can get a GPL compiler for most languages, but on a project
you don't want to have your coders digging into the code trying to
fix a bug, you want them writing code. Support is something you outsource.
Performance. Every minority language claims to be faster than C, but often
isn't in practice. Whatever the truth, C and C++ are at least known
quantities. Maybe the minority language will be faster, maybe slower. If its
faster, well gee so what. If its slower then you have a major problem.
Tool support. These days even small projects start by drawing UML diagrams and
then converting these automatically into class templates. CASE
tool vendors don't support minority languages. Ditto for testing and
documentation tools. Little things like tying your compiler to your
configuration control manager might potentially be major headaches. Again, its
more risk that the PM can do without.
Nobody ever got fired for buying C/C++/Java. If you are a PM this is a major
issue. Every language is going to bring some headaches, but if you have chosen
a minority language then these headaches can be turned into an excuse for
project failure, and hence for hanging you out to dry.
Trained staff in a minority language are going to be rare. This does not
necessarily make them more expensive (nobody else wants them), but it
does make recruitment much harder and more uncertain. Alternatively you have to
train all your existing people in the new language. And for Functional
Languages its not just another syntax, its a whole new way of thinking. The
industry went through this with OO languages, and many PMs have vivid memories
of reams of non-OO obfuscated C++ written by a bunch of C hackers who had been
sent on a one week C++ course. Getting your head around a new paradigm can take
months, and this is time that the project just does not have.
So, overall the PMs want to go with popular languages, not for PHM
reasons, but for entirely rational local reasons. But rational local decisions
turn into globally arbitrary decisions, as the entire herd gallops off in a
random direction chosen only because most of the herd thought that most of the
herd were headed that way.
The lesson of this is that if you want to introduce a language, you don't
concentrate on making it a good language, you try to persuade the herd of
programmers, PMs and tool vendors that your language is the Next Big Thing. The
important point here is not how much the language will do for productivity,
quality and cost, it is to create the perception that everyone else thinks that
this language will be the next big thing.
There are two ways to do this. One way is to tackle the whole industry at once.
For an object lesson in how to do this, see Java. For an object lesson
in how not to do it, see Eiffel. Believe me, I know all about this. I have
spent a long time giving presentations extolling the technical virtues of
Eiffel, only to have my audience say "Yes, but in the Real World....". In the
Real World what counts is the network effects. And you know what? My audiences
were right. It has taken me a long time to realise this.
The other more interesting and more promising way to introduce a new
language is to identify a niche market and attack that. Once you have taken
over your niche you can expand to nearby niches and start to build momentum.
Python is doing exactly this in web serving, for example. Web serving is a good
niche because lots of people do it, and productivity and quality generally
count for more than raw performance. Projects also tend to be small, so
experiments are not the Career Limiting Moves they are for large projects.
Education can also be a useful niche if you can afford to take the long view,
which is how Pascal, Basic and Unix got started.
You Work in a Fashion Industry
I've spent the last several years trying to explain to colleagues why
they should start using another obscure-but-good language, Eiffel, to no avail.
Here is what I have learned. Note that this is not about the pros and cons of
particular languages or paradigms, its about the way the programming language
industry actually works.
The language industry is dominated by network effects. There are major
costs with using a minority language, and for an individual project these
completely outweigh the benefits, even when the benefits are very large. Hence
it is generally far better to stay with a majority language. The costs of a
minority language include:
Support. Sure, you can get a GPL compiler for most languages, but on a project
you don't want to have your coders digging into the code trying to
fix a bug, you want them writing code. Support is something you outsource.
Performance. Every minority language claims to be faster than C, but often
isn't in practice. Whatever the truth, C and C++ are at least known
quantities. Maybe the minority language will be faster, maybe slower. If its
faster, well gee so what. If its slower then you have a major problem.
Tool support. These days even small projects start by drawing UML diagrams and
then converting these automatically into class templates. CASE
tool vendors don't support minority languages. Ditto for testing and
documentation tools. Little things like tying your compiler to your
configuration control manager might potentially be major headaches. Again, its
more risk that the PM can do without.
Nobody ever got fired for buying C/C++/Java. If you are a PM this is a major
issue. Every language is going to bring some headaches, but if you have chosen
a minority language then these headaches can be turned into an excuse for
project failure, and hence for hanging you out to dry.
Trained staff in a minority language are going to be rare. This does not
necessarily make them more expensive (nobody else wants them), but it
does make recruitment much harder and more uncertain. Alternatively you have to
train all your existing people in the new language. And for Functional
Languages its not just another syntax, its a whole new way of thinking. The
industry went through this with OO languages, and many PMs have vivid memories
of reams of non-OO obfuscated C++ written by a bunch of C hackers who had been
sent on a one week C++ course. Getting your head around a new paradigm can take
months, and this is time that the project just does not have.
So, overall the PMs want to go with popular languages, not for PHM
reasons, but for entirely rational local reasons. But rational local decisions
turn into globally arbitrary decisions, as the entire herd gallops off in a
random direction chosen only because most of the herd thought that most of the
herd were headed that way.
The lesson of this is that if you want to introduce a language, you don't
concentrate on making it a good language, you try to persuade the herd of
programmers, PMs and tool vendors that your language is the Next Big Thing. The
important point here is not how much the language will do for productivity,
quality and cost, it is to create the perception that everyone else thinks that
this language will be the next big thing.
There are two ways to do this. One way is to tackle the whole industry at once.
For an object lesson in how to do this, see Java. For an object lesson
in how not to do it, see Eiffel. Believe me, I know all about this. I have
spent a long time giving presentations extolling the technical virtues of
Eiffel, only to have my audience say "Yes, but in the Real World....". In the
Real World what counts is the network effects. And you know what? My audiences
were right. It has taken me a long time to realise this.
The other more interesting and more promising way to introduce a new
language is to identify a niche market and attack that. Once you have taken
over your niche you can expand to nearby niches and start to build momentum.
Python is doing exactly this in web serving, for example. Web serving is a good
niche because lots of people do it, and productivity and quality generally
count for more than raw performance. Projects also tend to be small, so
experiments are not the Career Limiting Moves they are for large projects.
Education can also be a useful niche if you can afford to take the long view,
which is how Pascal, Basic and Unix got started.
how funny is this? /.
I dislike Lisp for many reasons,BUT this is a worth while nerd interview that belongs on
I like Bruce Cambell, but his interview in no way a nerd matter.
The Kruger Dunning explains most post on
Yes, that post was brilliant and deserves to be repeated.
HAHAHAHA!
Thought you were serious until you said:
Nobody ever got fired for buying C/C++/Java.
VERY FUNNY! Boy I need a laugh today!
Never answer an anonymous letter. - Yogi Berra
try mcedit (midnight commander's editor)
A few (untested) implementations of the same loop, in Scheme this time, just for comparison and as thought-provokers:
;;;; Yuck, this one is verbose.
(let loop ((x 0)
(ys '(1 2 3 4 5 6)))
(if (null? ys)
'()
(let ((y (car ys))
(rest (loop (+ x 1) (cdr ys))))
(if (even? y)
(cons y rest)
rest))))
;;;; This one's less ugly, but still not great.
(let loop ((x 0)
(ys '(1 2 3 4 5 6)))
(cond
((null? ys) '())
((even? (car ys)) (cons (car ys) (loop (+ x 1) (cdr ys))))
(else (loop (+ x 1) (cdr ys)))))
;;;; Using "streams" as per SICP
(define (integers-from x) (stream-cons 0 (integers-from (+ x 1))))
(stream-map list
(stream-filter (lambda (x y) (even? y))
(integers-from 0)
(list-stream '(1 2 3 4 5 6))))
;;;; Using a lazy dialect of lisp:
(define (integers-from x) (cons x (integers-from (+ x 1))))
(map list (filter (lambda (x y) (even? y))
(integers-from 0)
'(1 2 3 4 5 6)))
With Java, C and most other neanderthal programming languages, it's only code, and you have no other choice.
The fact that an expression may be interpreted as data or code is an extremely important ADVANTAGE.
Go back to school and learn about Alan Turing.
-Don
Take a look and feel free: http://www.PieMenu.com
German->English
None has a requirement on the fact that this language of another language was more fastidiously put! What is with that was? And the 4000+ comments? In the name of the gentleman, this is condemned still times Slashdot, or?! YOU RETURN MY FLAMES (or FLAMES) to ME DIRT SOW!
And back again: English->German
Keines hat eine Anforderung an der Tatsache, daß diese Sprache einer anderen Sprache anspruchsvoller gesetzt wurde! Was ist mit dem war? Und der Kommentar 4000+? Im Namen des Herrn wird dieses noch Zeit festsetzt Slashdot oder? verurteilt! SIE BRINGEN MEINE FLAMMEN (oder FLAMMEN) zu MIR SCHMUTZ SOW zurück!
This sentiment is true for industry (except in the rare cases where you can make a real strong economic argument in favor of one language and are lucky enough to have a manager who "gets" it).
But there's no reason this kind of marketplace idea should apply to the "open source" or "free software" world. Personally, I feel free to hack my software in whatever language I like (typically SML, my favorite underdog). I hope that other hobbyists do take the time to build up an environment where their favorite (whatever that may be) can flourish, too. It is in our spirit to embrace things because of their technical merits, rather than their popularity!
And readability has a whole lot to do with maintainability. Programs should not just be written for the computer to understand. Much more importantly, other people should be able to clearly read and unambiguously understand the code.
I've read and written quite a lot of Lisp and other Lisp-like languages, not only in school, but also in the real world. I've spent much time reading, understanding and modifying huge complex Lisp systems written by other people, and I don't think it's unreadable at all. Well written Lisp code is extremely elegant, and a joy to read.
Complaining about parenthesis is trivial, misguided nit picking, and totally misses many much more important points.
Don't like parenthesis? Then let's talk about how all the subtle levels of operator precedence and associativity rules effect the readability and writability of C, C++, Java and Perl code!
Can't remember the difference in precedence between "==" and "<="? Then you have to either look it up (and require the poor bastards reading your code to either remember it or look it up themselves), or use an extra level of parenthesis!
Now whose code has lots of unnecessary parenthesis? Not the Lisp code. Every paren is in there for a reason. But most C, C++, Java and Perl code is eather riddled with unnecessary parenthesis, or totally unreadable, brittle and unmaintainable, because it subtly depends on operator precedence and associativity.
Most competent programmers put in lots of extra parenthesis just to be sure, because code is changed over time by other people. Relying on operator precidence causes many subtle, hard to find bugs, because it's extremely easy to make and miss practically invisible mistakes. And text editors like Emacs can't give you any help with operator precedence and associativity, like they can with parenthesis.
The arguments for operator precedence that claim people expect it are ridiculous. It's an utterly arbitrary and capricious linguistic artifact foolishly copied from mathematics (which most people don't understand), and taken to a ridiculous extreme (with many additional subtle levels of precedence for operators that simply don't exist in standard mathematical notation).
http://www.howstuffworks.com/c14.htm
C contains many operators, and because of the way in which operator precedence works, the interactions between multiple operators can become confusing.
x=5+3*6;
X receives the value 23, not 48, because in C multiplication and division have higher precedence than addition and subtraction.
char *a[10];
Is a a single pointer to an array of 10 characters, or is it an array of 10 pointers to character? Unless you know the precedence conventions in C, there is no way to find out. Similarly, in E.11 we saw that because of precedence statements such as *p.i = 10; do not work. Instead, the form (*p).i = 10; must be used to force correct precedence.
The following table from Kernigan and Richie shows the precedence hierarchy in C. The top line has the highest precedence.
[I am forced to spell out the operators in order to get past slashdot's lameness filter -- and I totally agree that languages with lots of ridiculous noisy punctuation are lame. Save it for cursing in comic strips.]
Operators : Associativity
"open paren" "open bracket" "minus" "dot": Left to right
"exclamation mark", "plus", "minus", "plus-plus", "minus-minus", "star", "ampersand", "(type-cast)", "sizeof": Right to left
(in the above line, "plus", "minus" and "star" are the unary forms)
"star", "slash", "percent": Left to right
"plus", "minus": Left to right
"less-less", "greater-greater": Left to right
"less", "less-equal", "greater", "greater-equal": Left to right
"equal-equal", "exclaimation-equal": Left to right
"ampersand": Left to right
"caret": Left to right
"pipe" : Left to right
"ampersand-ampersand": Left to right
"pipe-pipe": Left to right
"question-colon": Left to right
"equal", "plus-equal", "minus-equal", "slash-equal", "percent-equal", "ampersand-equal", "caret-equal", "pipe-equal", "less-less-equal", "greater-greater-equal": Right to left
"comma": Left to right
Using this table, you can see that char *a[10]; is an array of 10 pointers to character. You can also see why the parentheses are required if (*p).i is to be handled correctly. After some practice, you will memorize most of this table, but every now and again something will not work because you have been caught by a subtle precedence problem.
-Don
Take a look and feel free: http://www.PieMenu.com
It's "statements" having all the parentheses that bother me. I guess I want to have multiple levels that look different. In Lisp, every abstraction level (expressions, "statements", functions, classes, modules) look the same syntactially.
I'd be interested to see a language that had Lisp-syntax expressions but non-Lisp syntax statements. Something like this:
The argument for efficiency via type inferencing is made for many languages, including BASIC. Seldom is it implemented. Smalltalk implementations probably got further in that direction than LISP did.
The object system in Common LISP was an afterthought, and it shows. It's really a macro package kind of thing. LISP has a strong history of overly elaborate macros; ever see the MIT LOOP macro? These have the usual problem; what you're looking at in the source isn't what's running, and debugging macros (especially those written by others) is hell. Most other high-level languages have banished macros, or discourage their use.
If you really want dynamism at run time, Smalltalk has most of what you want, and it's cleaner. But Smalltalk is dying, if not dead. Even the ParcPlace people gave up. Java ate their market.
I've read and written quite a lot of ______ and other ______-like languages, not only in school, but also in the real world. I've spent much time reading, understanding and modifying huge complex ____ systems written by other people, and I don't think it's unreadable at all. Well written _____ code is extremely elegant, and a joy to read.
Readability is a function of the level of understanding of both the person reading and the person writing. If I write in a very verbose style I could make my code completely unreadable. You may not be able to fit all of one particularly ostentiated thought in your head. If I write code in a very terse style same thing, but now you need to do too much expansion. This particular argument about the joys of _____ is moot. If you wish to argue on this level it must be about the expresiveness of a language. Show thoughts that are easy to express in one language but not in another -a problem that appears in both human and computer languages.
--locust
The ScriptX parser allowed you to type in a straightforward javascript-like syntax, with traditional infix notation, precedence rules and other additional syntactic sugar.
The parser transformed text into a parse tree, that was like Lisp s-expressions. ScriptX macros operated in terms of those parse trees, not the surface syntax. So internally it even had "downward passing" continuations (that you couldn't pass outside of the scope they were created), but the parse trees were compiled into a byte code, not unlike the Java virtual machine (which explains why it didn't support fully general continuations).
So you could implement any number of different surface syntaxes for ScriptX, by writing different parsers. My trusty Kaleida colleague DanFuzz wrote a traditional Scheme parser for ScriptX.
ScriptX was a lot like Dylan with a cross platform multimedia class library. It was essentially a Lisp-like language, designed around an object system and class library, more dynamic like CLOS than static like Java. Unlike Java, all data types including integers and arrays are first class objects.
ScriptX had a rich set of polymorphic container classes, much more dynamic than STL, that made heavy use of multiple inheritance.
The container classes (like arrays and maps) were supported by the language sytax, and mixed into many system classes, so you could easily treat windows as arrays, looping over their subwindows, filtering collections of objects through functions and type conversions with "pipes", mix collections into your own classes so they're easy to use through well supported interfaces, etc.
ScriptX had built-in high level time synchronization and graphics classes, including QuickTime movies, sprite graphics like Director, and vector graphics similar to Flash.
One of the great things about ScriptX, which also applies to CLOS and Dylan which inspired it, is its wonderful dynamic objects system. Programming in C++ and STL is totally miserable after having been exposed to ScriptX and CLOS.
For example, I subclassed ScriptX container classes like Array to implement ScriptX Classes for automatically generating HTML, that macros can plug together like legos and dynamically expand into complex web pages.
The ScriptX Tracking Service is a good example of using multiple inheritance with the container and presentation classes.
There's an abstract class called Tracker (that inherits only from RootObject): "This mixin class gives an object the ability to track the mouse, by participating in the tracking service protocol. You can mix Tracker in with presentation and model objects to implement all kinds of direct manipulation interfaces.".
The abstract Tracker class is subclassed by the concrete leaf class TrackerCachedPresenter, and also by another abstract class, TrackerMulti, which implement the recursive tracking protocol. TrackerMulti is then mixed down into concrete with the various container presentation classes TrackerMultiPresenter, TrackerGroupPresenter and TrackerTwoDSpace.
ScriptX was great fun to think and program in. It was an ideal language for developing an open ended platform for plugging together dynamically loaded interactive multimedia objects like Legos.
At the time (1995), Java was no nowhere near capable of doing anything like that on the Mac, Windows and OS/2. With regard to more modern languages, Python is most exciting dynamic and practical programming language around.
The best thing about Python, is that it's completely open source.
It's not tightly controled by a short sighted company that only intends to use it in their religious Jihad against Microsoft, like Java.
And it's not proprietary, jointly developed by strange bedfellows Apple and IBM, and swept under the rug, like Kaleida's ScriptX was.
So Python will be around forever, while quickly and naturally evolving, because it has earnestly learned so many lessons from Lisp and other languages.
Q: What do you get when you cross Apple and IBM?
A: IBM.
-Don
Take a look and feel free: http://www.PieMenu.com
Sounds wonderful. I still have my prized Dylan manual that I ordered from Apple's Cambridge labs back in the day.
Is ScriptX still a going concern in any way?
- jon
Ganymede, a GPL'ed metadirectory for UNIX
We shipped the final version of ScriptX, and Kaleida closed in January of 1996. Apple said they were going to support it at first, then swept it under the rug. Now you can't find anything about ScriptX on Apple's or IBM's web sites.
Python and Zope are clearly the coolest dynamic cross platform open source programming environments happening today.
-Don
Take a look and feel free: http://www.PieMenu.com
Seriously, should you pass on and they need to hire someone else to maintain your LISP, they will certainly pay 2x or 3x the cost of a C programmer, as good LISP programmers are far more rare.
This isn't a joke - I know of companies that have acquired LISP code that has become a complete albatross as they struggle to hire or train people to maintain it - here's a hint - not many programmers want to bother with LISP as they see it as career-limiting.
All in all, I think offering LISP solutions to your customers is a lousy value proposition in the long term.
But in the usability sense explored by the Psychology of Programming field, there are important differences between programming languages, in terms of ease of use, learnability, maintainability, readability, syntactic surface area, cognitive load, etc.
The trivial fact that a language is Turing complete, does not mean that it's well designed or easy to use. It's not all just a function of the programmer's skill. Certainly there are objective qualitative differences between programming languages that make some substantially better than others.
-Don
Take a look and feel free: http://www.PieMenu.com
[reeses@ernie reeses]$ cdecl
Type `help' or `?' for help
cdecl> explain char *a[10];
declare a as array 10 of pointer to char
cdecl>
Learn your tools; they're there to help.
It's not Lisp in general. Lisp integrates just fine with lots of environments. Lisp can integrate very well with UNIX if you let it (Elk Scheme and Bigloo are an excellent examples). And traditional Lisp implementations had everything from the assembler on up built-in and written in Lisp.
I think many of the people who developed CommonLisp and the Lisp machine just had a deep disdain for anything UNIX-related and therefore couldn't care less whether CommonLisp integrated well with UNIX or the kinds of things people were doing on UNIX. Just read the UNIX Hater's Handbook, contributed to by many vocal Lisp users in the the 1980's. As a result, CommonLisp has endless provisions allowing for pathname syntax on TENEX or oddball byte sizes, but few of the things that make systems like Perl, Python, or even Java so useful on UNIX and Windows. Other essential facilities didn't make it into the standard probably because many CL vendors thought they could use essential proprietary functionality as a way of binding users to their product.
I hope future Lisp implementations will learn from these past mistakes. CMU CommonLisp, in my opinion one of the best implementations around right now, might do well to just forget going for ANSI CL compatibility and instead come up with a more useful, more complete, and more streamlined feature set.
Good questions, and answers overflowing with goodwill and scholarship. Excellent work, all round.
In a related late-breaking story, usually reliable sources are stating that a similar confession may be forthcoming from William Gates concerning the MS-DOS and Windows operating environments. And IBM spokesman have begun denying that the Virtual Machine (VM) product is an internal prank gone awry.
{COMPUTERWORLD 1 April} {contributed by Bernard L. Hayes}
The language is clearly not what makes Java interesting--it's a conservative, somewhat tedious language. The libraries are quite good. But the runtime and its specification what makes Java really interesting from a systems point of view because it offers
- a well-specified, complete reflection interface.
- a well-specified, complete interface for dynamic code generation.
- a well-specified set of interfaces to the garbage collector.
- complete specification of what operations must throw what exceptions under what conditions.
- complete specifications of both statically typed and dynamically typed operations (in particular, numbers behave with predictable efficiency).
- implementations that actually reliably perform cross-compilation-unit inlining and other dynamic optimizations.
This makes it straightforward to implement bullet-proof and portable code walkers, debuggers, inspectors, novel efficient object systems, code instrumentation systems, transparent persistence and transparent remote objects, and lots more.I was first exposed to Lisp as an undergrad, in probably the worst possible way. It was as part of the canonical language survey course, taught by someone who didn't really know Lisp, using an atrocious little monograph titled "Lisp for Fortran Programmers". List processing using only PROG, SETQ,and GO *shudder*. No macros, no arrays, no structures. And the implementation we used was essentially a batch interpreter - no emacs, no debugger, just a raw command-line read-eval-print loop.
When I saw Lisp again, in my second year of graduate school, it was taught by someone who used it to get real work done, with an implementation that had most of the features I have come to know and love.
A large fraction of current Lisp users (judging from comments in comp.lang.lisp) are people who started out knowing other languages, became frustrated with their instability or limitations, and went out looking for alternatives. Their choice of Lisp was not made in ignorance.
Lisp is not perfect, but it is an excellent balance of features in progrmming space. Lisp allows you to do imperative code, functional code, and OO code, without forcing you exclusively down one road or another. It is still one of the languages of choice when you want to do something truly new, and it will likely remain so.
To a Lisp hacker, XML is S-expressions in drag.
What's the point of x in these loops? You never use it in constructing the result. If your purpose is to scare people away from Scheme, no need to deliberately obfuscate the algorithm. Keywords like null?, car and cdr look scary enough, at least until people learn their simple meanings.
Does the "nobody got fired for Java" comment indicate that this was written after Java escaped being a minority language? Or does somebody update the essay as language "fashion" changes? With this kind of advice, new languages can never be mainstream, and old languages can never see a resurgence.
Not to worry, though. The "fashion" people will be swept along eventually, whether by new fashion, or by old fashion making a comeback.
See my reply to your posting of this same essay 4 minutes previous.
I have to say 'thank you' for the reference to the work of Gregory Chaitin. Having been in the trenches way too long and being highly subject to the programming languages network effect, it seems I hardly ever drink of the nectar which fuels deep thinking on topics important to CS. I guess there's a significant difference between CS and IT in general and I appreciate the peeks behind the conceptual curtain more now.
;)
Anyway, I'll find some way to let my wife order those books.
Thanks again.
Please mod this post only if you think others should/n't read this. I have enough ego^H^H^Hkarma. Thanks!
Not to troll, but what are you smoking?!
Did you get fired over a misplaced operator in the past, or something, and still hold a grudge against C? Because operator precedence is not the major obstacle to readability in any language. Let's talk about block structure.
Lisp:
(while (< (point) (match-end 2))
(setq s (read (current-buffer)))
(if (<= (point) (match-end 2))
(setq tcl-default-command-switches
(append tcl-default-command-switches
(list (prin1-to-string s)))*))))))
Java:
if (imp==null)
{IJ.noImage(); return;}
if (arg.equals("reset")) {
nLanes=0;
saveID=imp.getID();
if (plotsCanvas!=null) {
plotsCanvas.reset();
}
*
return;
}
I've inserted a star in each of these code snippets. Which block does the star fall in? This is what makes the C/C++/Java/Perl languages 30 times more readable, for all their faults, than the Lisp/Scheme family.
What's that? You say Emacs has built-in support for helping you find out which s-expression the star is in? Dude. If you need a computer to help you read code, the code isn't readable.
Let's be honest here. What are the real usability problems with languages?
I haven't done usability testing with programming languages. But I can guess what you'd find if you did:
Lisp goes against every one of these principles.
Andrew Wiles
a**n + b**n != c**n for n > 2
Since little companies seem to manage to upset big ones' applecarts from time to time, I'm sure that's true at the big companies, where bureaucracy is more important than profits. This same effect might be connected to HP's decision to dump their calculator division?
See what I've been reading.
I can't remember, but I sure could use some more peanut butter cups.
Your guess was close, but it was even more traumatic than that. A stupid TA took off points because I left a superfluous BEGIN/END in my Pascal program, around a single statement terminated by a semicolon underneath an IF statement. I insisted that the reason the null statement was defined in Pascal was exactly for that purpose. And that the code was more maintainable because it was easier to insert and delete debugging writeln statements in the if statement, without having to move to the previous line and add a semicolon. But he marked me off anyway.
Yeah, I admit it. I have written functions that go on for pages and pages, and I need Emacs to help me understand and edit them. Out of necessity and haste, I've written lots of horrible code that isn't readable, and I've been stuck working with and maintaining a whole lot more unreadable code than I could ever write myself. That is life. Thank McCarthy for Lisp and RMS for Emacs. Now where do we go from here?
Wouldn't the world be a better place if more programs were written in languages that were essentially easy to maintain and more robust against mistakes, misunderstanding, code rot and entropy?
I view parenthesis like the tie-downs and steel bars that reinforce a building against hurricanes and earthquakes, such as email corruption, global search-and-replace damage, tab changes and misleading reindentation.
Please don't pigeonhole Guido van Rossum as a usability guru -- GUI is only 60% of his first name! He's really a completely general purpose Guru! Python is just the latest thing that Guido is well know for. Just as Java is for Gosling, who's also implemented several programming languages that most headhunters have never heard of.
-Don
Take a look and feel free: http://www.PieMenu.com
I agree that language ease of use is not just a function of programmer skill. But I think its more of a function of the programmers background. Consider, Java. It syntax is designed to look a lot like C and C++, to make it easier to use for people coming from those languages. While the syntax of Java may appear close enough to someone who has done all thier programming functionally in C, object orientation, exception handling, and so forth are still foriegn. By cloaking them in a familiar syntax you make it easier for them to learn, but drop that programmer into an interpreted smalltalk environemnt, or throw prolog at them, and they will be much more lost.
The analogy has to be made to natural languages. In english we 'get on a bus' where in fact we ride inside it. In other languages you do in fact 'get in the bus'. More particularly, in navaho (sp?) a man cannot be kicked by a horse, he allows the horse to kick him. In that language the horse cannot be though of as having intent. The same sorts of things are true for programming languages. In some langauges particular thoughts are easier to express than others, and lend themselves to specific ways of thinking. In C no matter how hard I try I cannot encapsulate... Yet C remains a perfectly satisfactory way of expressing a great number of things. At times it is expressiveness superior to languages that do provide encapsulation.
When you pick the right tool for the job, you are picking it based on what you know, and that boils down to a qualitative decision based on how you are used to thinking.
--locust
I stumbled on a thoughtful discussion about lisp
The Rise of ``Worse is Better''.
Even though I don't care about lisp it made me come to the conclusion that XSLT is not a good idea. They have set a goal (no side-effects) with one hand and try the hardest to work around it with the other, making it practically impossible.
When different approaches to comparing two objects can come up with both true and false there's something wrong, a commite's work that's going to give implementors headaches forever.
What's that? You say Emacs has built-in support for helping you find out which s-expression the star is in? Dude. If you need a computer to help you read code, the code isn't readable.
Hmm, does your editor hilite language keywords? Strings? Comments? Should it? Can you do without it? If so you might want to turn it off. Oh you like that feature? What about autoindenting? Does allowing the computer to do it for me mean I am white-space impaired? Most people would agree that any aid the computer can give is a good thing; it's what computers are for.
Regarding your example, yes it is easier to immediately spot the block in the Java code. I remember when I first started struggling with Lisp. I found it very hard to read code, and I had to concentrate very hard on starting and ending parens, where each block was etc. I quickly got much better at understanding Lisp code visually. And most lisp environments have an editor available that will auto highlight the matching paren when the cursor is on one.
By the way I think your little list of usability principles perfectly describes assembly language.
[ (x,y) | (x,y) <- zip [0..] someList, goodResultQ y ]
Easy, automatic testing for Perl.
Your message is (Score: -1, Troll), but I think this part deserves a response:
True. Assembly language is off the other end of the scale, of course: it's too flat, the lines are too short and there are too many of them.
Andrew Wiles
a**n + b**n != c**n for n > 2
Your comparison is badly biased. In the Java code you put
the * on a separate line and in the Lisp code you didn't.
If you had done so in the Lisp code and had indented
correctly, as any good Lisp programmer would, they would be
equally readable.
I disagree with "Deeply nested code and structures are confusing.
Flatness is good". Too much of either one is a bad.
You seem to be assuming that Lisp LOC are longer than Java
LOC. That certainly hasn't been my experience, having done
a lot of programming in both languages. Quite the opposite.
If your problem is "we need 50 coders to maintain our external Web site", you choose a language where lots of people are available and there are lots of libraries to do the standard stuff. That's why Orbitz's Web site code is in Java.
To a Lisp hacker, XML is S-expressions in drag.
He he. RIP LISP.
--exa--
Re: I haven't done usability testing with programming languages. But I can guess what you'd find if you did:
I'm not into hard-and-fast rules but I don't think these two points are radically inconsistent with most style I see observed in Lisp code. Lisp doesn't have a statement concept, but things very like statements do typically occur on their own line. People don't start blocks and put all the subexpressions on one line, though they could. So, to be honest, I have no idea what you're getting at here. I see nothing Lisp does to really push against this issue one way or another. The comment seems equally applicable to C, even though there, too, people by choice tend not to do the thing the language would let them and that you seem to fear.
Of your various "style rules", this is the only one that I could clearly say there's a parting of opinion on. Now, I know parsing reasons for making this distinction. And perhaps there are teaching reasons. But I've never heard it asserted that this was a readability issue and I'd like some exposition here in order to understand your motivation (both so I can reply and also just because I'd be fascinated simply to understand your reasoning on this in general).
There could be a readability issue here, but a priori I don't see one. In fact, my experiences with things like HyperTalk and this statement/expression issue, since there you have to say for each function which kind you are making, is that you often end up with things that are nominally intended to be expressions but that you want to use as statements. So you do "get foo()" just to make an expression into a statement, even though you plan not to use the "it" variable that "get" sets up.
I find the statement/expression distinction to be tedious and pointless as an enforced mechanism. Though in practice, again, Lisp programmers often have certain expressions they tend to think of as kind of statement-like and so tend not to embed in well-styled code. So again I don't see a problem.
The ordinary use of block structure, and the commonplace use of separating blocks into separate functions, both practices introduced decades ago in Algol and long-practiced not only in Lisp but in most major languages seems to make the issue of deeply nested code not an issue. I'd need to see an example to know what this was about. I don't think Lisp gets a lot more nested than most other languages. Certainly nothing about the language forces this. Unless you want a language like Basic or Assembly that doesn't allow any nesting, I don't see how to avoid at least the possibility, and beyond that it's all just personal taste and personal practice, not language design. Do you see otherwise?
You know, at MIT on a mid-term exam in compiler design 20 years ago, I actually saw a question that was "Gotos are (a) good (b) bad". I was immediately alerted to the fact that Computer Science should probably be better named Computer Religion, since it's often more filled with unfounded religious dogmatism than with science. I believe goodness and badness are things that have to be context-relative. One can't just stop a sentence after the word "good" or "bad" without establishing a context and have anything other than a statement of religion. It may be that flatness is good for some unspecified purpose, and that if you specified that purpose we could talk about it more. But I won't give you unqualified Good® on no more than you've offered here.
I have to say I don't know where this comes from. Lisp has an error system capability that is unmatched by any other language I've seen, and has the best guidelines for writing error messages that I've seen anywhere also. If you want an abstract overview of its capabilities, see my paper Exceptional Situations in Lisp . It is not possible to make a programmable facility that leaves the programmer any discretion at all and not risk that someone will do something obscure, but (again) you can't blame the language for that. As a rule, Lisp error messages, in part because they are object-oriented, and in part because of the power of Lisp's powerful FORMAT facility for producing formatted output, seem to me to be much better than I get in other languages. So I'm not sure what you're talking about here.
Kent M Pitman
Philosopher, Technologist, Writer
The example given is
,func x yz)
,index)))
,list ,@more-lists)))
...
...
...
(loop for x from 0
for y in '(a 1 b c 3 4 d 5)
when (symbolp y)
collect (list x y))
=>((0 A) (2 B) (3 C) (6 D))
and was compared favourably to a more Lispy alternative
(do ((x 0 (+ x 1))
(y-list '(a 1 b c 3 4 d 5) (cdr y-list))
(result '()))
((null y-list)
(nreverse result))
(let ((y (first y-list)))
(when (symbolp y)
(push (list x y) result))))
Since I'm learning ANSI Common Lisp from Graham's book,
I thought it would be an interesting exercise to use mapcon.
As Steele explains, mapcon allows "the mapped function to
return a variable number of items to be put into the output
list. This is particulary useful for effectively returning
zero or one item:
(mapcan #'(lambda(x) (and (symbolp x) (list x))) '(a 1 b c 3 4 d 5))
=>(A B C D)
In this case the function serves as a filter; this is a
standard LISP idiom using mapcan."(I've tweaked Steele's example)
The problem is than mapcan doesn't tell the mapped function
where it is in the list, so I elaborated:
(let ((i 0))
(mapcan
#'(lambda (x)
(prog1 (and (symbolp x)(list (list i x))) (incf i)))
'(a 1 b c 3 4 d 5)))
=>((0 A) (2 B) (3 C) (6 D))
At this point I realised there was something wrong
with the discussion. It starts with a quote from
Graham's book and ends by contrasting the aesthetism of
Scheme with the pragmatism of Common Lisp. On the one hand
Graham has been painted into the aesthetes corner, but on
the other hand his book on Common Lisp is striking for its
pragmatism; he is trying to rescue Lisp from the aesthetes.
Graham covers DO in chapter 5, macros in chapter 10 and only
gets round to disapproving of LOOP in chapter 14. This
distinctive approach cries out for explanation and it is
clearly not due to Graham sharing the minimalist aesthetic
of Scheme.
I am going to stick my neck out and risk putting words into
Grahams mouth. His distinctive claim is that programmers
spend their days sitting at their keyboards typing in macro
expansions. If they could step back from the nitty-gritty of
coding and type in macro definitions instead, then the
computer could do the expansions for them, and much work
would be saved.
In the example the mapping functions, mapcar and mapcon, are
inapplicable because they lack a sense of place, of where
the mapped function is in the list. One way of responding to
this is to start typing. One cannot use the built-in mapping
functions, so one falls back on the basic iteration
capability. The surface syntax had better be attractive
because one will be typing it alot. An alternative way of
responding is to start thinking. How does one add a sense of
place to the mapping functions?
(defmacro countcan (index func list &rest more-lists)
`(let ((,index 0))
(mapcan
#'(lambda (x &rest yz)
(prog1 (apply
(incf
does the trick, allowing one to write
(countcan
index
#'(lambda(x)
(if (symbolp x) (list(list index x))))
'(a 1 b c 3 4 d 5))
=>((0 A) (2 B) (3 C) (6 D))
and one is back in business as far as mapping over several
lists in parallel
(countcan
index
#'(lambda(x y)
(if (eql x y)(list (list index x))))
'(c b a d)
'(a b c d))
=>((1 B) (3 D))
So Graham is not concerned with balancing the purity of
typing
(DO blah blah blah blah
against the pragmatism of typing
(LOOP blah blah
because he is intending not to type either of them all that
often. His plan is to type
(DEFMACRO purpose-built-iterator-17 blah blah
and then to win back the time he spent thinking with
quicker, easier coding in the rest of the program.
DO fits into this plan better than LOOP.
> No one cares how useful a programming language
> is - they care how many competent programmers
> they can hire who can code with it. This is why
> Lisp, ML, Haskell, Prolog and the rest have
> been consigned to the dustbin.
I strongly disagree.
In every large software system, there is a complex part. Writing this part in a lower level language (like Java) is giving up a lot of competitiveness, because your system will be inherently limited by the architecture choice.
Dont misunderstand me, Java (for example) is of great value, giving you a great standard of interoperability.
But for the part of the system that makes you headaches, choose a powerful language for fast prototyping, dynamic behavior and with code generation features (macro facility).
And of course, pay the higher price for experts, and get rewarded by a system having unique capabilities.
And even if you want to stick to Java (as example), you will be better generating this code out of a powerful meta language.
Anyway, this approach has of course some negative sides, but what would be our business without challenges...
I don't understand why you think precedence is something that's a "confusing" concept in general. I was taught that multiplication comes before addition in primary school...!
Also, because these rules don't tend to change in a language, I fail to see how relying on precedence makes code hard to maintain or easy to break ("brittle"). It won't break spontaneously, if that's what you mean. Somebody who does not know the language's rules has to come along and edit your code first.
If you're using a language for expressions, you've got to know the rules. When using any language with infix expressions, the precedence rules just belong to the rules that you're required to know, just as some other essential grammar rules for that language.
The only situation where you run into trouble is if you either believe that knowning grammar at all is optional, or that precedence rules don't belong to an infix expression language's grammar, and I don't think you can make a good case for either.
All generalizations are false, including this one. (Mark Twain)
What they didn't teach you in elementary school was that there might be any more than TWO levels of precedence. Nothing from elementary school prepared you for the FIFTEEN or so levels of precedence on C. Two levels was bad enough, but FIFTEEN is RIDICULOUS.
The fact is that the rules DO change from language to language. Each language with precedence rules has ITS OWN SET OF OPERATORS. Some blindly copy the precedence rules of C, but none of them are exactly the same.
And the rules of C++ have been changing for many years, so much that it's a running joke. If you think mathematical notation is so wonderful, then why can't you multiply a and b by writing "ab"?
Now do you still really want to blindly copy mathematical notation? Read Bjarne Stroustrup's paper, "Generalizing Overloading for C++2000" to see where that will lead. If you still think it's a good idea after reading that, let me remind you he wrote it as an April Fools joke. (The paper, not C++.)
Relying on precedence most certainly DOES make code hard to maintain, and easy to break ("brittle").
It's a fact that code changes over time, and many different people make those modifications. If any of those people did rely on precedence instead of using extra parenthesis, the chances are much higher that the code will break whenever you or somebody else modifies it. Much worse than simply breaking with a syntax error: its meaning will change, but it will still compile without error, so you probably won't even notice you made a mistake.
By "brittle", I mean that code should be ROBUST in the face of CHANGE, and precedence flies in the face of that.
For example, if you foolishly write a big "if" statement that spans several lines, has many sub-expressions with addition, multiplication, shifting, ?: conditionals, ands, ors, or any other operators at different precedences, it is extremely difficult and time consuming for anyone else to come along and modify that code, without reindenting it and wrapping it all in parenthesis, simply to understand what it does.
Second of all, you are probably responsible for many bugs youself, because you reply on precedence! How is the poor sucker who has to debug your code supposed to figure out if you really MEANT to depend on the subtle order of evaluation, or if you were simply too foolish to put in enough parenthesis so there was no visual ambiguity, therefore no bug?
If you're DESIGNING a language for expressions, you've got to design GOOD, SIMPLE, CONSISTENT, EASY TO REMEMBER RULES, or else the poor victims who have to use your language will waste a huge amount of time and energy trying to make up for your stupid mistake as a language designer, and fixing bugs they never would have encountered were it not for your short sightedness.
This is a discussion about the DESIGN of programming languages. It's acceptable to QUESTION the rules, instead of blindly following them, and blaming the victims for the mistakes they couldn't help but make, because their language was badly designed.
Don't act like such a pedantic school teacher with a ruler always ready to smack the hand of anyone who makes a mistake. Rules should not be designed as opportunities to PUNISH people for breaking them. They should help people get their work done more easily and efficiently, instead. And precedence rules cause much more harm than they do any good.
How does not having to type parenthesis really improve your life? If you were a good programmer, you'd type them anyway, because it's your duty to write robust maintainable easy to read code. Precedence rules only open up the door to hard-to-spot mistakes, they don't prevent any.
Precedence rules come from written mathematical expressions, which is a two dimensional visual language. Conventional programming languages are written in ASCII, which is a one dimensional string of characters. It's not possible to directly express the two dimensional branching and grouping in ASCII that you can in written mathematical expressions, therefore you have to use parenthesis and other explicit grouping and associative techniques. Precedence rules are subtle, invisible, and a totally arbitrary convention copied from mathematics and then taken to a ridiculous extreme. There's absolutely nothing "natural" or "essential" about it, like the rest of math. It's like arguing that racial prejudice is good and natural, just because you learned it from your parents.
Mathematical notation was arbitrarily made up over history by many different people. As you should know, there's no rhyme or reason to most of it, and a bad notation can certainly get in the way of understanding the problem.
That's why Alan Turing and others had to invent their own ways of writing expressions like differential equations, that make the problem easier to understand and work with. There is certainly room for evolution and improvement -- mathematical notation was not carved on stone and handed down to us from God.
It's ridiculous to say that precedence rules are easy to learn, because they're based on mathematical notation. People aren't born with it. They have to learn it over time, just like any other syntax in any programming language. Most people in this world have very little understanding (and a lot of misunderstanding) about math, and couldn't give a flying fuck about traditional mathematical notation.
I don't believe knowing grammar is optional, but I do believe the grammar should be simple and well defined enough that you can quickly learn ALL of it. This is certainly NOT the case with C++. Off the top of your head, what's the syntax for declaring and using a pointer to a member function? How did your knowledge of mathematical notation help you with answering that question? And what's the relative precedence of that syntax, compared to pointer indirection? How do you use an array of pointers to member functions?
Whatever it is, you'd better put in a lot of extra parenthesis, and use temporary intermediate typedefs and variables, if you want your code to be readable, maintainable and robust.
If you protest that it slows down your code, you don't know the first thing about compilers. If you protest that it slows you down, then that's good, because you should realize that writing robust code prevents bugs and saves a whole lot more time and energy in the long run.
-Don
Take a look and feel free: http://www.PieMenu.com