Pinderkent

Pain and glory from the trenches of the IT world.

Functional programming JavaScript is a dead-end exercise.

Posted on Saturday, October 31, 2009 at 4:30 PM.

Yesterday a colleague forwarded me the link to Underscore.js. It's a JavaScript library that provides some functions commonly offered by functional programming language implementations.

Now, I can understand completely why JavaScript programmers would desire to use such techniques. They bring some very clear and powerful benefits, including shortened development time, fewer lines of code, greater flexibility, and improved readability. However, I do hope that JavaScript programmers using such a library don't come to think that they're actually doing functional programming.

One of the most significant areas where JavaScript fails with respect to functional programming is immutability. Current implementations have spotty support for constants, leading to various workarounds. So while it's possible to manually avoid state changes as much as is possible, it becomes difficult to do when performing browser-based JavaScript development. And it's almost always better to have the language implementation strictly enforce const-ness, rather than trying to have developers communicate this intent through all-caps variable names, for instance.

Many functional languages also offer very rich pattern matching functionality, which we just don't get with JavaScript. While some people have tried to implement pattern matching in JavaScript, it is nowhere near as clean or natural as pattern matching in Haskell or pattern matching in Erlang.

Many, but not all, functional programming languages also offer strict, static typing. There has been much debate about the pros and cons of the various typing techniques employed by various languages. In the end, however, experience shows that static typing results in higher-quality software, and static typing saves developer time. Unfortunately, JavaScript as a language, as well as its current widely-used implementations, don't lend themselves to strong, static typing.

It also doesn't help that JavaScript came mainly from the imperative and prototype-based OO world, and is only now trying to adopt features and techniques from the functional paradigm. It's often much cleaner to start with a purely functional language, and then add useful imperative features like for loops and references, as was done with Objective Caml. So the language and standard libraries have a functional feel to them, and naturally encourage the use of functional techniques, yet still allow the use of imperative features where they may prove to be the best option.

In many respects, I see trying to do functional programming in JavaScript much like doing object-oriented programming in C. While it can be done, to some extent, it never feels very natural because it lacks support that should be provided at the language level and by the implementations of said language. GObject is one of the most widely used C object systems, and as anyone who has written even a moderately sized GTK+-based system in C knows, it's not a very pleasant ordeal. Languages like Objective-C and C++ offer a much more developer-friendly experience.

So I see trying to add features and techniques from functional programming to JavaScript as generally being a pointless exercise. It may help in some cases, but ends up just masking the symptoms of a greater problem, namely that we want (and maybe even need) a true functional programming language available in all of the popular Web browsers. I've suggested Haskell in the past, but just about any functional language would be better than JavaScript.

Permalink: http://pinderkent.phumblog.com/post/2009/10/functional_programming_javascript_is_a_deadend_exercise
Share:

"Utility" or "helper" classes are a sign of a language defect.

Posted on Tuesday, October 06, 2009 at 2:03 AM.

Chris Eargle recently wrote about so-called "utility" or "helper" classes. Within his article, he states that "There should never be a Utility class which is used as a general bucket. Every method in your system means something, it belongs somewhere." I can agree with this sentiment, nor can I necessarily argue in favor of using such classes. However, I do think that a tendency for developers to create such classes indicates that there is likely an inherent flaw with the programming language that they're using.

We most often see "utility" or "helper" classes arise when using languages like Java and C#. When first developed, these languages took an OO-or-nothing approach. This isn't surprising, especially in the case of Java. When it arose during the 1990s, the software development community as a whole was generally quite enthusiastic about object-oriented programming. So one notable feature it is missing is the traditional function.

Many OO purists will decry the functions and procedures that are native to many imperative languages. They claim there is no place for standalone functions within object-oriented languages and well-designed software. But it really just comes down to a typical clash of theory versus pragmatism. When developing real-world software, sometimes a plain old function is exactly the tool that we need.

So while languages like C++, Python and even OCaml allow for both functions and objects to be used, Java and C# unfortunately do not. Developers using languages like Java and C# have to resort to abstract classes with static methods, or similar workarounds. As Chris notes in his article, this isn't an ideal situation by any means.

Given that we, as a community, now have many more years of developing software using object-oriented languages and techniques, I think it's safe to say that our tools may need some minor modifications. Languages like Java and C# are missing an essential construct, and that construct is the function. Like any tool, functions can be misused. But as we've seen, their absence can result in other hackish designs that pose several problems of their own. So perhaps we will eventually see this deficiency addressed by adding functions to such languages, so we can use them when they do prove to be the best tool for getting the job done.

Permalink: http://pinderkent.phumblog.com/post/2009/10/utility_or_helper_classes_are_a_sign_of_a_language_defect
Share:

