Pinderkent

Pain and glory from the trenches of the IT world.

Perl has lost its momentum, but will be around for years to come.

Posted on Monday, January 19, 2009 at 2:33 AM.

It's not the end for Perl. It hasn't died. We won't see that happen for some time, if ever. But lately, it sure has lost its way. Andrew Binstock recently pointed this out in his article about Perl. Although it is very difficult to measure or quantify a programming language's popularity, we can get an overall sense of the "buzz" surrounding it.

Perl used to have that community "buzz". About 10 or 12 years ago, when somebody brought up Perl in a newsgroup or mailing list discussion, there was genuine excitement about what it had to offer. Mainly, that was rapid development, CPAN, powerful regular expressions, and the ability to write CGI scripts, all with little expense. We had needs, and Perl did a fantastic job of meeting them.

Times have changed. We still need to be able to develop software rapidly and with as little cost as possible. But we now have to make better use of our systems with multicore CPUs. Languages like Erlang often do this better than Perl does. Also, we need languages that allow for applications to be more easily maintained. For most sizeable, real-world development projects, Perl code can quickly become a maintenance headache.

Furthermore, the main benefits of Perl are now offered by most other mainstream languages. Python and Ruby offer very good regex support, a suitably large library, support for rapid development, a high degree of portability, and a low cost. Python, for instance, often encourages the development of more maintainable programs than Perl does.

There's very little that'll draw people specifically towards Perl. Recently, I've seen it used only because that's what the developers were most familiar with, or in numerous businesses, it's what they're stuck maintaining. Few people these days seem to choose Perl because it offers something they just can't get elsewhere.

Andrew makes some good observations in his post. One we really need to consider is how, for example, the Python community has gone out of its way to create several usable and actively-developed implementations of the language. We have the CPython implementation. There's IronPython for .NET. There's also Jython for Java. And we can't forget Stackless Python.

We just don't see that sort of activity in the Perl community. Sure, there is Rakudo. And there is also the now-stagnant Pugs implementation. But neither is really suitable for production use. Meanwhile, the different Python implementations are used successfully by many different people and companies. The Python implementations have momentum; Perl does not.

I read a number of blogs, mailing lists, newsgroups, and online forums dealing with Perl. Likewise, I talk often with people in industry who make use of Perl on a daily basis. And one thing I've noticed is that there's little excitement to be found. I think the extraordinarily long time it has taken to get anything useful in terms of Perl 6 has been extremely harmful to the Perl community. To really see a programming language prosper, it needs that raw community excitement. Python and Ruby currently have this excitement. Erlang and Haskell have it, too. Even the Common Lisp community seems more up-beat than the Perl community.

It's far too early to label Perl as "dead", or even "dying". Perl will be with us for ages. But we shouldn't deceive ourselves into thinking that it still has the same momentum that it used to, or has momentum comparable to what we see in the Python, Erlang, Ruby and Lisp communities. The action we see within the Perl community pales these days compared to what is happening in the other communities.

Permalink: http://pinderkent.phumblog.com/post/2009/01/perl_has_lost_its_momentum_but_will_be_around_for_years_to_come
Share:

Haskell is not for the programming community rank and file.

Posted on Sunday, January 18, 2009 at 2:01 AM.

Everyone following Haskell is well aware of Brian Hurt's recent article about Haskell. It raises a lot of interesting points, and is worthy of consideration. And much consideration and response there has been! I agree mostly with this response, which points out that Haskell doesn't have to appeal to all programmers.

More specifically, Haskell shouldn't be a language for everyone. Although it has academic roots, it has become a very powerful language for more practical uses. As with all powerful tools, it is best used in the hands of a seasoned professional who has devoted many years of study to its use and handling. In short, it is not a programming language for the rank and file of the development community. It is for those who have exceeded the mentality needed for more traditional or mainstream programming languages.

Of the many programmers I have worked with, I believe only a small handful of them could ever work effectively with Haskell. Part of that is just because it is so different. And this is what makes it unique and powerful. By not catering to what the typical Java or VB.NET programmer needs, Haskell has been able to capture the attention of those in the community who need better. Haskell's deep academic roots and its numerous ties to various advanced branches of mathematics have allowed it to transcend almost all other programming languages.

We shouldn't expect the typical developer to understand the terminology of Haskell. Much of it does come from the study of mathematics, something which is foreign to many developers. In a sense, it's of a more prestigious breed than many other programming languages. And we can't have it both ways. If Haskell is to appeal to a wider range of programmers, it will need to leave behind all that has made it so appealing to the select few masters who do use it effectively. This is not the thing to do to maintain the power of Haskell.

Permalink: http://pinderkent.phumblog.com/post/2009/01/haskell_is_not_for_the_programming_community_rank_and_file
Share:

JavaScript cannot be considered a functional programming language.

Posted on Sunday, February 24, 2008 at 8:05 PM.

