Ending the Era of Patronizing Language Design 40

Posted by Michael Feathers Mon, 13 Jul 2009 18:44:00 GMT

Earlier this year, I was asked to speak at a Ruby Conference. I was happy to go, but I also felt a bit out of place. I haven’t done much Ruby, but I’ve admired the language from afar. I have a number of friends who’ve left C++ and Java to jump toward Ruby and Python and for the most part, they are happy. They do great work, and they enjoy it. They are living proof that the nightmare scenarios that people imagine about dynamic languages aren’t inevitable. You can program safe, secure, high quality applications in dynamically typed languages. People do it all the time, but that’s cultural knowledge. If you are in a culture, you hear about all of the things which are normal which appear odd from outside. If you aren’t, you don’t.

This is pretty much the situation I’ve been in with Ruby, up to a point. I haven’t written a large Ruby application. I’ve tinkered around with the language and written utilities but as far as total immersion goes — no, I’ve never been totally immersed in the language but that hasn’t kept me from learning noticing interesting things at the edge. One of the striking things that I’ve noticed is that the attitude of Rubyists toward their language is a bit different. They seem to have an ethic of responsibility that I don’t see in many other language cultures.

Ethic of responsibility? What do I mean by that?

I guess I can explain it this way. In many language communities, people are very concerned with the “right way” to do things. They learn all of the warts and edges of the language and they anticipate the ways that features could be misused. Then, they starting writing advice and style guides — all the literature which tells you how to avoid problems in that language. The advice goes on and on. Much of it centers around legitimate language defects. Some languages make you work hard to use them well. Other bits of advice, though, are really extensions of culture. If a language gives you mechanisms to enforce design constraints, it doesn’t feel quite right to not use them. As an example, consider sealed and final in C# and Java. Both of those constructs do pretty much the same thing and people do go out of their way to advise people on how they should be used to protect abstractions. It’s interesting, however, that languages like Ruby, Python, and Groovy don’t have anything similar, yet people do write solid code in those languages.

Let’s leave aside, for a minute, the debate over static and dynamic typing. What I think is more important is the issue of tone. In some languages you get the sense that the language designer is telling you that some things are very dangerous, so dangerous that we should prohibit them and have tools available to prohibit misuse of those features. As a result, the entire community spends a lot of time on prescriptive advice and workarounds. And, if the language doesn’t provide all of the features needed to lock things down in the way people are accustomed to, they become irate.

I just haven’t noticed this in Ruby culture.

In Ruby, you can do nearly anything imaginable. You can change any class in the library, weave in aspect-y behavior and do absolutely insane things with meta-programming. In other words, it’s all on you. You are responsible. If something goes wrong you have only yourself to blame. You can’t blame the language designer for not adding a feature because you can do it yourself, and you can’t blame him for getting in your way because he didn’t.

So, why aren’t more people crashing and burning? I think there is a very good reason. When you can do anything, you have to become more responsible. You own your fate. And, that, I think, is a situation which promotes responsibility.

For years, in the software industry, we’ve made the assumption that some language features are just too powerful for the typical developer — too prone to misuse. C++ avoided reflection and Java/C# avoided multiple-inheritance. In each case, however, we’ve discovered that the workarounds that programmers apply when they legitimately need a missing feature are worse than what the omission was meant to solve. Blocks and closures are good immediate example. There are tens of thousands of applications in the world today which contain duplication that you can really only remove with the template method design pattern or by creating a tiny class which encapsulates the variation. If blocks or closures were available, programmers would be more likely to tackle the duplication and arrive at much less cluttered design.

Meta-programming features are yet another example. Business applications are rife with situations where you need to know the value, type, and name of a piece of data, yet we use languages in which these sorts of capabilities have to be hand-coded and over and over again. The fact that it took decades for the industry to arrive at something as useful as ActiveRecord in Rails is due primarily to the attitude that some language features are just too powerful for everyone to use.