Programming languages should not try to guess the programmer's intentions.

Posted on Sunday, May 24, 2009 at 12:39 AM.

A common trait among some of the poorer-quality programming languages, namely PHP and JavaScript, is their use of weak typing. While some developers are convinced that it's acceptable, it's generally a bad idea to have a programming language essentially guess at what the programmer means.

Recently, I saw an article describing some problems within a PHP script caused by automatic conversion. Frankly, these kinds of issues should just not exist. Strong, static typing is clearly a better approach. Although it puts slightly more of a burden on the programmer, the act of manually specifying type conversions leads to higher-quality software, especially if any errors are caught at compile-time, rather than run-time.

JavaScript is another language that employs weak, dynamic typing. I recently saw another article that gives some good examples (under the "2. Plus operator overloading" section) of how this behavior may result in unexpected results, especially for novice developers. But even seasoned professionals still make mistakes, and such conversions should at least be flagged with warnings, if not outright disallowed.

Even though we often deal with fuzzy and incomplete specifications when developing software, we shouldn't bring such uncertainty and guesswork to our communication with the computer itself. We should specify exactly what we mean, even if it does take slightly more typing. Then again, when using languages like Haskell and OCaml, we can clearly see how strong, static typing and type inference can be implemented without overly burdening programmers. Any type conversions that must be manually specified help to force the programmers to think about what they're doing, which in some cases may be quite wrong, especially if a type conversion is necessary.

For the sake of trying to achieve even a moderately reasonable level of quality in our software, especially when programming for a hostile environment like the Internet, we shouldn't resort to languages like JavaScript and PHP that allow for type-related errors to occur so easily. It's even worse when they try to make automatic conversions that result in unexpected behavior. That's just plain unacceptable.

Permalink: http://pinderkent.phumblog.com/post/2009/05/programming_languages_should_not_try_to_guess_the_programmers_intentions
Share:

Do programming languages for code embedded in Web pages need to be dynamic?

Posted on Saturday, April 11, 2009 at 9:41 PM.

Towards the end of his "On programming language design" article, which does a very good job of pointing out the benefits and necessity of statically-typed and statically-checked programming languages, Andrej Bauer writes the following:

There are situations in which a statically checked language is better, for example if you're writing a program that will control a laser during eye surgery. But there are also situations in which maximum flexibility is required of a program, for example programs that are embedded in web pages. The web as we know it would not exist if every javascript error caused the browser to reject the entire web page (try finding a page on a major web site that does not have any javascript errors).

This opens the door for some interesting speculation. One thing to consider is whether successful languages meant for embedding within Web pages need to be dynamic. Another thing to consider is how the current situation would differ if browser-based languages were more static than JavaScript is.

Anyone who has worked extensively with languages like Haskell, SML, and OCaml will be aware that a more static-oriented mindset itself typically doesn't negatively limit the development of an application. It may make certain software development techniques more difficult, but usually this is just a case of those techniques being a bad idea in the first place, regardless of the language being used.

A good example of such functionality is JavaScript's eval function, which allows for a string to be executed at runtime as if it were code. It's the sort of functionality that's abused far more than it's ever used appropriately. Some of the JavaScript community's more enlightened individuals have recognized this. Douglas Crockford, for instance, appropriately describes eval as "the most misued feature of JavaScript." His advice to "avoid it" makes perfect sense. Wladimir Palant has also written an article about eval. His article is very practical, giving five real-world abuses of eval. In the end, he concludes that there really aren't that many valid reasons for using eval.

So just because a language allows for certain dynamic techniques to be employed, often they're not what is wanted. The natural way of obtaining the same outcomes using static languages like Haskell, Standard ML and OCaml may require slightly more work on the part of the developer, but the end result is typically much safer and much more reliable than the dynamic language's equivalent. In short, using a static language for code embedded within Web pages shouldn't prevent any legitimate and sensible programming activity from being performed.

There's nothing about static languages that would prevent them from being embedded, in source form, into a Web page. Hugs and GHCi are good examples of how Haskell, for instance, can be be used in a manner similar to that of many interpreted scripting languages.

We'll have to resort more to speculation when considering how things would be different today and tomorrow were static languages, rather than JavaScript, more widely available for embedding within Web pages. One of the most significant changes, I think, would be the performance of such code. Until this past year, the performance of most JavaScript implementations can best be described as horrible. Even then, it took the initiative and involvement of Google with their Chrome Web browser, and Apple with Safari, before we even began to see reasonable performance.