As both JavaScript and functional programming have gained traction over the past several years, one common misunderstanding that I've seen expressed more and more often is that JavaScript is somehow a functional programming language. Such an example of this can be found in this Reddit comment, where the author says, "I don't know much about functional programming other that what I've picked up hacking javascript, ..."

One of the main traits of functional programming languages is that of referential transparency. JavaScript is obviously nowhere near as purely functional as a language like Haskell. While it is possible in JavaScript to write functions in a way that minimizes or eliminates side effects, this is often not at all practical (especially when using JavaScript for Web development). Most JavaScript code heavily concerns itself with manipulating the mutable Web browser DOM.

Support for tail recursion is another hallmark of functional programming languages. JavaScript does not offer such support, by default. It is possible to get a hackish form of tail recursion working with JavaScript, but it clearly is not comparable to what is offered by Scheme implementations, Haskell, and other truly functional languages.

Having support for first-class functions does not make a language "functional". Functional programming is a much broader philosophy, and JavaScript does not subscribe to or exhibit many of its ideas. So we should not mistakenly think that by using JavaScript, we are partaking in functional programming using a functional language.

Permalink: http://pinderkent.phumblog.com/post/2008/02/javascript_cannot_be_considered_a_functional_programming_language
Share:

A small example of the hidden dangers of dynamically typed programming languages.

Posted on Sunday, February 17, 2008 at 9:09 AM.

Several days back I wrote about how unit testing is not a substitute for static typing. A comment posted to that article by James asked for more clarification regarding what I was talking about. James wrote, "I can't recall the last time I had Ruby code break because I tried to act on an object of the "wrong" type." Well, I will give a simple example of how such problems arise, and how different languages deal with them. The languages in question will be Ruby, Python, OCaml and Haskell.

Our example program will be simple. It will consist of two functions. One will be called 'test', it will take two integers, and it will return the arithmetic sum of them. The other function will be called 'main', and it will invoke the 'test' function in two different ways, depending on the size of the array or list containing the command line arguments passed to the program. If there are over three command line arguments, the result of the 'test' function applied to the values 1 and the function 'test' is returned. Otherwise, the value of 'test' applied to values 1 and 2 is returned. Thus the program should have a return value of 3 up until the array or list storing the command line parameters has more than 3 elements.

Since James mentioned Ruby, let's start with the Ruby version of the code:

def test(a, b)
  a + b
end

def main()
  if ARGV.length > 3
    test(1, test)
  else
    test(1, 2)
  end
end

Process.exit(main())

And now we'll run it, with warnings enabled and set at the most verbose setting:

$ ruby -w -W2 t.rb; echo $?
3
$ ruby -w -W2 t.rb 0; echo $?
3
$ ruby -w -W2 t.rb 0 1; echo $?
3
$ ruby -w -W2 t.rb 0 1 2; echo $?
3
$ ruby -w -W2 t.rb 0 1 2 3; echo $?
t.rb:7:in `test': wrong number of arguments (0 for 2) (ArgumentError)
        from t.rb:7:in `main'
        from t.rb:13
1
$

As is expected from a dynamically typed language like Ruby, the error wasn't detected until runtime. Not only that, but the program ran quite successfully before then, without giving any indication that a hidden problem might arise were too many command line arguments given. Even were unit tests to be used, it is quite possible that duplicating such a scenario would be missed, and a perplexed user would be faced with an error such as the one above.

Python doesn't fare much better. Here is the code we'll use for it:

"""docstring"""
import sys

def test(first_arg, second_arg):
    """docstring"""
    return first_arg + second_arg

def main():
    """docstring"""
    if len(sys.argv) > 3:
        return test(1, test)
    else:
        return test(1, 2)

sys.exit(main())

Just to be safe, that code was run through the pylint utility, which rates the above code as "10.00/10". So an unsuspecting programmer may believe they have written high-quality Python code, when they surely have not, as we will soon see when we go to run the code:

$ python -W error t.py; echo $?
3
$ python -W error t.py 0; echo $?
3
$ python -W error t.py 0 1; echo $?
3
$ python -W error t.py 0 1 2; echo $?
Traceback (most recent call last):
  File "t.py", line 15, in ?
    sys.exit(main())
  File "t.py", line 11, in main
    return test(1, test)
  File "t.py", line 6, in test
    return first_arg + second_arg
TypeError: unsupported operand type(s) for +: 'int' and 'function'
1
$

Python behaves similarly to Ruby. The error isn't caught until runtime, and there's a good chance that unit testing would not have caught it, as well.

Let us try OCaml, a statically typed language. Compiling:

let test a b =
  a + b;;

let main _ =
  if (Array.length Sys.argv) > 3 then
    test 1 test
  else
    test 1 2;;

exit (main ());;
gives the following error:
$ ocamlopt -w A t.ml 
File "t.ml", line 6, characters 11-15:
This expression has type int -> int -> int but is here used with type int
$
The OCaml interpreter also catches the error, even without the code being executed:
$ ocaml -w A t.ml 
File "t.ml", line 6, characters 11-15:
This expression has type int -> int -> int but is here used with type int
$ 

