Samurai - Protecting Critical Data in Unsafe Languages

Samurai - Protecting Critical Data in Unsafe Languages. Karthik Pattabiraman, Vinod Grover, Benjamin G. Zorn.

Programs written in type-unsafe languages such as C and C++ incur costly memory errors that result in corrupted data structures, program crashes, and incorrect results. We present a data-centric solution to memory corruption called critical memory, a memory model that allows programmers to identify and protect data that is critical for correct program execution. Critical memory defines operations to consistently read and update critical data, and ensures that other non-critical updates in the program will not corrupt it. We also present Samurai, a runtime system that implements critical memory in software. Samurai uses replication and forward error correction to provide probabilistic guarantees of critical memory semantics. Because Samurai does not modify memory operations on non-critical data, the majority of memory operations in programs run at full speed, and Samurai is compatible with third party libraries. Using both applications, including a Web server, and libraries (an STL list class and a memory allocator), we evaluate the performance overhead and fault tolerance that Samurai provides.

An acceptable overhead for the pleasure of using an unsafe language? You decide.

Comment viewing options

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

This is unconstructive and

This is unconstructive and you've already said it, but I can't help myself. This looks like a very unsatisfactory solution to a problem that has a very satisfactory solution.

Ditto

The extent to which people are willing to go to avoid using better tools boggles the mind.

But when the ball drops on the cat's tail...

I do find some amusement value in all of this, though. The Rube Goldberg / Heath Robinson spirit lives on...

Indeed, brothers. Let us

Indeed, brothers. Let us condescend.

Wrong word?

Condescension would imply that I'm making some effort to come down to an inferior level. I didn't intend to make any such effort.

Designing and implementing systems to be inherently unsafe, and then retrofitting them with additional features designed to make them safer, bears quite a strong resemblance to the examples I alluded to. I submit that if you don't see any humor in that, you're way too close to the problem, and way too sensitive about it. Step back and laugh a little.

I meant "condescend" in the

I meant "condescend" in the sense of "behave in a patronizing and condescending manner." While this thread seems to have turned into a general flame-fest, it started out as a series of unilluminating, self-congratulatory one-liners of the kind I tend to associate with retired Lisp hackers. That's not to say I think Samurai sounds useful -- I don't. I just think condescension is ugly.

One-Liners and Attitudes

Having offered at least one of the one-liners: guilty as charged.

But you know what? I don't care. I've been using C++, off and on, since 1990, and C before it, and Pascal, and a couple of assembly languages. So when I dismiss something about making C or C++ safer in one line, it's because I have a high degree of confidence, based on direct experience, in the utility (or lack thereof) of what's being discussed relative to other options. What those options might be, their cost, the relative merits of one-time costs vs. (hopefully amortized) ongoing costs, the relationship to the Time Value of Money, etc. have all been explored in this thread, inflammatory though some of the comments might be.

There have most definitely been times when I've said things on LtU that I've regretted—in particular, when I have singularly failed to make my criticisms strictly of an idea rather than an individual—and I'll offer any mea culpas that any of those individuals desires. But I'm done playing Mr. Nice Guy regarding technology choices. Some technology choices are superior in a given context; some are inferior in a given context. As I've said elsewhere, it's extremely difficult to imagine the context in which bolting safety onto inherently unsafe languages is obviously superior to switching to a safe language, and the arguments against that claim do nothing but reinforce the observation that there's far too much "sticking with the devil you know" in the industry, and a serious—debilitating, in many cases—unwillingness to learn enough about the alternatives to be able to offer sound judgments about them.

Don't save the tarbaby

That's not to say I think Samurai sounds useful -- I don't.

Samurai sounds as though it could be useful enough, if your problem is with memory corruption in a large enough C/C++ system, where the costs of rewriting, retraining, and/or otherwising fixing the system are prohibitive. There's no question that systems like this can have large real-world economic value.

However, that doesn't make the situation any less silly - if anything, it compounds the ridiculousness. For me at least, this perspective is not directed at the inventors of a system like Samurai, but at the state of the industry, which in some ways is thrashing around in a self-created tarpit. See Paul's comment for more on that.

Gallows humour

I just think condescension is ugly.

Perhaps my interpretation is off, but I saw the first few posts in this thread not as condescending but rather as gallows humour: making light of something that otherwise might make you feel gloomy.

Some of us have been kicking around here for quite a while, and this is not the first (or even 26th) time some of these ideas have been floated. After watching a parade of PLT innovations come down the road over that time, it is a bit discouraging to see some of the more solidly-proven techniques draw the same old objections yet again. (And we aren't talking some new-fangled FP/monad/dependent types/thingamajig here, we're talking about basic memory safety!)

I don't think anyone was looking down on anyone, nor do I perceive any self-congratulation. But having carefully considered the alternatives and issues for a long time, some of us believe strongly that there is a better, well-established alternative for a very wide variety of projects (much wider than is currently practiced), and that the only real reason these haven't made more headway is garden-variety industry inertia.

Surely you can allow a bit of dark humour at the expense of that fact: we all just need to keep our spirits up.

_

_

Lots of them

The satisfactory solution is using a safe language. Even something as crude as Java solves this problem.

Yawn..

This is unconstructive and you've already said it, but I can't help myself. This looks like a very unsatisfactory solution to a problem that has a very satisfactory solution.
....

The extent to which people are willing to go to avoid using better tools boggles the mind.

In other words, don't try to add safety to something inherently unsafe, just remove the unsafe constructs

And if any of the 'safe' propents above have missed out that is doable today by any good compiler or tool, it is a trend in fact...

C++ has unsafe constructs for backward compatiability (and lets face it none of you are running more bytecode than 'unsafe' chips/hardware) and for the record, you just have to point to creator's site (one of the true legends of compiler field ) and look for 'not using unsafe constructs'.

So it is a compilation or coding standard issue, and your point about 'unsatisfactory' becomes mute. Also, thinking 'unsatisfactory' is not what will accelerate or bring you the next advance in computing is plain wrong as evidenced by all the new hardware manufacturers.

But hey, LtU is not what it used to be, it is more into bloat your way to CLR or JVM or interpreted backed nonsense.

but I also think most people living today, and reading LTU as an example, don't fully understand why the ability to make something was more important than architectural elegance was.)

Exactly. And the argument that 'unsafe' C++ not using pointers but references, not using union hacks etc, not using casting (something 'safe' Java or C# and plenty of others like F# do, blewh), looks much different to any other code (other than FP language) is absurd.

Semantics are almost (but not entirely) identical, just that C++ ones really represent the machine abstraction more closely and efficiently. Heck give it to a kid and it will tell it looks the same, try it out for yourself.

And this is where static typing of C++ and the meta-programming capabilities come in. This is the new C++ and implemented right now, and it is all about static checking. But hey, I do not expect any runtime or garbage collected zealot will ever get that.

You want 'safe' just enforce it. You want to interface with unsafe hardware? Modular approach to that work (aka different standard or tool or compiler) would help. Btw, static code analysis works even in the old C and is becoming more popular than you would believe in fact.

[Community] Le't get back on track

But hey, LtU is not what it used to be

Based on recent developments in this thread, you are right.

Let's get back on track, and here's how you can help:

  • Use your real name, or at least a reputation-backed pseudonym. Recently created accounts without accountability can't really be taken seriously as contributors to sensible discussion.
  • Try a less confrontational tone: if you have any substantive points to make in support of your opinion, the well-informed and open-minded people who read this blog will be able to perceive them better when they are presented in a civil tone rather than a sneering one.
  • Avoid generalizations about the readership here: though some of us are more vocal than others, I believe there is a much wider range of views out there. Many may be sympathetic to your position, but no one will be won over by or want to be associated with an insulting tone or the casting of vague aspersions. Moreover, some of the people you are characterizing as zealots may in fact know a lot more about the alternatives than you are giving them credit for. Assuming that those who disagree with you are merely ignorant is an unwise and unproductive position to take. It certainly won't do your point of view any good.

Hopefully you can see the wisdom of modifying your approach to be in line with the policies and spirit of LtU, and will take this advice to heart.

C++ minus everything

And with C++ minus pointers, references, arrays, casts, deallocation, subtyping, and libraries whose interface requires any of these, you can still do exactly what?

OT: Eternal September

But hey, LtU is not what it used to be,....

IIRC, LtU used to be Ehud, Andrew and myself seemingly talking amongst ourselves. Ah, those were the really good old days. :-)