We’ve paid a price for that attitude. Fortunately, I think we are getting past it. The newer breed of languages puts responsibility back on the developer. But, language designers do persist in this sort of reasoning — this notion that some things should not be permitted. If you want to see an example of this style of reasoning see the metaprogramming section in this blog of Bruce Eckel’s ( http://www.artima.com/weblogs/viewpost.jsp?thread=260578 ). I respect Bruce, and I realize he isn’t speaking as a language designer, but I offer that as a example of that type of reasoning — reasoning about what should be permitted in a language rather than what puts a bit more control and responsibility in the hands of programmers. Maybe decorators work in 95% of the cases where you would want to do metaprogramming in an application, but there is a price to that choice, and it isn’t just the workarounds in 5% of the cases. The additional price is a decreased sense of responsibility and ownership. I think that those human dimensions have far more impact on software than many people suspect.

The fact of the matter is this: it is possible to create a mess in every language. Language designers can’t prevent it. All they can do is determine which types of messes are possible and how hard they will be to create. But, at the moment that they make those decisions, they are far removed from the specifics of an application. Programmers aren’t. They can be responsible. Ultimately, no one else can.

Comments

Leave a response

  1. Avatar
    Scott Bellware 28 minutes later:

    Awesome! Awesome! Awesome! Three cheers for learning culture!

  2. Avatar
    Mark Haskamp about 1 hour later:

    Agreed. It’s why I miss C++ and perl (not that I’m advocating their widespread use in today’s environment) and wonder why people don’t write lisp and/or Clojure.

    In addition, I touched on the same topic a few days ago at http://code.google.com/p/markhaskamp/wiki/ProgrammersAndElectricians .

  3. Avatar
    Coda Hale about 1 hour later:

    I’d really like to believe that Ruby has a culture of responsibility, but I don’t think that’s accurate. I’ve debugged plenty of problems in Ruby applications which were caused by a third-party library taking liberties with other people’s code—turning NilClass into a black hole or using alias_method_chain without perfectly duplicating the underlying method signature. Each time it took effort to convince the offending library’s author to fix the problem, and each time I had to hot-patch the code myself until the library was updated. That’s not responsibility in the positive sense; it’s responsibility in the sense of “no one else will fix this if you don’t.”

    I think that Ruby has more of a culture of permissiveness than responsibility. Just about anything is acceptable, and rather than complaining about another library’s bad behavior you should write your own version with its own bad behavior.

    Also, Ruby does have some ability to lock a class down. You can freeze a class and its instances, which (mostly) prevents their modification. Practically speaking, no one does this because it’d be rude—just about every Ruby application is written in bald-faced defiance of the Open/Closed Principle. They’re open for modifications but closed to extension, so the mechanism of extension becomes modification.

    I also think the reason most Rubyists are OK with that is because most Rubyists work on small, time-limited projects. The twelve-year, million-LoC enterprise cathedrals of sorrow are certainly not written in Ruby, and people whose corporate culture dictates a monolithic solution don’t end up writing Ruby, except perhaps for fun. You don’t hear about the failures because no one sinks a group of 200 into a 20M LoC Ruby mega-project.

    I’ve worked on a few Ruby projects which have failed to deliver sufficient business value, and it usually boils down to a codebase in which it becomes progressively harder to reason about side-effects of modifications, even with good test coverage. This isn’t inevitable by any stretch of the imagination, but when everything is mutable one must be incredibly disciplined at all times. (And one usually isn’t.)

    All that said, I agree with you about language features. This:

    numbers.sort { _ > _ }

    is better than this:

    Collections.sort(numbers, new Comparator<Integer>() {
        @Override
        public int compare(Integer a, Integer b) {
            return 0 - a.compareTo(b);
        }
    });
    

    But the difference isn’t due to dynamic typing or mutability.

  4. Avatar
    Niclas Nilsson about 1 hour later:

    Very well put.

    This is a discussion I for some reason end up in all the time with people in all kinds of different contexts. “Isn’t that dangerous?”. The answer I give is often “Yes, it is. But so are cars, knifes and medication”. Almost anything useful can be misused and will be misused, but we seldom do it or learn fast if we do, and in software we have unmatched undo-capabilities of all sorts.

    I’m not willing to pay the price for (false) protection as long as the price is less power, especially since they are circumvented anyway. Your not supposed to change a class at runtime in Java, so to solve that, people turn to byte code weaving. Barrier broken, but at a high cost with high complexity. I much rather trust responsibility, good habits and safety nets I set up anyway to protect myself from logical mistakes.

    Liberty and responsibility goes hand in hand.

    Kind regards
    Niclas Nilsson

  5. Avatar
    Leo Bushkin about 3 hours later:
    “the language designer is telling you that some things are very dangerous, so dangerous that we should prohibit them and have tools available to prohibit misuse of those features”

    I’m sure this is true in some instances – but there is another consideration – allowing the language tools to reason about your code.

    Languages like Java, C+++, and C# come from a mindset that the compiler should make an attempt to validate the certain invariants about the code that you produce. As each of these languages evolved, some invariants were relaxed – others were strengthened.

    Take, for instance, C++ const keyword. It provides programmers to make assertions about the mutability of variables in their code – and declare methods that promise to observe the mutability requirements of const variables. This allows the compiler to verify such assertions and make sure that you are writing code that adheres to certain assertions you yourself make.

    Does support for const-ness in C++ make the language less flexible for the developer? Is it taking power away from what you can do? Perhaps. But it also provides certain guarantees about how your code will behave (under normal circumstances). Interestingly, C++ also has the ability to remove constness from an object using the const_cast<>() operation – probably to open the door for developers to shoot themselves in the foot.

    An example of a language that demonstrates some of the challenges involved with dynamic capabilities is JavaScript. Many of the things you can do in Ruby you can also do in JavaScript. You can define classes on the fly. You can weave aspects into DOM objects. You can dynamically intercept and replace method calls. You can create untyped objects and even generate JavaScript using JavaScript.

    In my experience, I have not seen an ethic of responsibility in the JavaScript I’ve seen. If anything, JavaScript encourages a lax and careless attitude towards programming. And you can ask anyone – there is an awful lot of really bad JavaScript out there. (I’m sure there is a lot of good JavaScript too … but we tend to run into the stuff that causes our browsers to barf – so it’s more obvious it’s out there).

    Dynamic languages offer a trade-off between the capabilities of the language to support compile-time assertions about code – and the capability of developers to dynamically change how their code behaves and what it does. Essentially, it trades development productivity for maintenance productivity.

    Don’t get me wrong – I like the power that capabilities like aspect oriented weaving and functional metaprogramming bring. But I wouldn’t mind seeing a better blend of compile-time assertions and dynamic capabilities. In my opinion – the quality of code you see in the Ruby community says more about the kinds of developers than anything about the language itself.

  6. Avatar
    Luca Minudel about 3 hours later:

    I’m with Coda Hale

    While I think that can be a good exercise to practice Ruby actually I have the same doubts about a spread adoption

    Can anyone suggest me reading/exercises that will help me to investigate/solve my doubts ?

  7. Avatar
    Glenn Vanderburg about 4 hours later:

    Wonderful. My response got a little long for a comment box, though: http://is.gd/1xCPq

  8. Avatar
    mark about 4 hours later:

    Great article.

    I do slightly disagree though. I believe the focus is not so much on responsibility, but more on which feature set to use, and how to write code.

    Personally I try to use a minimalistic OOP approach with ruby. If i dont need feature x, I am happy to omit it. I try to stay rather simple, because sooner or later complexity will hit me anyway.

    Ruby as language is 95% perfect for me. The 5% would however be a simpler (!) language, with a slightly different require/include/Module approach, a prototype approach and behaviour snatching to reuse object behaviour (rather than subclass). But I digress.

    One thing that I want to state, and this is the last thing I want to comment, is that I believe too many people have stopped thinking BIG. They have no vision anymore.

    People dont aim for a new kernel. People dont aim for a new Operating system. They are happy with the existing infrastructure.

    I am not. I believe a whole ecosystem can be written in a SIMPLE ELEGANT language. I am not saying that ruby is this. But I am saying that people should stop worshipping C, and instead try to get the LOGIC of what needs to be done, in a way that other humans can understand it as well, without studying C for years.

    Real hackers dont want to hear it, but I tell it bluntly – you guys are coding in fossil ancient languages.

    One day those languages will be dead.

  9. Avatar
    WTF about 6 hours later:

    What you’re essentially saying is that encapsulation is a bad thing because it prevents bad things and languages are good if they let you do bad things either accidently or by design. Perhaps then we should all be using assembly?

    Your argument is like expecting banks to become more transparent with less regulation. Maybe we should abolish the houses of government, elections and invest all power in the President. All that responsibility is sure to make them exceedingly honest and responsible.

    It seems the truly defining characteristic of the Ruby culture is detachment from reality.

  10. Avatar
    T. Powell about 6 hours later:

    A Ruby responsibility discussion … hmmm not sure I buy that. You can be lame or great in any language. In this sense I think Ruby people need to get over themselves a bit. Sure language influences things and you often see the hand of the designer or community in place but you can be an idiot in Java or Ruby or Fortran or ….

    With dynamic languages of course we see some real danger with the “idiots” redefining the language as they like,...hey wait the C preprocessor was used to do this before :-) A few have commented on this type of abuse with Ruby.

    Anyway the programming language is a small part of things. Chinese language or English language doesn’t make one more likely a better poet, no more than Ruby or C# makes one a better programmer in a deep sense. Sure in PLs a language may encourage some habits but languages don’t address the challenges of thought and construct. I’d argue in fact that Ruby muddies this a bit of this with some of its pattern and convention adoption via Rails which is wrongly attributed to the language. Is it the language or the framework (some dub culture) we really speak of?

    These days if teaching undergrad programming language theory class I often suggest the “language is the library (or API, framework, whatever)” because in many ways that is more important than anything in promoting what people often argue about more so than the inclusion of a Goto, the type system, global variables, etc.

    Anyway that’s clearly more than 2 cents. Good to raise the point, a linguistic view of programming langs and use is appropriate and not discussed enough at times.

  11. Avatar
    Keith Braithwaite about 7 hours later:

    I thought I posted this before, but apparently not. Very sucky blog engine. What’s it written in? Anyway…

    I’ve long understood one of the (more-or-less well concealed) design drivers of Java to be a desire to open the recruitment pool to those less…inclined to be careful, shall we say without courting disaster. And also without courting productivity, but no disasters was seen as more important.

    Meanwhile, the existence of books with titles like “Yet 50 More Absolutely Mandatory Properties Your C++ Program Definitely Must Exhibit If It Is To Stand Any Chance Of Working Correctly Even A Little Bit But That The Compiler Doesn’t Enforce. Be Warned. (7th Edition, fully revised and updated)” point to another failure mode.

    What lessons might there be from the history of the Lisp community? Lisp (along with Smalltalk and assembler) is about maximally non-patronising of its users. I seem to recall reading some Dick Gabriel piece that explained how Lisp programmers ended up self-censoring, deeming certain kinds of template cleverness to be in poor taste—and taking a care not to inflict those clevernesses upon their peers. They could do (and write code to do to itself) pretty much anything, but they chose not to do certain things. Can’t recall any more detail than that. Sorry.

  12. Avatar
    Ward Bell about 8 hours later:

    Seductive case … who could be against responsibility and learning? ... but years of reading actually existing code tell us both that others are not responsible and that we ourselves are often lax. How has Ruby changed our nature?

    I wrote commercial applications in APL back in the ‘70s and ‘80s. Very dynamic. Very easy to morph code written by others. You could write new APL as strings and execute them with the thorn operator. Very little interpreter support (there was no compiler) to catch or warn.

    What wonderful messes we created. It was cool that we could fix almost as fast as we wrote. But you had to be damn good to read anyone’s code (including your own).

    Did we squawk? No much. We were a small community who understood that’s just the way it was. We smugly compared ourselves to the Cobol and Fortran clods, reveling in our superiority of intellect and in our productivity. At least we had the productivity.

    Another factor: there wasn’t much you could prohibit without defeating the language altogether. Gradually, after a decade at least, there emerged one or two few thin books on style. But, really, you might as well have complained about gravity.

    Similarly, I’d be a little wary of making too much of the fact that the Ruby community isn’t consumed by style debates … yet.

    Another thought. What about languages (e.g., F#) that rely on specific syntax to declare mutability/immutability. You mess with that and the wheels come off.

  13. Avatar
    Robert about 9 hours later:

    If you want to see advice on language style in the Ruby community, try googling “monkeypatching ruby”.

  14. Avatar
    Samuel A. Falvo II about 9 hours later:

    If this were true, then as more and more people realize that personal responsibility and, perhaps more importantly, GROUP responsibility, enables creative and productive use of more expressive languages, the more they should be taking up languages like Lisp and Forth for contemporary, real-world development tasks today.

    Both Lisp and Forth, but especially the latter, permit an anything-goes coding approach. Forth, in particular, revels as THE language in which you don’t write programs, you rather create a new language in which to describe your problem, then solve your problem in said language (usually within one or two top-level definitions). Abstractions, such as strings, arrays, objects, etc., must all be implemented by hand, assuming your organization doesn’t already have its own library thereof. Lisp takes things more conservatively and encourages construction of libraries you can rely upon (which people do use!), but again, it’s strictly optional.

    Right now, I’m working to implement a graphical user interface in Forth, and I’m loving every minute of it. The application using the GUI is coming along quite nicely—implementing a 6-option radio button requires less than a handful of application lines of code. (Of course, the GUI logic behind this radio button takes substantially more code, but still less than two pages total; but, the concept at hand illustrates my point nicely.) The code is compact, easy to read, and to a limited extent even able to lay widgets out in a useful form in O(1) space and time. Bliss, if its slightly typographically unjustified output sits well enough with you.

    Still, (1) I couldn’t care what other people do with my code after I’m finished with it, because such projects have no influence on MY current project (thus, I do not feel any responsibility towards them), and (2) I know nobody else is going to give a rodent’s bum about my projects in Forth anyway, which frees me from the responsibility of interacting with other coders. Forth is a “dead language”, industrially speaking. Any effort I invest in it is academic at worst, and extremely libertarian at best.

    Forth and Lisp are sometimes called “programmer amplifiers,” precisely because of their heavy reliance on personal- and/or group-responsibility. These languages make good programmers great, and bad programmers horrific to deal with. And, it is for this very reason that both languages have fallen so far out of favor amongst corporations for industrial-scale coding.

    Ultimately, bean-counters and managers want standards—standards for how the code looks, standards for how the code behaves, and most importantly, standards for how coders work together. Since coding standards rarely can be agreed upon between companies or research institutions, let alone individual groups within a single company or academic group, the next best thing is to take the Djikstra-approach and embed your preferred standards into the code itself. C, C++, Java, Pascal, Modula-2, Oberon(-2), Sather, Eiffel, Ada, Python, C#, the multitude of (un)structured BASICs, and so many more languages all impose a kind of coding style on the programmer. No personal responsibility required! And that means you can get by with hiring folks off the street easier, because you have some semblance of understanding their solutions to problems without first undergoing expensive training sessions.

    So, yes, it is truly a cultural issue, and not a technical one. There is zero doubt in my mind that Forth, as low level as it is out of the box, can handle tasks comparable in complexity as what we’re throwing at Java today, and do so compactly, gracefully, and with ease, IF coders are willing to take the responsibility for things like settling on industry-standard abstractions (a kind of standard library for Forth if you will), industry-standard coding guidelines, and industry-standard approaches to memory management.

    Heck, we already KNOW Lisp can do the job, and in a way so superior to Java in every way imaginable it boggles the mind to wonder how Java ever got off the ground.

    However, that will simply never happen, for the simple fact that, beyond the coding styles enforced by the fuedal society found in all corporations today, no two statistically-significant group of programmers could ever agree on a common set of idioms. (FWIW, ANSI Forth is what you get when several commercial and amateur Forth developers get together to agree on such things. The result is that nobody likes the standard as it’s defined. Go figure.)

    This is why stricter languages truly exist, at the most fundamental level.

    Now, it’s also true that this can be taken too far. I love Oberon, for example, but nobody else I know would associate with me if I admitted it in their presence. THEY HATE ALL-CAPS KEYWORDS (another example of language-imposed coding styles). And, even without such keywords, they think all Wirth-ian languages are much too verbose (they are hired to WRITE code, not read it).

    So, despite the fact that Oberon beat Java to the write-once-run-anywhere punch (Juice came out slightly ahead of Java’s commercial acceptance), complete with in-browser player modules, nobody went for it at all. Java was so much more “C-like”, despite its worse garbage collector implementation and run-time performance, that it became the de-facto web applet language, cementing Java’s place in history.

    So, really, if you want to give coders a good feeling about the languages they use, it must (1) actually impose a coding style upon them, while, (2) giving them the illusion of brevity and freedom of expression. Then, and only then, will a language actually succeed in the market-place.

  15. Avatar
    kdfjkla about 12 hours later:

    You know, there are a lot of other design decisions that go into a language. It’s not just a ‘protecting users from themselves’ attitude.

    In C++ reflection and the required RTTI are expensive and difficult to incorporate. If reflection were there it would just be more fodder for the ‘C++ is slow and bloated’ people. Also would have been fun to see this interact with C.

    In Java multiple inheritance would have greatly complicated the class model and introduced ambiguities: it would not have been clean, further would have required language features to deal with the ambiguities or been severely crippled (interfaces are basically the clean crippled compromise)

  16. Avatar
    Aslam Khan about 13 hours later:

    Extremely good observations.

    Many (language designers) make the assumption that people need to be “controlled”. Indeed, newbies do prefer a rule/recipe/formula-based learning culture and languages that impose all sorts of “safety nets” around “dangerous” things serve that group well. Until, the newbie is no longer a newbie and then the constraints become impositions.

    Sadly, humans have a desire for control and power and it is easier and more convenient to assume that someone is an idiot with no choices than a person with thought and freedom. I agree that it is about responsibility, but not just responsiblity to self, but responsibility to everyone.

    Freedom should mean the same thing for everyone.

    —Aslam

  17. Avatar
    Tom about 13 hours later:

    +1 to “kdfjkla”

    C++ didn’t “avoid” reflection.

    Whilst I’m sympathetic to the sentiments of the OP, I suspect it’s mainly the case that the author likes Ruby and therefore the “Ruby way” takes a positive form.

    You could write this article about C++ and you’d be able to make the same arguments about it not “protecting” the coder – in fact, people have, I think.

  18. Avatar
    Guy Murphy about 15 hours later:

    There’s lots of things I like to do in my spare time. Some of those things are care-free and fun. Some of those things are a little risky or even downright dangerous.

    When I come to work, my boss doesn’t really want me carrying on the risky, fun, thrill-seeking behaviour I might have been engaged in at the weekend.

    When another developer has to come along after me and support my code, he really doesn’t care how much fun I had writing the code. They just care about whether or not they can understand my code, and what/how it does.

    Se unless you are a romantic lone wolf programmer, it’s not just on you. You’re not the only one carrying responsibility. It’s on your whole team.

    Fortunately the new breed of languages are including things like pre/post conditions and invariants. They’re including inline unit tests etc. They aren’t letting the developer monkey-patch every time they itch. Yes there are new hip fringe languages that allow you to play any which way they want… what languages do you hope you bank uses to manage your account? What languages do you hope your hospital uses to monitor your heart, control the nearest nuclear powerstation, manage the auto-pilot on the jet you’re on… I’m pretty sure you don’t want any of them to be using Ruby. And I’m sure you don’t want any of them developed using the kind of approach outlined in this article.

    Lastly… tests are good… unit tests are good… a compiler represents the largest chunk of automated, free unit tests that one can ever hope to aquire. It would take you man-months to develop the unit tests you get for free when you hit “compile”.

  19. Avatar
    Pattern-chaser about 15 hours later:

    Mark: “I believe a whole ecosystem can be written in a SIMPLE ELEGANT language.”

    I’ve been searching for that language for some time. It’s compilable to machine code too, so that I can use it in an embedded firmware environment.

    What was its name again? ;-)

    Pattern-chaser

    “Who cares, wins”

  20. Avatar
    Magice about 19 hours later:

    It is amazing to see how different people offer so radical different perspectives on the world. Just the other day, I read a blog on how we (programmers) have moved past the days when “Languages are designed to teach the right aptitude” and put more direction into the languages themselves (through the form of static type system, rigid syntax, etc.). And now, we have the totally opposite view.

    Frankly, I am surprised at your view on Python. In my opinion, Python out-javas Java in the department of restricting the programmers. The community don’t seem that much better: they, for some reasons, despite anything Lisp-like. Once, a Python designer bragged about how tail-call Optimization is bad (it breeds unrealistic expectation, you know), another time, how the programmers should be forbidden from thinking about implement a interpreter themselves; or, how a Python user claim that if his/her language (aka Python) does not support his/her design, s/he must be wrong, and must revert the design to conform to the language. Etc.

    Although I have never looked at Ruby (I don’t feel the need to), I think Ruby also suffers from something similar to Python. These languages offer a lot of pre-built syntax and shortcuts, but forbids their users from even thinking about extending these. Opinionated framework is another type of restriction and non-responsibility: you don’t decide how to design your application; the decision is in the framework already.

    Personally, I think your view on how the languages are freeing the programmers is not so correct. Look at C, or Lisp. Or even C+. C/C+ does not offer reflection simply because, well, they can’t! They are so low level, so close to the bare metal that offering such thing is pretty tricky. However, C is surprisingly free-spirited: the machine is yours, now go and manipulate it. Lisp is another perfect example of programmers’ responsibility: read the first line of R5RS! And Macros, dynamically type, etc. The language is designed so that the programmers can build whatever they want, be it a small interpreter or some specialized languages.

    Thus, we don’t experience freeing up! We are experiencing more restricting. However, the situation is like the US and China. China is restricted, but it publicly and loudly so, to preserve its heritage and whatnots. The US is also restricted, but stealthily and behind your back, while trying to convince you that it is provide you with utmost freedom. Similarly, Python is worse than Java and C#, but it does not proudly announce that. It just poisons your mind and creep into your life, enslaves you slowly until you become one of its users. So, beware.

  21. Avatar
    Michael Feathers about 19 hours later:

    Looking back on it, I don’t know if ‘ethic of responsibility’ is the was the best phrase for what I was talking about.

    I remember reading some psychologist a long time ago who defined ‘responsibility’ as the ability to respond. So, it is responsibility in that sense.

    What I was trying to get at was the fact that when I’m around Ruby people, I don’t notice the hand-wringing that I notice in other communities, and I think it is because, as bad as it gets, they are never boxed in. They can respond.

    Just because the responsibility goes back to the developer doesn’t mean that all developers behave responsibly, but it’s nice that they can without artificial constraints. When you are in control, you can do better work. If you are in control, you can also apply a bit more peer pressure.

  22. Avatar
    Jason Orendorff about 21 hours later:

    Well, you’re right, the argument you’re countering here (“Ruby is too much power for average programmers”) is given a lot of credence in some circles, and it’s a crummy argument. However there are good reasons to use weak languages.

    Invariants make software more reliable. Weaker languages have stronger invariants. There’s less stuff to test.

    Invariants are also useful to people who write compilers and interpreters. So in practice it takes a lot of effort (on the part of the language implementers) to make a powerful language run as fast as a weak one. As a language hacker I can attest that the more effort you put in, the harder it is for end users to predict what’s fast and what’s slow in your language.

    The worst language features sow confusion among users and smash through invariants and abstractions for little practical payoff. JavaScript’s ‘with’ statement, for example, breaks lexical scoping.

    Other features break fundamental abstractions in exchange for a large practical payoff. Threads, for example.

    It is useful to have languages at multiple points along the spectrum.

  23. Avatar
    Hans about 24 hours later:

    Magice: “In my opinion, Python out-javas Java in the department of restricting the programmers.”

    How, exactly? Python is more restrictive than Lisp, and the community can be pedantic sometimes, but I fail to see how Python-the-language restricts the programmer more than Java.

    The only thing I can think of is the significant whitespace issue. Other than that, Python doesn’t have all of the balls-and-chains that Java does. It doesn’t require the public/private/protected/static/final/etc hodgepodge, there’s no silly one-class-per-file rule, it has actual introspection, you can add/delete an object’s attributes at runtime, no checked exceptions, etc. Not to mention that it doesn’t have the static typing straightjacket. ... So what exactly does Python have that supposedly makes it restrictive, compared to Java?

  24. Avatar
    Laurent 1 day later:

    Michael,

    Reading this, I immediately though of Dijkstra’s “Go To Statement Considered Harmful”.

    Are you saying that you disagree with that?

  25. Avatar
    Wedge 1 day later:

    Excellent!

    I think it does come back to different cultures and different priorities and different ideas about responsibility. Some folks are very concerned with childproofing languages. But at best this helps only the lowest tier of developers, almost always at the cost of hamstringing the language for more advanced users, if for no other reason than that the language developers are wasting a lot of time on this rather than other features. Java is very much a blub language through and through, and it shows in the concentration on childproofing over capability or elegance. C# is somewhere in between but leaning heavily away from childproofness and more and more toward elegance, power, conciseness, etc.

    Java is the Xanax of languages, it’s got some nifty features that remove a lot of pain from, say, C++ development, but it’s so hemmed in with childproofing that trying to do anything of value in the language becomes frustrating and cumbersome very quickly.

    Languages should very much be designed to guide programmers into a “pit of success”, but attempting to design a language such that it’s impossible to write bad code is itself an impossible task. No matter how safe, how clear, how well-designed a language is there will always be a way to misuse it horribly. You can’t baby programmers as if they were children, and you can’t make the world a 100% safe place. The world is messy, complicated, and dangerous. And it takes serious tools wielded by experienced, responsible craftspeople in order to build anything of value in such a world.

    Look at any construction site, there are nail guns, hammers, saws, concrete, generators, compressed flammable gas, high ledges, etc. Imagine if all the tools of a construction worker were childproofed to such a degree that they could not injure themselves or others no matter how hard they tried. Such tools would be useless. Instead, the tools have reasonable safety measures put in place that are just enough so that responsible operators don’t have to fear for their safety yet not too much so that the tools are completely useless.

  26. Avatar
    Michael Feathers 1 day later:

    Laurent: I knew someone would bring up that point. Although, I thought their example would be pointers rather than goto. Frankly, I think goto is okay to have in a language for the odd cases when you feel you have to use it. Raw pointers in a managed memory language, on the other hand, are a harder issue. The question is really whether you can do anything useful with them.

  27. Avatar
    0ffh 1 day later:

    yup: the programmer can fix the language, but the language cannot fix the programmer =)

  28. Avatar
    0ffh 1 day later:

    Michael: Just so! If you do systems programming, for example (as I do for part of my living): There you often need some way to directly access specific memory locations – and pointers are the fastest and most convenient way to do this. When I code other stuff, I try to avoid them (unless they’re just too convenient to resist, hehe).

  29. Avatar
    Michael Feathers 2 days later:

    Offh: I wasn’t saying that I don’t see the need for pointers, but rather that they can be constrained in managed memory environments. I spend a lot of time in C and I know that you do have to touch the metal at times. The trick is separating out those cases where you need to to that from the cases where you don’t.

  30. Avatar
    Steve Py 2 days later:

    It’s human nature. If we could all just accept something as being the “best” option at a given time and focus our energy on it there would be a lot less time, money, and energy wasted in the world. One software development language, one spoken language, one standard of measurements, etc. etc. etc. (So Socialist of me, but one application development language, one web development language, one database…)

    Put the energy into improving the tool, not reinventing the wheel every time the trend points out that there may just be a “better way”.

    Heck, let’s just start small and agree on one, or at most two screw heads! Phillips vs. Slot vs. Robertson vs. Hex vs. Torque vs…. ENOUGH! At least get rid of Slot. Just re-brand the damned things as paint can openers and be done with it.

  31. Avatar
    PeterC 4 days later:

    C is a language that assumes the programmer is responsible and will “do the right thing.” However, widespread use of C (and C++ in a C-like way) is a major source of buffer overflow vulnerabilities. The evidence is that programmers are not really all that “responsible” in the sense that oversights and errors are common.

    I’ve used the dynamic languages (Python) for certain things and it is possible to rapidly build programs that work with them. However, I wonder if anyone has used a dynamic language for a really large program… such as 10 million lines of code created by 100 programmers spread of 5 different organizations. I also wonder if anyone has dared using a dynamic language in a safety critical application. Would you feel comfortable flying in a plane with Ruby code controlling the instruments?

    On the other end of the spectrum is something like SPARK Ada. SPARK is a very limited subset of Ada with many constraints in what is and is not allowed. What do you get for this? You get the ability to statically prove that your code conforms to specified pre and post conditions. Note: statically prove.

  32. Avatar
    Grubert 9 days later:

    Static type languages feel safer to the corporate IT managers. They imagine the type system will force the coders to cooperate, that the compiler will do the managing work for them.

    But a strong type system doesn’t really prevent that many bugs, it just feels like it should. Most non-trivial bugs are algorithmic. I used to think a large-developer-count project should always use a static type language, now I’m not so sure.

    I mean, if you’ve got your types well defined, how many hard-to-debug errors will result because someone passed in an Address parameter object rather then an Account parameter object? And how stupid would that programmer need to be to make such an error?

    I just finished a substantial project in Python, and now I think that OOP and design patterns are not all that essential when you’ve got first class functions, closures and dynamic typing. I can spot a Java programmer doing Python a mile away, it’s all classes! :)

  33. Avatar
    http://tradeskillsllc.blogspot.com 10 days later:

    What are the critical thinking ethics learning tools to teach kids how to avoid organized crime through the course of their lives?

    The wheel of Buddhist terms poster modular wall mural game. Doctoral dissertation for philosophy, title: The Interpenetration of Buddhist Practice and Classroom Teaching. Technocracy Ethics USA censorship Chinese military intelligence genius clones

  34. Avatar
    artsrc 14 days later:

    I am convinced.

    Who can doubt that goto use and misuse were common when Djikstra wrote, and is rare today. Culture has changed. So Djikstra can be right (then), and be wrong (now). Cost of the goto feature has declined.

    For a collection of projects there is a return:

    Return = Value – Effort

    A goto language feature has a positive or negative effect on return for a collection of projects – programs and teams. The sign of the effect on return for a feature usually depends on the collection of projects.

    One characterization of a powerful feature is one with high costs in misuse and high benefits with use.

    The combination of education to effect culture, and power in features, is an approach which is recognized to have higher return now, than in the past.

  35. Avatar
    Samuel A. Falvo II 29 days later:

    Grubert writes, “I mean, if you’ve got your types well defined, how many hard-to-debug errors will result because someone passed in an Address parameter object rather then an Account parameter object?”

    As a professional software engineer who has worked with all variety of type-safe and dynamically-typed languages, A* *LOT.

    I’ve seen this happen all-too-often, and ESPECIALLY by people who, like you, feel they don’t need type-safety in their languages.

    Indeed, those who prefer type safety in their languages are the LEAST likely to make such mistakes.

    Grubert continues, “And how stupid would that programmer need to be to make such an error?”

    Not stupid at all. Many of them have degrees one could only dream of acquiring—physics, electrical engineering, discrete or analytic maths, etc. in addition to their comp-sci or comp-eng degrees.

    But, more importantly, these people often have been in the field for decades. Like me.

    So don’t even go there.

  36. Avatar
    Roxy and Elsewhere about 1 month later:

    “The fact that it took decades for the industry to arrive at something as useful as ActiveRecord in Rails is due primarily to the attitude that some language features are just too powerful for everyone to use.”

    Although I could agree with some of the point if the article, in the right contexts, the statement above has so much wrong with it, I just can’t take the author seriously. Indeed, the irony that such an uninformed statement was made in an article about freedom and being wise enough to wield it is thicker than Oatmeal.

  37. Avatar
    PFar 2 months later:

    @”Roxy and Elsewhere”

    You stated that you don’t like the author’s statement on ActiveRecord. But you did not state * why * you don’t like his statement.

    Please enlighten the rest of us on why you take exception to his characterization.

  38. Avatar
    PFar 2 months later:

    @Michael. Brilliant blog post by the way. Well done.

  39. Avatar
    PT 3 months later:

    1. Yes I agree… what nonsense, nonsense I say!!!

    2. The mistakes made by BRILLIANT people in designing languages such as C++ were not mistakes at the time, just reflective of a point in time

    3. Shooting yourself in the foot is a good way to teach yourself not to!

    4. Programs evolve, someone else’s mess is another’s masterpiece (e.g: the Linux kernel!)

    5. Having more power at your fingertips means either you will crash and burn or learn to use it!

    6. Though after having said all of this, you wouldn’t rock climb on a cliff without a harness, not as a novice anyway!! first you need to understand the risks, then proceed accordingly.

    To Conclude: You have a point (but there is also merit in providing safety nets, as others have also mentioned!)

  40. Avatar
    loz 3 months later:

    ?????

Comments