Unlike when using Python or Ruby, the OCaml compiler and interpreter catch the error before the code begins to execute. And note that this is done without any source-level type annotations. This compile-time failure forces the programmer to deal with the error, rather than the user. Thus we end up with a more reliable program. Not only that, but the error was caught without the developer having to write even a single unit test. Now instead of writing unit tests to check if his or her code types correct, the developer can write unit tests to check the actual functionality of his or her software.

We can write a similar program using Haskell, another statically typed language, and it will also catch the error during compilation:

import System(getArgs)
import System.Exit

test :: Int -> Int -> Int
test a b = a + b

main :: IO ()
main = do
  args <- getArgs
  if (length args) > 3
    then exitWith (ExitFailure (test 1 test))
    else exitWith (ExitFailure (test 1 2))

When we go to compile the above program using GHC, we get:

$ ghc -Wall t.hs 

t.hs:11:39:
    Couldn't match expected type `Int'
           against inferred type `Int -> Int -> Int'
    In the second argument of `test', namely `test'
    In the first argument of `ExitFailure', namely `(test 1 test)'
    In the first argument of `exitWith', namely
        `(ExitFailure (test 1 test))'
$
The same error is given by ghci, the interactive REPL of GHC. As with OCaml, the problem is caught at compile time, rather than runtime. Thus the developer must actively deal with it for his or her program to just compile, let alone execute. This helps increase the program's reliability.

As we have clearly seen above, dynamically typed languages like Ruby and Python can allow for some flawed code to be written with ease. But more dangerously, it is possible for the code to run just fine, until a certain context arises upon which a runtime error occurs. Even when running the interpreter with warnings enabled, or after using a code-checking tool like pylint, such problems go completely undetected. This deception is dangerous. Some developers think that unit testing for such situations is appropriate, but there's a very good chance that such typing errors won't be detected by the unit tests, either.

It can be said that the code above is unrealistic. That's true. But the scenario it simplifies is very real. Based on my own experience, I have seen far too many problems arise with dynamically typed languages, where rarely-executed code contains a type-related error, and the execution of this code causes a runtime error (usually at a most inopportune time).

Thankfully, statically typed languages provide a very natural way of avoiding such problems at runtime, instead having them be caught at compile-time. When using languages like Haskell and OCaml, that support type inference, it's not even necessary for the developer to specify the types in the source code. So such developers get the convenience of languages like Python and Ruby, but without the inherent runtime danger of those languages, and without the inconvenience of having to write unit tests to handle checking that a proper compiler can do automatically, and more rigorously than a human could.

Permalink: http://pinderkent.phumblog.com/post/2008/02/a_small_example_of_the_hidden_dangers_of_dynamically_typed_programming_languages
Share:

Debunking some static typing myths.

Posted on Friday, February 08, 2008 at 9:22 PM.

Today I read an article about static typing, written some months back. I believe it is a very short-sighted article, and factually incorrect in several respects. However, I do encourage you to read it, so that you'll better understand the fallacies it portrays.

The first myth is that "static typing requires extra typing." Anyone who has used a language like OCaml or Standard ML knows this to be a blatantly incorrect statement. Such languages offer static typing, yet also offer type inference. So it is very rare that one must manually specify the type of a function argument, for instance. A developer will do just as little typing as when using Python or Ruby, but will get the numerous benefits of compile-time type checking.

The second myth is that when it comes to static typing, "people will want to work around it." Developers who strive to work around static typing clearly do not understand how to use it to their best advantage. Often, attempts to work around static typing are caused by a lack of preparation. Although one will never know everything about the problem domain in which he or she is developing a software solution for, even a small amount of research and preparation will allow one to use static typing to its full advantage.

That article discussed several other issues, but on further investigation it becomes clear that they have little to nothing to do with static typing, are convoluted micro-examples that have no real-world relevance, or actually are irrelevant when using languages like SML or Haskell.

There was one other paragraph that I wanted to discuss: Have I ever written dynamically typed code that has run for two hours, only to return and find that it broke because of a typeo or a wrongly-used type? Yes. But in almost every case it could have been fixed by better unit tests. Besides, those few situations pale in comparison to the man-months saved in typing, digging through verbose code, and wrestling with the type system..

This is clearly the wrong attitude to take when developing software. There is no reason for a type-related error to ever occur at runtime, especially when such checking can be performed at compile-time (ie. static typing). Furthermore, the use of unit tests to detect typing errors is sloppy and senseless. You're manually doing work that even a rudimentary compiler can do for you (and probably a lot better than you could, too). And it's just laughable to think that writing verbose unit tests somehow requires less typing than using a statically-typed language that supports type inference.

Permalink: http://pinderkent.phumblog.com/post/2008/02/debunking_some_static_typing_myths
Share:
Feeds
  • RSS 2.0 Feed
  • Atom 2.0 Feed
Tags
Archives