Much of JavaScript's performance problems arise from its dynamic nature. This inherently makes the development of optimizing implementations difficult. Of course, this isn't a problem associated just with JavaScript. Other dynamic languages, like Perl, Python, and especially Ruby offer poor performance, as well. Being an embedded, interpreted language doesn't help JavaScript, either. Static languages, on the other hand, allow for implementations to safely perform a greater amount of analysis and optimization, which can lead to better performance than we'd see out of dynamic languages for the same task.

Greater reliability and increased security are other areas where static languages tend to excel. Andrej's article mentions a number of the common language features that help with this. In essence, static languages help eliminate techniques that are known to typically lead to flaws, and they usually provide greater syntax and type checking to catch human errors more readily. The developer mindset one develops by using such languages also inherently helps encourage the development of better software.

Many have touted JavaScript's accessibility as a key to it being widely used. That is indisputable, of course. Its shortcomings as a language have made it widely usable by people who probably shouldn't be using it. Many Web developers who can do a fine job designing a page that looks good have gotten away with using it (along with PHP, another poor language) to perform programming tasks with which they don't have as much experience and knowledge. These are the sort of users who typically create code rife with security holes and other problems. So aside from the natural ability of static languages to encourage higher-quality applications, making programming slightly more difficult may bring additional benefits, by weeding out users who probably shouldn't be performing programming-related tasks.

It's unlikely that we'll see a static language like Haskell, or one of the languages from the ML family, available within all popular browsers any time soon. Even today, Web developers spend an inordinate amount of time dealing with cross-browser issues when writing JavaScript code. Instead, we'll likely see the current trends continue, with JavaScript still having relatively poor performance even after much work funded by powerful industry backers, with JavaScript still being used to develop poor-quality and insecure software, often by developers who have little real programming knowledge or background.

Permalink: http://pinderkent.phumblog.com/post/2009/04/do_programming_languages_for_code_embedded_in_web_pages_need_to_be_dynamic
Share:

Static typing is a necessity for quality software.

Posted on Wednesday, April 08, 2009 at 10:55 AM.

When unit testing is used in conjunction with a dynamic programming language, it's typical to see many unit tests whose sole purpose is to test for errors that a language employing static typing would have caught at compile time. Justin Etheredge recently discussed this, and it's something that I have written about in the past in my "Unit testing is not a substitute for static typing" article.

This isn't necessarily an argument about whether statically-typed or dynamically-typed languages are better. There is no single answer to that argument, as what's best really depends very much on the situation at hand. When we want to write software really quickly and are willing to accept a low degree of quality, then dynamic languages are quite suitable. A good example of this is a system administrator writing a short Perl script to scan through certain log files, for instance. Chances are a reasonably competent administrator will be able to write such a script with no significant errors. But once we start moving beyond that scale, we need the help of a compiler, and often static typing.

While proponents of dynamic languages are often quick to point out that such languages allow for more rapid development, they often neglect to see the greater picture. Initially writing code is a very small portion of the lifetime of a typical software product. This is especially true as the software systems get larger and more complex. Significantly more time is often spent testing the software initially, testing for regressions as changes are made to other parts of the system, and debugging user-discovered problems after it has been deployed.

Automated unit tests have become a popular way of reducing this post-initial-development burden. While using a statically-typed (and often, but not always, compiled) language, such tests are usually about testing the actual functionality of the software. More trivial checks, such as whether we're assigning textual strings to variables we expect to be purely numeric, are left to the compiler to perform. And this makes perfect sense; developers shouldn't be wasting their time writing unit tests to essentially perform checks that a compiler could do far more thoroughly and efficiently.

There have been numerous times now when I've had to work with larger software systems developed using languages like Ruby or Python. Thankfully, there have been extensive unit test suites available in the majority of those cases. But the value of those test suites is diminished by the numerous tests that would be rendered immediately unnecessary by strong, static typing. Whatever time the developers might have saved by using the dynamic languages ended up being used instead to write trivial unit tests.

This isn't to suggest that we shouldn't use dynamic languages. Like I mentioned earlier, they're often practical and suitable for very small scripts and applications. But when we're writing serious software that's expected to perform reliably, it's in everyone's best interest to use a more static language. That way the developers don't have to waste their time writing unit tests that essentially test for typos and minor programming mistakes, rather than testing the functionality of the software. Likewise, the testers don't have to file numerous bug reports about the inevitable mistakes that the programmers made, but which were missed by their unit tests. And most importantly, the end-users don't have to fall victim to typing errors that both the developers and the testers missed. In short, it just makes more sense to use static languages.

Permalink: http://pinderkent.phumblog.com/post/2009/04/static_typing_is_a_necessity_for_quality_software
Share:
Feeds
  • RSS 2.0 Feed
  • Atom 2.0 Feed
Tags
Archives