January 2018

S M T W T F S
  123456
78910111213
14151617181920
21222324252627
28293031   

Style Credit

Expand Cut Tags

No cut tags
pozorvlak: (Default)
Thursday, March 6th, 2008 12:16 pm
There's a meme out there that Java is the new COBOL. The rationale is summarised nicely in the first couple of paragraphs of this Wiki page, before they ramble off into a rant about how Smalltalk should have taken over the world:
Is Java the new Cobol? A good argument can be made that yes, it is. Considering the billions of lines of Cobol code that have been (or still are) in production; that observation should in no way be considered a slur. Java has succeeded in the marketplace (partially) because it is a language of its time; not one behind the times - or ahead of them.

Java is the new COBOL because it's becoming the new de facto standard for enterprise applications. Like COBOL, it's a good language for its time, but there are better ones. Like COBOL, it's bloated with features. Like COBOL, it's being used beyond its original view.
This comparison is appealing, but false. As I've been saying for years, Java is the new Ada.

Consider:
Java Ada is a compiled, structured, statically typed, imperative, and object-oriented high-level computer programming language. It was originally designed by a small team led by James Gosling Jean Ichbiah. Java Ada emphasises "programming in the large", portability, multiprogramming using threads the rendezvous mechanism, and, in particular, the development of reliable software, which is aided by a combination of strong static typing and runtime checks inserted by the compiler. The restrictions of static typing are partially alleviated by the ability to create "generic" types and subroutines. Java Ada is particularly intended for development of software for embedded systems and hard real-time environments. The familiar C++ Pascal-like syntax aids new learners, and a large standard library provides much common functionality as standard.
It's instructive to ask why Java took off when Ada largely didn't. There's no single answer, but I think the following factors explain a lot:
  • More programmers were familiar with C syntax than Pascal syntax (or associated Pascal syntax with limited Pascal environments they'd used at school).
  • Java came from Sun, a company with programmer cred, and had the names of famous and respected hackers (James Gosling, Guy Steele) attached to it. Influence leaders in the hacker community took it seriously. Ada came from the DoD and Honeywell, and some guy that nobody'd ever heard of.
  • Sun marketed the hell out of Java, and did so to the right people.
  • Early Ada compilers were very poor, and by the time good compilers were available, the language had acquired a bad reputation.
  • Mostly, though, I think it was timing. Ada was developed just before OOP went mainstream, so missed out on that bandwagon. By the time Java came along, OOP was well-established, and the masses were ready for a language in which OOP was built-in rather than bolted on. They were also familiar with the horrible complexity of C++, and were ready for something like C++ but less painful. "Reliable software" was a less effective rallying call back in 1980, unless you were developing control systems for aircraft (Ada's original niche). Ada was ahead of its time in many ways; Java, as the Wiki poster said above, was very much of its time.
There are some other suggestions here, from someone who appears to have been around at the time and is thus more reliable than me.

The new COBOL is, of course, Visual Basic.
pozorvlak: (Default)
Tuesday, March 4th, 2008 11:43 am
My post about design patterns and if-statements in Smalltalk yesterday got a very pleasing reaction, garnering some informative comments from knowledgeable people and making the front page of programming.reddit. I guess I should have checked my facts on Smalltalk semantics more carefully before clicking "Post" :-) One comment that particularly interested me was this one (sadly anonymous), which shows a rather cute trick for using Smalltalk-style keyword methods in Haskell:
data Then = Then
data Else = Else

if' :: Bool -> Then -> a -> Else -> a -> a
if' True Then t Else f = t
if' False Then t Else f = f
Now that's pretty cool, and could even be useful for DSL implementation1. But there's a problem. See the repeated code?
data Then = Then
data Else = Else
Here, let me show it to you the way it looks to me:
data Then = Then
data Else = Else
Literally half the elements that aren't pure syntax on those lines are repeated. What I'd like to do is define a keyword function, and then just write
keyword Then
keyword Else
Or, better,
keywords Then Else
Not a big deal, you might think, but what if you were writing a whole EDSL with many keywords? Or many different EDSLs? And it's not just the repetition: by defining a keywords function, I'd move the code up an abstraction level, making my intent clearer. We could of course write
data Keywords = Then | Else
but then we lose the benefit of compile-time syntax checking of our EDSL. Well, I guess our pseudo-keywords are syntactic sugar anyway, so it doesn't really matter. But still.

A few days ago, someone asked me for an example of code that's repetitive in Haskell but wouldn't be in Perl, and here's one. In Perl, and probably in Python, I could write a keywords function. It would be ugly, and would involve hairy symbol-table hacking or calls to eval, but the user wouldn't need to know that and I'd only need to write it once (never mind the fact that the "pseudo-keyworded functions" pattern wouldn't actually make any sense in Perl...). In Lisp or Ruby, I wouldn't need to write it at all, because I could use symbols instead. But perhaps this kind of thing (and other, more egregious examples) are just the price we pay for Haskell's type system, and are more than balanced out by greater opportunities for concision and abstraction elsewhere?