The upside

You're missing the upside guys: after spending some time messing around with this approach, even the most die-hard "bare metal" jockey will say to himself "There's got to be a better way....".

From there, next stop LtU. ;-)

Safety-critical systems

I don't think this approach is completely useless. In safety-critical systems such as medical devices, it is required that developers perform a fault tree analysis on critical paths of code (say, the one that turns on the laser) and protect against all contemplatable errors that would arise -- cosmic rays, buffer overflows from elsewhere, spurious interrupts, etc. Approaches such as memory protection are valid in such an ultra-defensive code style.

They don't mean it's useless

They don't mean it's useless to protect memory, they mean that this approach to protecting memory using memory unsafe languages is useless. The preferable approach is to use a memory safe language, and to add some fault tolerance to protect against memory errors, cosmic rays, and so on. In other words, don't try to add safety to something inherently unsafe, just remove the unsafe constructs.

Large existing code base?

I assume the use a safe language comments are mostly for amusement.

My guess is that this sort of solution is intended to be used by making small changes to existing programs - is that wrong?

No Doubt...

...this is the intent, and no, of course it's not wrong in and of itself. Where my particular skepticism comes from is precisely the observation that, in a large existing code base, the cost of determining where these small changes are necessary, implementing them, ensuring that they are semantics-preserving, and then rinsing and repeating as the codebase continues to evolve is likely to be higher, in practice, than the one-time cost of rewriting in a safe language. Working in unsafe languages incurs, in my experience, a vastly underestimated quality (here, primarily memory safety) debt over time, resulting in a horrible Catch-22 where as the need to replace the code becomes increasingly obvious, so does the risk, because the actual behavior of the system can't be articulated with any precision. This is the realm of Working Effectively With Legacy Code, months or years spent developing characterization tests, refactoring the code to support either new development of the existing codebase more easily, or rewriting it, and, if you're very lucky indeed, Domain-Driven Design.

What seems apparent to me (again, I cannot presume to speak for Derek or Anton) after over 20 years of industry experience is that projects—managers and developers both—routinely underestimate the cost of continuing to use unsafe technology relative to the cost—which, to be fair, is generally excruciating in the short term—of re-developing using safe technologies (where "safe" could just as well mean a good memory-safe dynamically-typed language such as Erlang or Smalltalk or Lisp or Oz as a memory-safe statically-typed language such as Scala or OCaml or Haskell).

if only

... the cost of determining where these small changes are necessary ... is likely to be higher, in practice, than the one-time cost of rewriting in a safe language.

Oh if only we knew when that was true!

I think we also might guess that managers and developers both routinely underestimate the cost of moving to new technology relative to the benefit.

Sure

Yes. But I'd feel very differently if half of the projects I've been on chose to evolve the existing codebase and half chose to rewrite, as opposed to my actual experience, which is a whole lot closer to 99% evolving the existing codebase, watching the bug count increase rather than decrease, and doing so over a period of months or years while paying the teams' salaries and, often, third-party consulting fees as well; vs. maybe (optimistically) 1% rewriting the system from scratch.

[Update: I've seen lots of projects rewrite... using the exact same methodology, the exact same framework, the exact same language... this isn't what I'm referring to above.]

Note that I have no connection to the Mozilla project, so I can't comment on specifics. But it might be interesting to consider the trajectory of Mozilla from it's point of forking from the Netscape code to what we now know as Firefox, not forgetting that the result is not just Firefox, but also Gecko HTML engine and other things built with it, such as Thunderbird, as well as the XUL infrastructure, Spidermonkey JavaScript engine, Firebug HTML/CSS/JavaScript debugger, and so on. In other words, the short-term costs of rewriting seem gargantuan by any rational measure, and it's not at all obvious that Joel Spolsky was wrong to say that you should practically never do this. But it's also not obvious that, strategically, it wasn't the right choice for the long term given a very different strategic goal than just "we want to have an open-source browser." The Mozilla infrastructure is a platform unto itself. XUL and the plug-in architecture represent an interesting initial stake in the ground; as Brendan Eich makes clear right here, the evolution of ECMAScript is very much about extending the platform inwards, with more of the "browser" (whatever that means in such a context) written in ECMAScript and less in C++, with the concomitant benefit of more of the platform's functionality being available via reflection and introspection, allowing greater innovation on the platform.

Realistically, could they have gotten there with the Netscape 4 codebase without a rewrite? It's an honest question—I think there's at least one, and more likely several, case studies in the Netscape/Mozilla experience. Hopefully they will be written someday.

[Update #2: An important cost factor that I think tilts heavily in favor of the one-time rewrite is the ongoing cost of using unsafe languages as the code evolves. You don't get to just find the problem spots once, write tests, and make the tests pass. You have to do that over... and over... and over again. With a one-time safe technology switch, you do that once, and your tests get to focus on the business logic instead of safety issues.]

conservative change

But I'd feel very differently if half of the projects I've been on chose to evolve the existing codebase and half chose to rewrite ...

Rewriting the system from scratch also involves paying the teams salaries and third-party consulting fees and all those risks you listed for making small changes to an existing code base, plus re-training and re-tooling and ... !

The unquantified ongoing cost of using unsafe languages is the project norm - until we can say with confidence how much will be gained from a one-time safe technology switch I don't think it's unreasonable for managers and developers to be skeptical and conservative.

Conservativer than thou

I don't think it's unreasonable for managers and developers to be skeptical and conservative.

I don't think any of us are disagreeing with that.

The point is that retrofitting with Samurai doesn't seem any less risky than a targeted rewrite.

And if you are starting a new project that needs that functionality, where Samurai might be a more feasible solution, maybe it is worth thinking about a safe language instead.

(For the record, my first reaction to this thread was like yours, that it might be useful in certain circumstances. After perusing the paper though, I was less than convinced of its utility in any circumstances that didn't already have better "conservative" solutions.)

doesn't seem any less risky

When rewriting the system from scratch in a safe language is described as a targeted rewrite, I don't understand what is meant by a targeted rewrite ;-)

So often we seem to have these debates without bounding any of the variables. If with Samurai we had to change 5,000 lines in 10 million that's a world of difference from a rewrite. If with Samurai we had to change 1 million lines in 10 million then we have a very different situation.

I don't know enough to have an opinion about how useful Samurai would be for it's intended purpose.

Assumptions revealed

When rewriting the system from scratch in a safe language is described as a targeted rewrite

The hidden assumption here is that the "critical memory" bits can be isolated from the rest of the system. (AFAICT this is the same assumption that Samurai makes.)

If that portion can be isolated (even with a bit of work), why not rewrite that portion in a safe language rather than using Samurai?

If you can't isolate those bits in any way, you're pretty much screwed, even with Samurai. ;-)

Like Paul, I've actually done quite a bit of architectural retrofitting of this kind, so my sense of the relative conservativeness of the various options is not merely academic. ;-)

Nothing hidden to reveal

Paul explicitly said rewriting the system from scratch - if you think it would be practical to rewrite portions of a system in a safe language then I agree that's a different situation.

I'm not sure why having parts of the system written in a safe language and parts written in an unsafe language would be more appealing than something like Samurai in a C shop.

not merely academic - and yet still not actually specific.

Nothing revealed that should be hidden

would be more appealing than something like Samurai in a C shop.

Now we've moved from technical merits to sociology. If a group of programmers thinks they are better off programming while leaping through hoops of fire, I'm unlikely to convince them to just sit at a desk by technical arguments. I can only offer my dispassionate assessment and advice. ;-)

and yet still not actually specific.

Specific, non-trivial examples are usually way more complicated than can be easily (or wisely) discussed on LtU, as I'm sure you know.

If you have some problem that you think Samurai solves better than the alternatives, by all means, use it: you know your problems better than we do.

We can only speak from the set of problems that we have each come across.

Important angle

I think contrasting library based approaches (such as Samurai) and multi-language approaches to the problem (which can be summarized as having to deal with legacy code, sans rewriting) may be a good way to uncover the issues invovled.

A hierarchy of principles

contrasting library based approaches (such as Samurai) and multi-language approaches to the problem (which can be summarized as having to deal with legacy code, sans rewriting)

Put this way, at that level of generality, I would have to switch sides. ;-)