Nah, bollocks to that. We can do better.

Template Haskell to the rescue! )

The final version of Main.hs is here, and the final version of Keyword.hs is here. Not entirely straightforward, but we pretty much got there in the end. Would it be worth posting these code samples to the TH wiki, and perhaps linking here? Anyway, it's nice to have finally got this simple stuff to work: hopefully I'll be able to get some more difficult things to work soon, and this should reduce the amount of frustration and needlessly duplicated code in my Haskell programming experience.

1 Did you know you can do this in (plain) TeX, too?
\def\fred #1 barney #2 betty{#1#2}

\fred Hello there, barney Wilma betty !
produces "Hello there, Wilma!".
pozorvlak: (gasmask)
Monday, March 3rd, 2008 01:32 pm
I did warn you...

A while back, [livejournal.com profile] markdominus wrote an article about the Design Patterns movement, in which he claimed that design patterns are basically signs of weaknesses in programming languages; if a language forces you to implement the same pattern of code over and over in different programs, that's a sign that your language is insufficiently high-level with respect to problems that your users actually encounter, so language designers should focus on patterns as places where their languages could be improved. This prompted some reaction in the tech blogosphere, including this response from Ralph Johnson, one of the authors of the original Design Patterns book. Dominus responded here, correcting some of Johnson's misunderstandings and commenting further; in fact, though, they're mostly in agreement (and I'm pretty much in agreement with them both, FWIW).

Everyone up to speed? Good.

Something Dominus didn't seem to get was Johnson's distinction between things that are in the language and things that are in the library. Johnson seems to think that there's a three-tier hierarchy:

1) Language features
2) Library code (available to every application)
3) User code (must be written for each application).

He claims that it can be a good tradeoff to leave something as a pattern, because the alternative might be to overcomplicate the standard library or, even worse, the language itself - he seems to have visions of a language with decorator, abstractFactory etc. as keywords. Dominus largely refutes this claim in his response. But more interestingly, Dominus thinks that the distinction between 1 and 2 is basically artificial - is C's printf (or Haskell's standard prelude) part of the language or the library? It might matter to language implementers, but to the average programmer, the distinction's pretty unimportant. Now, this is a good point, but I think I can see what Johnson's getting at. Remember that Johnson's a Smalltalker. Let's consider (finally) how Smalltalk handles if-statements, which in most languages are built-in syntactic elements of the language.

In Smalltalk, booleans (ie, True or False) are objects: specifically, they're instantiations of the abstract base class Boolean, or rather of its two subclasses True and False. So every boolean has type True or False, and no actual member data. Bool has two virtual functions, ifTrue: and ifFalse:, which take as their argument a block of code. Both True and False override these functions; True's version of ifTrue: calls the code it's passed, and False's version does nothing (and vice-versa for ifFalse:). Here's an example:
a < b
  ifTrue: [^'a is less than b']
  ifFalse: [^'a is greater than or equal to b']
Those things in square brackets are essentially anonymous functions, by the way. Except they're objects, because everything is an object in Smalltalk. Now, what's happening there is that we call a's "<" method, with argument b; this returns a boolean. We call its ifTrue: and ifFalse: methods, passing as arguments the code we want executed in either case. The effect is the same as that of the Ruby code
if a < b then
  puts "a is less than b"
else
  puts "a is greater than or equal to b"
end
but what other languages do with special syntax, Smalltalk does as a special case of method-dispatch. (Code samples from here). This completely blew me away when someone ([livejournal.com profile] pdcawley?) first told me about it. Haskell does something similar, of course. [Edit: no it doesn't - see comments. But it could. I've also got some details of the Smalltalk wrong.]

Now, back to Johnson. Smalltalk's designers had three choices: bake special syntax for if-statements into the language, implement it in Smalltalk library code in terms of more general concepts that were part of the language, or force the programmer to do the work him/herself every time (using, I dunno, computed gotos or something). They made the unusual choice to go for the second option. While this doesn't matter if all you want are if-statements, it affects the language in other ways: the powerful abstraction mechanism needed to do this is available to the user to define new features.

This, I think, is the real distinction between "language" and "library": if the feature in question could have been implemented by your users using a combination of other features, it might as well be part of the library. Smalltalk's if-statements pass this test, as do (say) Lisp's looping constructs. Haskell's monads fail, because of do-notation: if a Haskell programmer wanted to add similar syntax for (say) comonads, would they be able to? I don't think so, and so it follows that monads are actually baked into the language. Several of Perl's built-in functions do things that user functions wouldn't be able to do, and thus should count as part of the language, even though they feel like part of a library.

So here's where it applies to design patterns: if your programmers find themselves having to implement essentially the same code over and over again, it's because you don't provide powerful enough abstraction mechanisms for programmers to write library modules that would do the job for them. Programmers are (rightly) lazy, and don't do work many times if they can do it once and then use that solution over and over again. So the fact that it's a design pattern means that it can't be in the library, and your language needs fixing: either by special-casing extra language features in or (preferably) by making your abstraction features more powerful, so the necessary library code can be written.
pozorvlak: (polar bear)
Tuesday, February 12th, 2008 10:26 am
I'm going to make what should be an uncontroversial statement: if you don't understand and use monads, you are at best a quarter of a Haskell programmer. A corollary of this is that, since using monad transformers is the only (or at least the approved) way to use two or more monads together, if you don't understand and use monad transformers you are at best half a Haskell programmer.

[Another corollary is that I am, at best, about an eighth of a Haskell programmer: though I understand monads well on a theoretical level, I invariably emerge defeated from any attempt to bend them to my will.]

But we'll come back to that later.

Something I've been thinking about for a while is this whole business of designing languages to make programs shorter. )

1 There really ought to be a word that means "would never use a twopenny word when a half-crown word would do", but I can't think of one. English grads? Edit: sesquipedalian! Of course! Thanks, [livejournal.com profile] fanf! (Originally, I used "prolix")
2 I actually came up with this list by thinking about languages whose users were the most passionate. But they're also extremely concise, which I think is a large part of the reason for the passion. If I were focusing purely on concision, I should probably consider Forth, but I don't know enough about it.
3 J has "boxed arrays" too, which are something like two-dimensional s-expressions, but let's leave those aside for now.
4 You might want to raise this objection against Smalltalk, too: objects are members of classes, which are something like types. Now, I've hardly used Smalltalk, so I'm probably talking out of my elbow, but: since everything is an object, and the language has powerful reflection features and duck typing, we can in fact write generic operators that work for objects of many or all classes. But maybe I'm entirely wrong about Smalltalk programming: in which case, please delete all references to the language from my argument.
5 Do you find yourself wanting to go out and strangle small fluffy animals every time you have to type out an instance declaration that would be entirely unnecessary in a duck-typed language? I do. Particularly when it doesn't work and spits out some ludicrous error message at me, telling me that I've encountered another stupid corner case of the typeclass system.
6 I learned to my surprise the other day that I'm a member of the Geometry and Topology research group, and not the algebra research group as I'd always assumed - apparently universal algebra is now considered a branch of geometry!