In general, multi-language solutions add considerable complexity to any project, so my default preference would be a library. (Pace all the DSL fans out there. ;-))

But in this particular case, where the design problem that one is trying to solve is the fundamental inadequacy of unsafe languages to protect memory, adding a library seems like a band-aid (and a hard-to-apply one at that), and a more seemingly-radical, but ultimately safer and long-term sustainable solution would be to switch to a safe language.

In general, maintaining legacy code inevitably seems to involve choosing the lesser evil, and doing what you can now, bit by bit.

With this particular design problem (lack of memory safety) the lesser evil seems to be rewrite critical components in a safe language and bit by bit moving to that language for good. (Though you may never completely finish for that project...)

If there is some other constraint we want to imagine (sociological or otherwise) that makes this impossible, well, that's a different design problem, but I would have to say "Good luck" to the person who had so many constraints on what is already a hard problem. Samurai might be just the thing for them...

Good!

Now we are making progress.

(By the way, since this comes from Microsoft, it might make sense to include Managed C and ilk in the discussion).

the lesser evil seems to be

the lesser evil seems to be rewrite critical components in a safe language

Which only helps if the unsafe language cannot corrupt the memory of the safe language's runtime (e.g., if you turn a system consisting of one process into a system of two processes, which in turn might be considered too much overhead and adding too much complexity of itself when maintaining some legacy system).

Choose the right default

Which only helps if the unsafe language cannot corrupt the memory of the safe language's runtime

We can always find some weird edge case that will fail with any set of solutions.

I would say that if you are in such rough shape that there is no hope of segregating the safe and unsafe uses of memory, your problem space is either very small, or your solution space is nearly empty.

Let me rephrase my argument to head off all the other edge cases one might want to consider:

If safety is critical for an app, the sensible default is to use a safe language. If you can't for some reason, well you can't, but then you are working with a different, bigger problem and a lesser solution.

Curious

OK, I'll bite: in what context is a known-ongoing cost less than a one-time cost? Isn't the conservative position "This one-time cost is outrageous, but at least there's a limit to its scope?" Isn't it quite likely that the ongoing cost point is only accepted because it's a bit like being the frog in the gradually-increasingly-hot pot of water?

Again, honest questions: obviously, I've made my own assessments based on my experience, but equally obviously, most teams in practice make different assessments. I'd like to understand that better (and we should probably bring this back to how PLT issues affect such choices within the next post or two). :-)

PLT meets economics meets people

in what context is a known-ongoing cost less than a one-time cost

Every investment has a cost. A company has finite resources and ideally invests its limited resources in the areas that give the best bang for the buck.

Rewriting an existing piece of software may or may not be the best use of resources (time, money, people). A good model makes the determination pretty mechanical. The art is in building the model.

Unfortunately, it's a known SE problem that its very, very, very hard to accurately determine any of the numbers needed to build a model for a large software project.

In practice most managers end up going with their "gut" which tends to be conservative in general and in particular is likely to be led by the feelings of the existing developers who naturally have a vested interest in the existing infrastructure since they're "experts" in it.

A connection with hardware "design rule checking"

I think the "one-time cost" being outrageous (probably so) relates closely to "type-centric" languages, ones where the compiler does a lot of work in checking types, inferring types (when possible), and generally doing what we in the chip business call "design rule checking."

Chips are obviously a kind of large, complicated program, with various languages and DSLs running in various subareas of the chip. (A thread touched on "spatial" issues as well as temporal issues, and the implications for programming.)

I was in the chip business for a while, though not in chip design per se. (I was at Intel in the 70s and 80s, mostly in device physics. The mention here of cosmic rays is of particular interest to me...)

Besides software tools which enforced a large number of constraints, "DRC" (design rule checking) was run on designs at many stages of completion. This is like "static typing," in the same way a construction material--a steel I-beam, for example--is "statically typed" )with certain strengths, modulus of elasticity, surface treatment, etc., a "rating" which determines price and suitability), and then the bill of materials takes into account the typing. (It's pretty dangerous to not check the type and rely on run-time errors or even test-driven discovery of run errors, not when a dam or skyscraper or Pentium chip is involved!

Some of the things DRC does is to check that the building materials--in the case of chips, conductors, transistors, closeness of positioning to other things, etc.--satisfy all sorts of constraints that have been calculated, theorized, measured, or even have come from failures in the field or in testing. For example, closeness of one conductor to another. (These failures are somewhat different from software failures, in that they are probabalistic: only some fraction of devices built with design rule violations may fail, and these failures may take months or years or decades to happen.

DRC and other tools don't catch all type errors--the famous Pentium FDIV problem in around 1994-5 being a good example of a subtle floating point type error that was not detected early enough.

(And I understand that one of the many things Intel did to try to minimize these kinds of problems was to add new kinds of checking and testing, including an ML guy in the Oregon labs...I don't recall his name, but he's shown up in some FP presentations. Not clear to me what the FP/ML tools are.

I come to the FP and static vs. dynamic typing issue from this kind of hardware/physics set of prejudices: I hope to use all the power of modern computers and compilers to do as much "prep work" as possible to better ensure that specs are met, that certain rare errors are avoided, etc.

(FWIW, I loved Haskell when I first discovered it, several years ago. Not just for the static typing, but for other reasons as well. Reasons which I also believe are closely related to how complex chips are usually built. I may put more of this line of reasoning in another post, if there's any interest.)

--Tim

formal methods at Intel

And I understand that one of the many things Intel did to try to minimize these kinds of problems was to add new kinds of checking and testing, including an ML guy in the Oregon labs...I don't recall his name, but he's shown up in some FP presentations. Not clear to me what the FP/ML tools are.

Maybe you're thinking of John Harrison? (At least that's the guy I know that works with formal methods at Intel, although I'm pretty sure there's a whole team and probably several teams). I know him from going to TPHOLs ("Theorem Proving in Higher-Order Logics") conferences, where he presents papers like "Formal verification of floating point trigonometric functions"; with obvious applications to Intel. (See his list of papers here: http://www.cl.cam.ac.uk/~jrh13/compapers.html)

That sounds right....

That sounds like I was reading about a couple of years ago.

Gotta understand, when I was at Intel it was pretty radical to even talk about Lisp.

(Though some of Intel's tools were, even even in the late '70s, well into the '80s, based on "Mainsail," from "Machine Independent SAIL," from a Stanford AI Lab language. I think many of you may admit that it was pretty radical that a lot of Intel's core design tools were based on such a language. A language which has gotten very, very, very little discusson here or elsewhere. I will tell you that Mainsail and the design tools associated with it were very important for several generations of Intel microarchitectures. Take that as you will, with laughter or whatever, but this was an important language. One which has received virtually no attention. I assume that its importance has lessened in the 21 years since I worked at Intel.)

--Tim

We are fond of history, and

We are fond of history, and I am not hearing anyone laughing. Tell us more!

Ehud, I know little of Mainsail

I think Mainsail is one of the lesser known tribuaries of "advanced beyond its time" languages that actually was important for what are arguably some of the most important chips of our time.

To put it more bluntly, Intel used Mainsail for the core designs of the 8086, 80286, 80386. I'm not sure how much further the use of Mainsail continued.

I Googled Mainsail a few years ago and there was some detail about the status of the current, surviving as of a few years ago, company. I won't try to recap what this account was.

From my perspective, as an outsider at Intel (a device physicist, in the same building as the chip designers, at least back in the 70s and early 80s), you have to understand that there were VIRTUALLY NO DESIGN TOOLS WHATSOEVER. What CAD existed was mainly for aircraft and skyscrapers (mostly via companies like Calma and Applicon, I believe merged into other companies now).

Ted Hoff, usually credited in various ways as one of the inventors of the microprocessor (others being Frederico Faggin, Stan Mazo, M. Shima), developed some of Intel's earliest design rule checkers--essential checkers for static typing constraints. Continuity checkers, programs checking that conductors were in fact contiguous, were one of the earliest and most important such checkers. (Arriving at Intel in '74 and hearing of such things, I'm retrospectively amazed that I was so blase about such a simple thing as having tools to check the continuity of a conductor...I later came to realize this was all part of what Marshall Stone once mandated: "Always topologize."

Several years later, the fact is that Intel had its designs "computerized," whatever one wants to make of that, while our main rival for an mportant design win (a little thing called the IBM PC, which you may have heard of) had his design only extant in a rubylith layout done with X-Acto knives on Mylar. Also, our design was about 30,000 transistors, available now, his design was about 68,000 transistors (more or less....it fit with the name, obviously), and his design would be long time in having variants.

And so we won the design, based on manufacurability, cost, ,and on the abililty to proliferate design variants. (You can read many accounts of why Intel won out over Motorola. I expect no one living today knows the full story, but I also think most people living today, and reading LTU as an example, don't fully understand why the ability to make something was more important than architectural elegance was.)

Intel had a truly amazing amount of specialized tools. We (speaking as if I still worked for them) had labs devoted to obscure effects, to simulations, to applications.

One of these tools was MAINSAIl, or Machine Independent SAIL (Stanford AI Lab/Language, not sure which was the final L). Last I hear, the MAINSAIL product was still being sold out of Bodega Bay, CA, or someplace close to there. A small group, obviously. No idea of what he current status is.

But, remember, this was long before companies like ECAD and Cadence, some of them formed from Intel people. (I knew Todd Wagner and Dick Gruen. Todd I have lost track of, Dick I still see at Bay Area events.)

Someone probably ought to do a story about how a relatively obscure "AI language" was actually used in a major way at what is now the world's largest chip company.

(Still is, last I checked.)

--Tim

Thanks! I know this seems

Thanks! I know this seems slightly off topic, but the history of programming languages was always an important topic around here.

To make sure I understand: Was MainSAIL used to produce tools, or were it used directly as it were to progam the specific rule checks etc.?

MainSAIL was used as a primary CAD tool

MAINSAIL was used as a primary tool for DRC (Design Rule Checking, a kind of static typing checker) and CVS (Continuity Verification Check, a seemingly trivial, but critical, check that conductors were in fact conductors, that is, that continuity was preserved.....amazing how important this was in the 70s and 80s).

Most programming of certain sets of tools was in MAINSAIL. I assume some tools were then subroutines of MAINSAIL.

Later, tools like DRACULA appeared, on commercial platforms. Various CAD companies happened beginning in the early 80s that were not part of the more traditional skyscraper/airliner CAD companies. Companies like ECAD, Daisy Systems, Silicon Compilers, etc. A lot of them merged.

As I said, I don't know how much of MAINSAIL is still in use at Intel. But I will always remember that while the conventional wisdom was that only FORTRAN was important, then only that Pascal was important, then than only C was important, Intel was using mostly MAINSAIL and other hacked-together tools on its main design systems, which were PDP-10s until into the mid-80s.

Ehud, inasmuch as you are in the Bay Area for a while, you might find it worthwhile to track down the MAINSAIL people--whom I believe are in the general area of Bodega Bay, or a neighboring city, Wiki may have details--and talk to them about the 1970s genesis of MAINSAIL and what they can say about Intel's use of it.

I believe several language tools were as important to Intel's success as the more commonly mentioned lithography tools were.

-Tim

I was at a company that used MainSAIL

We were a Computer-Aided Engineering company, concentrating in digital logic design, that spun off of Evans and Sutherland around 1983. The name of the company was Cericor, and it was sold to HP in the spring of 1985. We used MainSAIL because it was supported on almost all of the wide variety of workstation hardware that was out there at the time and because of its memory imaging and garbage collection facilities. We basically rolled our own object system with two fixed base-class definitions, each with a dynamic escape method. Working with objects (even non-language supported ones) was much easier than using the procedural languages available at the time. Xidak, the company that spun off of SAIL to commercialize MainSAIL, still appears to be in business. My presumption is that the language has advanced in the past 23 years and by now has actual object support. But for it's time, it was a pretty good language to work in.

(FWIW, I loved Haskell when

(FWIW, I loved Haskell when I first discovered it, several years ago. Not just for the static typing, but for other reasons as well. Reasons which I also believe are closely related to how complex chips are usually built. I may put more of this line of reasoning in another post, if there's any interest.)

I'd certainly be interested - if nothing else, it'd be interesting to see how it lines up with some of my intuitions.

Your knowledge of Haskell is beyond my own...

You ask how my intuition of Haskell matches my own (roughly speaking). I think your understanding of Haskell, type theory, etc. is beyond my own. But I think this is an importan forum, one I've been reading for several years (since around 2003-4), so I'll ramble on.

I worked with complex chips. Though the 8080A is not complex by modern standards, it was complex in 1974. The year I first tried to figure out what was going on it. Understand, I was a physics person whose previous exposure to programming was a high school exposure to BASIC, circa 1968, and some college classes in "FORTRAN IV with WATFIV" in the early 70s. Horrible, horrible, horrible,..., horrible.

(Fortunately, at about the same time I was exposed to analysis, essentially general topology, a la Kelley, Dugundji, etc. That is, open sets, limits, sequences, chains, compactness, Tychonoff's Theorem, etc. I was mostly interested in relativity, black holes, Hawking, etc., so the connections with computation (a la Dana Scott, Plotkin, et. al.) were totally and completely beyond me at the time.)

Once at Intel, where things seemed initially to be "more of the the same" (NOT an acronym for MOS!), they came to be more and more interesting. In particular, some very large and very complex environments were appearing on the same chip.

(I expect that if I had been in the Alan Kay/Xerox camp I would have seen this as inevitable, but I was working on problems actually implementing the designs, circa the mid-70s.)

It happened, to be modest, that I discovered that alpha particles (and to a lesser extent, not the problem at the time, but described in my papers) were the main (99%) cause of the random, single-bit errors in the dynamic RAMs that Intel was then one of the main producers of. (Our main competitors were Mostek, long since folded into other companies and essentially no longer extant, Motorola, Texas Instruments, and a few others.)

This is sort of far afield of lambda calculus, so I won't go into details. (Though, ironically, there have been papers about the effects of internal chip errors on security of chips, even of cryptography. Search here on "cosmic rays" for details. BTW, "cosmic rays" has always gotten the most attention, even snce my papers in the 70s, but until recently it was actually alpha particles from the surrounding packaging, and the chip themselves (usually 10-100x less important, for various good reasons) that were the real culprits.

Anyway, I saw chip design first-hand, and have had many years to think about it. Typing plays a central role. (I also provided VAX power to the early iAPX 432 group, so I had some early exposure to objects. The same year the famous "Byte" issue on Smalltalk came out. Intel let met spend a lot of time pondering, so the developments in OO in 1980-83 were interesting. In 1984 I went to my first "Lisp and Functional Programming Conference," in Austin, and concluded that FP was what actually fulfilled the key promises of OOP. I worked on FP approaches for a few more years at Intel, then chose to leave in 1986 (for a bunch of reasons too complicated to get into, but having made a lot of money over the years was one important reason).

I have seen FP and static typing as largely the fullfillment of the OO dreams of the early 80s.

Kitchen recipes, woodshop methods are my main touchstones. If this makes sense, "equals for equals" means that one is able to brown sugar, or toast bread, but one had better not call these things other than what they are. Kitchen recipes depend on sugar being sugar, not caramelized sugar, and woodcraft depends on a board being a board (of a certain size), not a planed board, not a sanded board. Functions do indeed change things, as we all know, BUT WHEN THINGS CHANGE THEY NEED NEW NAMES. This is the essence of Quine, of referential transparency, of pure function.

(And this is a principal present in a vast percentage of the transistors and blocks of trasistors on a chip. Virtually always, the same set of inputs to a block of transistors, be they inverters or something more complicated like a math unit, the output is the same. Only rarely does "state" matter, and this in constrained circumstances.

(Speculation Alert: I believe that the cases where "state matters" can be identified in a monad sort of way. Sure, state matters in certain RAM (DRAM, SRAM, cache, etc.) sorts of ways, but most of the chip is operating in a referentially transparent way--given identical inputs, identical outputs. My thesis, or speculation since I have not proved it, is that nearly all hardware devices are nearly always operating in a purely FP way. Not an OO way, either, as there are no mysterious little actors sending "messages" to sort of give the same result that FP gives. Rather, nearly all devices are nearly always pure FP boxes. An important point, I think.)

Anyway, enough for now. I saw enough with chips, and in the intervening years with Smalltalk and Java, and especially in the past several years with Haskell (and other FP languages, though I have the luxury of only focussing on Haskell and not having to compromise wih OCaml, etc.) to see that complex systems are mainly being built in an FP style (there are nearest neighbor, spatial and temporal reasons for this) with referential transparency paramount.

As for typing, which is closely related to this, it's possible to build a house with no typing. Sort of a tree house. Nail this board to this and hope it holds. Find a piece of plywood and hope it's an OK floor. Wrap some rope around the trunk. Pound in a few extra nails. Hope it holds.

But building a treehouse and hoping it doesn't fail is a far cry from buidling an A310 and counting on fewer than 1% loss of aircraft failures over the next 20 years.

Sorry to conflate FP purity (referential transparency, etc.) with static typing (checks of materials, inputs), but I think they are deeply and closely related in a way I haven't quite been able to put my finger on....

(And don't get me started on laziness. I know Simon P-J has sometimes said laziness was not central to Haskell's success, but I disagree. Nothing says loving like being able to say "Let S be the set of prime numbers" without the computer blowing up, Star Trek-stylle.)

Sorry for the length. I've lurked here for several years.

--Tim

Purity and Static Typing

Sorry to conflate FP purity (referential transparency, etc.) with static typing (checks of materials, inputs), but I think they are deeply and closely related in a way I haven't quite been able to put my finger on....

There are actually some clear and strong relationships here. Static typing is significantly weakened in the presence of (more and more) effects. A striking example of this is the massive weakening of parametricity. Even Haskell breaks this mildly: the "obvious" free theorem of seq is false. Another strong example is the value restriction in ML languages and why it is there (namely type safety can be circumvented via polymorphic references). Yet another one is the Curry-Howard correspondence itself, it's much more murky and less useful with partiality in the mix. For variety, some "OO" (subtyping rather) issues arise when we include effects, particularly state. The main issue is that a reference is invariant (i.e. neither co- nor contra-variant). The failure to recognize this is a common problem in most even somewhat popular OO languages and OO programmer's understanding.

Parametricity and ML

Static typing is significantly weakened in the presence of (more and more) effects. A striking example of this is the massive weakening of parametricity. Even Haskell breaks this mildly: the "obvious" free theorem of seq is false. Another strong example is the value restriction in ML languages and why it is there (namely type safety can be circumvented via polymorphic references).

Interesting choice of words. I can write a Haskell program that breaks parametricity. I can name optimizations performed by Haskell compilers that are unsound due to this. Can you write a Standard ML program that breaks parametricity? Can you write a Standard ML program that circumvents type safety via "polymorphic references"? Can you name optimizations performed by Standard ML compilers that are unsound due to issues with parametricity or the circumvention of type safety via "polymorphic references"?

Doesn't anyone care about facts anymore?

History

Doesn't anyone care about reading? Where did I say Standard ML broke parametricity? I said it is massively weakened which is well known. There is only one value of type forall a. a -> a in the polymorphic lambda calculus. There are three in Haskell. There is a countable infinity of them in ML. Most of the free theorems do not hold in ML, many even break mildly in Haskell due to strictness concerns.

As for polymorphic references, this is extremely well-known. -With- the value restriction, no I can't circumvent SML's type system, but if you remove it, which was the case I was addressing, then yes I can. In fact, SML did once not have the value restriction and it's type system was unsound. A similar thing can be done in Haskell using unsafePerformIO and IORefs.

I don't know why you bring up optimizations at all. I said absolutely nothing about optimizations.

Counting

Doesn't anyone care about reading?

I do.

Where did I say Standard ML broke parametricity?

Where did I say you did?

I said it is massively weakened which is well known. There is only one value of type forall a. a -> a in the polymorphic lambda calculus. There are three in Haskell. There is a countable infinity of them in ML.

I can't really know, but a reasonable guess would be that the three values of type forall a.a -> a that you refer to are:

\x -> x
\x -> x `seq` x
undefined -- actually has the type forall a.a

But these aren't all of them. First of all, undefined is a special case of error. Using error you can write a countably infinite number of different values of said type. Even that is not all of them.

Using the Debug.trace function (not in Haskell'98), you can also write an infinite number of values of said type --- each producing observably different output.

Further, using Foreign.unsafePerformIO, which is defined in an addendum to the Haskell'98 standard, you can write roughly the same countably infinite set of values of said type as you could in ML.

Most importantly, however, Haskell's type system does not guarantee termination, which already "massively weakens" parametricity. So, here is another one:

\x -> let lp x = lp x in lp x

Here is one more:

\x -> let lp x = lp (x ++ x) in lp [x]

You can tell the difference if you try to call it. (Wow, Hugs actually gave me a segmentation fault on that one.)

To say that the weakening is more massive in ML than in Haskell deserves a more precise argument than counting with only three fingers.

Most of the free theorems do not hold in ML, many even break mildly in Haskell due to strictness concerns.

There are infinitely many "free theorems" that can be stated. It is unsurprising that the set of free theorems that hold in ML is not the same as the set of free theorems that hold in Haskell. However, if you wish to claim that strictly more free theorems hold in Haskell (whether it is Haskell'98, Haskell'98 with Addendums, or, the most common meaning, Haskell as in GHC) than in ML, you should present a (sketch of a) proof.

As for polymorphic references, this is extremely well-known. -With- the value restriction, no I can't circumvent SML's type system, but if you remove it, which was the case I was addressing, then yes I can. In fact, SML did once not have the value restriction and it's type system was unsound. A similar thing can be done in Haskell using unsafePerformIO and IORefs.

Indeed. Haskell's development seems backwards. AFAIK, Haskell once started as a pure and type safe language. Later feature after feature and optimization after optimization has been added and now there are (impure) features and optimizations that together are now strictly unsound. Frankly, I find it dishonest to say that things are "mildly" broken in Haskell when it comes to things like parametricity --- especially if you then continue by claiming that parametricity is "massively" weakened in ML while also implying it isn't similarly weakened in Haskell.

I don't know why you bring up optimizations at all. I said absolutely nothing about optimizations.
Because it is a relevant issue.

"Haskell"

As is common when talking about somewhat theoretical issues (which itself is the default on LtU), by "Haskell" I mean, Haskell minus the things which are obviously and explicitly unsafe; Haskell 98 if you want something concrete. Why would I mean GHC Haskell when I'm talking about the language itself? In GHC Haskell, there is unsafeCoerce#. That destroys all guarantees. Why did you not pull that one out? Of course, in practical implementations of SML I can easily implement unsafeCoerce as well, if they don't outright provide it, which I believe they do, so your whole line of argument is disingenuous. I don't know why you (seem to) feel like this is some kind of attack on SML (or why you feel you need to defend it.)

The three values in Haskell (98) are:
\x -> x, \x -> undefined, and undefined

The equality that is being used is the common denotational notion where an uncatchable exception (and they aren't in H98) is denotationally equivalent to an infinite loop (i.e. bottom).

x `seq` x is identical to just x

Debug.Trace is not Haskell 98 as you say. unsafePerformIO is not Haskell 98 (though it is Haskell 98 + the FFI addendum). Your lp functions are denotationally equivalent, they are both equivalent to the \x -> undefined case. And as I said, partiality -has- already weakened parametricity by there being three denotationally distinct (or observationally different, where the contexts are terms of Haskell) rather than one, id. If it wasn't for seq (or rather seq being parametrically polymorphic), there would only be two. Using observational equality, there is no way to tell the difference between your two lp functions from within Haskell.

If you are still upset, just go through and replace "Haskell" with "the call-by-need polymorphic lambda calculus with fix" and "ML" with "the call-by-value polymorphic lambda calculus with fix and mutable references".

Later feature after feature

Later feature after feature and optimization after optimization has been added and now there are (impure) features and optimizations that together are now strictly unsound.

How many of these don't involve unsafe* and aren't debugging tools such as Debug.Trace (which strictly speaking involves unsafe* anyway)? Rather the (documented!) point of the unsafe* operations is that the compiler won't treat them any differently during optimisations, the burden of proof belongs with the user. Once in a while someone suggests that there ought to be a compiler flag to list everywhere it's used so that Joe and Moe can be sacked for doing stupid things with the operations in code that doesn't warrant them, and that's something I support.

The value restriction

The value restriction has nothing to do with type safety. It has to do with the compiler converting terms into values quietly.

The polymorphic lambda calculus adds type-abstractions (and application) to the basic typed lambda calculus. These type-abstractions, like ordinary abstractions, are considered values and evaluation does not proceed inside their bodies in call-by-value semantics.

In ML polymorphism, there is no explicit type-abstraction syntax. The compiler, when generalizing to a polymorphic type, inserts a type-abstraction around the code in question. If that code is not currently a value, then it has now become a value because the type-abstraction is wrapped around it.

This means that terms involving side-effects, that are not values, can become values. Then, those values are type-applied at various points resulting in unexpected behavior: repeated side-effects. But not violation of type safety.

ML simply forbids type-abstraction of non-values in order to prevent this presumably "surprising" situation.

For the love of Pete!

Apparently this isn't as well known as I thought. See, for example, Simple Imperative Polymorphism which itself refers to this as "well known".

known ?

You've made your own assessments, now can you quantify your assessment of the ongoing cost of using unsafe languages with any confidence? Is your assessment based on your gut feel?

Good Question!

Fortunately or unfortunately :-) even when I've been in a position of sufficient authority to implement any kind of metric with respect to the development process, I either didn't know enough to, or decisions made farther up the chain precluded such a process (there's a side conversation there about disincentives to implement such metrics that isn't appropriate to this post). I wish I had a spreadsheet with these metrics—more, I wish there were even a de facto, let alone a de jure, standard for such things (and no, I'm not pining for CMM or ISO 9000. At least, I don't think I am).

What I can say with some confidence is that I've seen literally dozens of projects undertaken in which there's been what I would call a normal, healthy level of requirements discovery via implementation—I'm not advocating waterfall design or anything like that—but in which some inflection points are reached that are pretty readily apparent to anyone who has even modest exposure to alternative technologies and, more importantly, alternative computational paradigms, but those inflection points are somehow not apparent to the deciders, and entirely predictable levels of schedule, budget, and defect (which, are, of course, three ways of saying the same thing) overrun occur as a consequence of not pulling back and reassessing one's choices, preferably as early as possible. When I say "with some confidence," I mean: I can face an issue at work, go home, and rapidly code up an alternative implementation of a feature, perhaps in a different language, certainly employing a different computational paradigm, and, while not necessarily getting to "production quality" in the process, gain enough confidence in the better fit to task to feel that the project has inadvertently placed itself on a distinctly, measurably sub-optimal path. Sometimes that leads to conversations at work the next day; more often it doesn't for the attendant political reasons.

So for me, the experiences lie somewhere between "gut feel" and "quantifiable" in any sense that a consensus could be built around, even making quite conservative estimates about rewrite costs given the need to possibly learn a new language and (much more importantly, IMHO) a whole new paradigm (imagine asking a bunch of J2EE programmers to learn logic programming via Prolog in a practical timeframe, for example). This is why, I think, the cost-measurement process does? should? come down to little more than that one is fixed and one-time, while the other is ongoing. But that might indeed just tell you more about the type of pain that I prefer than anything else. :-)

And the answer ...

afaict your answer to "can you quantify your assessment of the ongoing cost of using unsafe languages with any confidence?" is - No ?

Well, No

My assessment of the ongoing cost of using unsafe languages is, of course, that it's unbounded. That's the whole point. One-time, fixed, large for a rewrite, vs. unbounded. Hence my lack of understanding of people's willingness to accept an unbounded cost vs. a fixed one.

And really, particularly when the question is "memory-safe vs. un-memory-safe," there's a whole other question as to why anyone, today, accepts the use of un-memory-safe languages for any project that isn't a device driver, but that's rather obviously another thread.

I guess its the market economy.

Like Joel Spolsky says, It doesn't matter if its better resource utilisation in the long term if you lose the market (and possibly go bankrupt) in the short term.

Of course

It's just been that my experience has been that too many projects avoid taking on a high-but-manageable short-term cost in favor of increasing quality debt over time until, essentially, a rewrite becomes necessary just to make future development possible, and the costs are much, much higher, and can even break the bank, whereas they might not have had the bullet been bitten earlier.

No one is proposing "let's not ship anything and watch the company go under because of it," but that is certainly the favorite strawman to trot out when someone points out that the bullet needs biting. :-)

In some dreamland that wastes a lot of time...

there's a whole other question as to why anyone, today, accepts the use of un-memory-safe languages for any project that isn't a device driver, but that's rather obviously another thread.

I guess we should forget Google, all operating systems, MS Office, 99% of all browsers (including the one you are using now), 99% of the form factor software, most of the HPC community, any cluster out there and so much more I cannot be bothered to list..

Therefore, I have to say I frankly find it very naive to say 'device drivers' and get away with some Joel comment while all we see there is some management utility he maintains for what a decade now.

Most of the advances out there are based on 'unsafe' languages use and development of systems with a competative advantage, not some FP or 'garbage collected is the only way' retoric. And that comment on 'bankruptcy' I am afraid been so ignored by people literally losing their market share concentrating on 'safe' languages and not retaining any competative advantage whatsoever ( Python glue Google can afford is an example of an 'unsafe' infrastructure that gives them that capability in the first place).

When you 'safe' guys get all of the software apart from device drivers on 'safe' land, let me know where to get the Cray with 50TB of RAM cheap so I can run on abstractions that simply do not scale for any large-scale infrastructure (if J2EE and .NET and JS and lack of proof that FP-only commercial markets winning are not an example of it let me know what is; besides they are all implemented in 'unsafe' dogma, hmm wonder why ).

Hence my lack of

Hence my lack of understanding of people's willingness to accept an unbounded cost vs. a fixed one.

I think the cost of all software is unbounded since bugs are hard to eliminate entirely, and requirements can change at any time necessitating yet another development cycle. The marginal cost of this ongoing development for safer languages is just much lower than unsafe languages. So the the question of whether a conversion is worth it is a matter of determining the relation between "Ongoing Marginal Cost of Unsafe Language * time" compared to "One time Cost of Safe Language Switch + Ongoing Marginal Cost of Safe Language * time".

As for the other comment about time to market, many studies imply that safer languages enable faster time to market due to decreased need for elaborate testing and quality assurance cycles; they're still needed, but less so. That interpretation is not a concrete conclusion, but my own logical extension of the study which I'm sure others here share.

Well Put

I think people think I'm talking about a binary cost analysis when I'm not, but I think you've done a much better job of articulating the fundamental point than I have.

economics matters

The business choice of rewriting vs. continuing a program often has little to do with comparing the development costs on either path.

If customers have real choice between competing programs then the vendors of those programs tend to lose: the market price of each program will quickly approach its marginal cost of production (the software vendor can pay salaries but not accumulate capital, pay dividends, etc.) (This is easy to see: try to sell your program for more than those costs, and your competitor can undercut you and still make a profit.)

Therefore, successful vendors tend to build "lock-in" of one sort or another into their products. If it would cost customers real money to switch to a different program, and if that other program might break the customer's interoperability with peers in the market, then customers don't want to switch: they'll happilly pay the larger development costs (plus a premium profit on top of that) because it costs them less than switching.

Generally, the only way to get really new technology into the marketplace is to create entirely new kinds of application.

So, why are customers so "stupid" they keep allowing themselves to get "locked in?" Because successful software businesses put them in a pincer and force them:

IT is just pure cost. The only reason to buy any at all is that, if you don't but your competitor does, they'll outcompete you. So, if you invent a new program that can give one potential customer an advantage over other potential customers -- then all those potential customers have no choice but to buy your program.

The development costs of a program -- and for that matter its technical quality -- are secondary.

-t

Your argument is valid up to

Your argument is valid up to a point: if the lock-in and interoperability pass a threshold of mediocrity, alternatives become more viable despite the cost. You can't get cheaper than open source (buy-in cost), which historically has provided a solution to lock-in, and whose solutions are becoming increasingly competitive on all fronts (features, support, etc.). Examples are OpenOffice, Firefox, Linux on the server and now desktop.

The other solution to lock-in are interoperable standards which sufficiently large customers might push for; customers like governments. Examples are ODF, PDF (though it remains to be seen whether ODF will really take off).

Both of these pressures will eventually topple a mediocre monopoly if it doesn't adapt. If the monopoly can keep its quality up and its prices reasonable, then I think they'll survive much longer; at least until the next 'revolution' in its market (like desktops did to mainframes).

that's mostly "in theory"

Thank you, that's right. But people who have lock-in have to work really hard in the wrong direction to lose it. I'm skiddish about accepting your examples: Neither OpenOffice or Firefox has broken lock-in. Linux broke lock-in to unix vendors but not obviously because of Unix's mediocrity (Linux long was and arguably still is worse, for example).

Firefox may have *forclosed* future I.E. lock-in (with a little help from the courts) and, for some markets, OpenOffice forclosed future MS Office lock-in -- but that's not the same as actually displacing I.E. or Office.

Yes, (most) legacy systems seem to eventually die from attrition, with less and less demand to add new features or keep things up to date for the latest hardware but that's demand collapse for external reasons, not because the software development projects become too expensive.

Bottom line is that pointing out in-retrospect better ways to re-code something has, almost always, somewhere between "very little" and "simply negative" market value. It doesn't matter if its FP vs. imperative or anything else: "better" is irrelevant in many software markets. ("New," on the other hand, matters more than in many markets.)

That is part of the reason I like things like interactive software development ("live programming") and rich improvisational environments (like good lisps): the actual game to win is to be able to generate interesting "new" things at a faster rate than anyone else. For that, I think a lot of FP/safer-languages/etc. will pay off.

"Better" is an internal matter to our profession. It's good to be transparent about it and explain to outsiders what we think its about -- but it's only "new" that can be sold. "Better" is just an internal tactic for getting to "new".

-t

("New," on the other hand,

("New," on the other hand, matters more than in many markets.) [...] but it's only "new" that can be sold. "Better" is just an internal tactic for getting to "new".

So instead of a gradual transition, just rewrite it entirely in the new language, tout it as new, and let them flock to you huh? ;-)

Time Value of Money

What is your discount factor?

Netscape/Mozilla

Realistically, could they have gotten there with the Netscape 4 codebase without a rewrite?

I'll stick my neck out here and say no. I worked on the Netscape 4 codebase in 1996-97, and it was pretty hellacious. As one example, there were many, many race conditions between the JavaScript thread and the rendering thread—race conditions bad enough that sufficiently advanced JavaScript programmers had to work around them.

Still, the early Mozilla project tried for a long time to avoid doing a rewrite. I believe part of the reason was the memory of the Javagator project: rewriting Navigator in Java. There was strong desire for Javagator to work, but it was finally killed. The main reason given was that Javagator was chasing Navigator's taillights: it started out behind, and would never catch up as long as Navigator kept adding features. Since Mozilla started out mostly with Netscape people, they resisted getting into a chasing-taillights scenario again.

'Memory safety' on the order

'Memory safety' on the order of bounds checking is total mistake. It is a bug, no matter that it is filtered as an 'uncaught exception'.

I mean, can you really point to some 'memory safe' commercial apps that appear more stable and usable? I cannot they are all appaling and fall over in logic bugs, something no project management experience can make up in any of the world's largest gargabe collected project of this world.. that says a lot in itself.

Dynamic typing solves nothing in my experience.

I assume the use a safe

I assume the use a safe language comments are mostly for amusement.

Not necessarily. Given safer languages tend to have greater abstraction, rewriting is not as onerous as it might at first seem. Not that that makes it pleasant of course. :-)

Long-term, rewrites using better technology will be superior, all other factors being equal; short-term incentives are harder to justify though.

Obscure languages considered possible

I just wanted to add to the overall thread that there are existence proofs that "obscure languages" can be introduced to a corporation without some "flag day" that converts the entire world, sort of in the way that Java is perceived to have done.

The example I cited in the last couple of posts here is MainSAIL, standing for "Machine Indepent SAIL," where SAIL stands for Stanford AI Lab/Language" (I'm not sure what the final L stands for). The Wikipedia should have details.

The point for fans of advance, lambda-based, languages should be that some languages have had tremendous commercial ($$$) impact even though they were never sold to the programming language communint at large as the ultimate programming tool (TM).

I expect there are other examples of this situation, and perhaps Ehud or others could ask about them here.

(I never used MAINSAIL. Wouldn't run on my VAX in 1980 or my Symbolics 3670 in 1985 and it was outside my focus. But I knew a bunch of the folks using it.)

The point is, a lot of times a language is important even if it doesn't have a large community.

--Tim

C++ does not need that to be safe

C++ can be as safe as any high-level language, if not safer, simply because one can make it as high-level as one wants (mainly by creating types for which one can define how they're constructed, destructed, copied, assigned, etc.)
One just needs to restrict himself to the right idioms and build all types as combinations of carefully crafted safe types or templates of types: the building blocks.
For example, using raw pointers and manual memory management outside of implementation details of those building blocks is out of the question to achieve necessarily safe code.

The only memory issue that isn't easily preventable is out of bounds accesses to arrays, unless you add runtime bounds-checking overhead everywhere.

_

_

Its both a feature and a

Its both a feature and a bug. Its a feature that you CAN do it. Its a BUG that you have to.

I wouldn't call it a bug...

a bug, after all, is a variance from the intent of the design (including internal inconsistencies in the software). C++ behaves, more or less, as intended--it was designed to be a "bare metal" language with extensive C compatibility; and this design constraint prevents it from being a "safe" language in the sense that all syntactically valid programs have defined (or at least predictable) behavior.

If avoidance of undefined behavior is a significant concern, then C++ is an inappropriate language choice. And greenspunning a safe language on top of C++ is seldom, if ever, a sensible option.

C++ is what it is. It does quite a few things well, and is entirely unsuitable for many others.

To put it another way...

Or to put it as we (programmers) like to: it's not a bug, it's user error.

_

_

C++ and abstraction

Different people have different wishes.
There are several frameworks which each promote one or various design policies.

One key element in the conception of C++ is "don't pay for what you don't use". That is why C++ allows, if one user wants, to be quite unsafe, by being as low-level as one needs.
Yet, one can also build abstractions on top of the language features to provide more or less safety, at a more or less important efficiency cost.
The challenge of library design being to provide beautiful and safe interfaces with minimal abstraction penalty.

As an indication of what the extents of the C++ abstraction facilities are, it is actually even possible to implement Domain-Specific Embedded Languages with C++ expressions.
Here are a few interesting applications: a DSEL for a parser generator, a DSEL to define other DSELs, a DSEL for array programming, a DSEL to define lambda expressions...

The C++ standard library, extended by the Boost libraries, promote the standard ones, which are quite safe. Much work have been done to make those libraries as beautiful and efficient as possible, and the Boost community is widely known for its highly advanced usage of C++, including metaprogramming and other tricks, and their selective formal reviews.
The most unsafe (and inelegant) thing probably is smart pointers (which still isn't really less safe than a Java reference), but there is quite some demand for these.

However, most C++ applications, mainly for historical reasons -- like because some more than 10 years old compilers choked on some advanced features -- but also because of usage of other popular and not-so-pretty frameworks, are coded rather in a mix of C and C++, with a Java-ish touch sometimes.
This has strongly hurt what people think of C++ and for some reason, even today, it seems people still see it as a language synonymous for unsafety and undefined behaviour. I believe this is quite a shame, especially coming the community of research in programming languages and software design.
People often refer to "C/C++", but those are two completely different languages and especially two completely different coding approaches.

Few people recommend coding Java-style in C++, as it is seen as one of the worst things one can do after coding C-style.
The functional style isn't very popular due to the limits in defining lambdas in C++ at the moment. (it's planned to become part of the language)

Mea Culpa

I am guilty, I suppose, for the direction this thread took, which may have been the result of my one line editorial comment: An acceptable overhead for the pleasure of using an unsafe language? You decide.

Be that as it may, what I had in mind is the type of gallows humour Marc mentioned.

To follow up on what Anton and Marc said: the situation is rather ironic, and this does not mean that it is necessarily the result of stupidity or malice. But given that, the situation still makes one wonder about the state of the art in industry. I tried to direct the thread in the direction of possible solutions - given the way things stand today - are libraries (like Samurai) better than multi-language solutions? Other relevant questions: Is it better to use safe dialects (Managed C++) or languages that have safety "built in" (e.g., Ada)? Perhaps multi-language solutions are most likely to be productive if the safe language is also a functional language?

Meta discussions are fun, but now how about addressing the technological and scientific issues?

Once again, my apologies to the thread and to the guys behind Samurai.

Agreed

I wish to hasten to add that my reaction to the Samurai project is in no way intended to reflect on its developers—as Anton said above, the reaction is about the state of the industry that makes tools such as Samurai necessary in some contexts. I also don't wish to pretend that people haven't done useful, even amazing, work in languages such as C and C++—as has also been pointed out, we're all benefitting from that work even as I type this. Rather, the point is that the need for such tools as Samurai underscores precisely and viscerally the motivation to research and develop alternative technologies that at least mitigate, and ideally eliminate, that need. A while back, someone asked Tim Sweeney what he thought of some of the static-checking tools available for, IIRC, C++ or C#; Tim responded basically along the lines that I had in mind here—that those tools are good for when you have to use C++, but wouldn't you rather have a better language, given the choice? Apologies for not being able to find that comment at the moment, and apologies to anyone who understood my comments on this thread to be about Samurai or its developers.