Tuesday, April 10, 2007

The perfect programming language

This really can't end well, because there really is none that I've discovered thus far. I'm sure lots of people in any language's band camp would beg to differ, but whatever. This is clearly going to be a post based purely on opinion, because the definition of what a perfect programming language is, is incredibly subjective. Personally, I tend to put a lot of emphasis on aesthetics of a language. Don't get me wrong, features are obviously vital, but often times it boils down to how languages look compared to their cousins (there are times when I'll argue in the feature field, usually about Java and C#).

I'm not trying to put any specific language in the spotlight, but is it just me, or do imperative languages look nicer than functional languages? Having grown up on imperative languages, maybe I'm biased; I know there are people out there that prefer some icky, icky looking languages like Scheme as well, so maybe it all depends on how we're cultured. Awhile ago, after talking with a friend from IU, I decided I would finally stop being [as] lazy and pick out a functional language to dive into.

Now, being the person that I am, I like to analyze things to the point of death (read: complain) sometimes, so we spent the night looking at different languages on Wikipedia, after talking about how he didn't "get" imperative languages and I didn't "get" functional languages (even though he actually started on C++). We looked at languages such as Haskell, Lisp, ML, and OCaml before I decided that I thought functional languages were just ugly.

I have nothing really specific to complain about either; I think they all just look really alien or messy. What I'm really wondering is, do functional languages purposely try to look as foreign as possible compared to imperative languages? After picking OCaml as the language and going through some tutorials, I noticed a lot of concepts that were present in OCaml and various other imperative languages. It seems like OCaml just [mostly] removes mutability, allows you to pass in functions to functions (which allows currying, probably the coolest feature I've seen), and full type inference. Since OCaml is impure, unlike Haskell, it does allow mutability in records (structs), references, and arrays.

It seems like a lot of the examples that are given in the OCaml tutorials could be expressed similarly in C#; however, there are still [obviously] advantages of using OCaml for functional programming.

  • OCaml is optimized as a functional language. For example, the CLR has a sub-optimal performance on performing its .tail MSIL (now apparently called CIL) instruction. A developer for Nemerle commented on writing manual tail call optimizations, which eliminated the use of .tail by using a simple jump instruction, but pointed out that mutually recursive methods are still not optimized.
  • Currying on C#, while it can work, doesn't work very well. You have to create your own classes for generating lambdas via anonymous delegates. The main article shows a type unsafe way to do it, as pointed out in comments; in order to provide type safety, you would have to add a type parameter for each argument to the Curry method, which could get cumbersome (e.g. Curry<K1, T1>, Curry<K1, T1, T2>, etc. where K1 is the return type and T1 are argument types).

On the other hand, I think C# in the general case brings a lot more to the table, concerning syntax (aside from full type inference, though it seems that C# 3.0 is moving towards type inference). I definitely like the C-family syntax a lot more (inherited bias); it feels terser than the ML-family syntax. I also think it's kind of silly how OCaml uses a semi-colon to separate statements, with double semi-colons to end blocks. Using braces feels more sensible to me, or at least something to enclose a block.

Along the same lines, I've never been a big fan of optional parentheses when it comes to calling functions, either. I first encountered this when learning Ruby and thought, "Cool!" However, after awhile, I changed my mind. It feels like optional parentheses are just for lazy people, and doesn't really increase readability; rather, it encourages laziness where applicable (I guess the space bar is a lot easier to hit than the parentheses' keys). I've never really gotten why Lisp and Scheme put their parentheses on before the function name, either. Of course, I know absolutely nothing about the Lisp family, so I'm sure there's a reason, and I'll get around to learning it. But really, what's so bad about "fun(arg1, arg2, arg3)"? In high school and onward, we're taught that functions are represented exactly like that, so I would think that using that representation would make more sense.

So why can't a language like C# take on the cooler features that are present in OCaml? Here's a [small] list:

  • Type inference - I know C# 3.0 is working towards type inference, as mentioned above; I don't think it will ever reach the point of full type inference, like OCaml. I had the opportunity to sit in on some language design meetings (and didn't understand much of it), but from what I understand, OCaml accomplishes full type inference by having literally no implicit casting at all, including promotion of numeric data types.
  • Currying - Maybe I think this is just really, really cool; I haven't programmed anything major in OCaml, so I don't know just how valuable currying is (the examples provide some interesting uses, but they're just that--examples). By looking at Sriram's article, it seems like it would be possible to have the currying functions that he wrote generated on the fly, rather than forcing the user to write it all.
  • Support for more optimal tail recursion - From what I understand, recursion and tail recursion are used very often in functional programming languages. Thus, providing a better optimization for tail recursion would get some imperative programmers thinking more functionally.

Interestingly, the comment about Nemerle brought me to their website. In their own words:

Nemerle is a high-level statically-typed programming language for the .NET platform. It offers functional, object-oriented and imperative features. It has a simple C#-like syntax and a powerful meta-programming system.

It sounds a lot like what I'm looking for, but I wonder if I'll actually like it. I'll put it on my list of languages to learn/look into; I'm still going to finish going through OCaml tutorials, at least. Unfortunately, there won't be much of that until school is out.

12 comments:

Anonymous said...

Hey Dan,
Luke pointed me towards your blog so I thought I would leave a comment. I am by no means a expert on any field it cs, let alone programming languages, but I thought I would share my two-cents.

I've recently being playing around with functional programming manily ML and a tiny bit of scheme. I have to say that what I have picked up so far I find to be extremely elegant and much cleaner that similar code in an imperative language. Althought, if you write imperative style code in a functional language, you end up with a nasty mess.

Recently there has been a lot of talk about adding functional features to imperative languages (e.g. closures in java, lambda forms in c#). I think that the preposed idea are terribly clunky and "ulgy". These languages just don't have the clean style for this type of code, hence the beauty of functional languages.

I give an example of what I mean (albeit a very trivial example that is still subjective). I don't know how well blogger comments do with code, but I'll give it a try. The example I will use is finding the max in a list.

//A common c example
int max(int[] list) {
int max = list[0];
for(int i=0; i < sizeof(list) -1; i++) {
if (list[i] > max)
max = list[i];
}
return max;
}


(* A simple ML example *)
fun max([x]) = x
| max(x::y::tail) =
if (x > y) then max(x::tail) else max(y::tail)

Why do I explictly have to loop though the list as in the c version? It seems to be very error prone and I find it less easy to understand. The functional representation is more natural and easy to show that it is working correctly. The syntax leads to a much concise representation if functional style is used.

Anyway just me thoughts on the topic.

P.S.
Why does scheme put parentheses' before the function?

Scheme bascially has two types of data, lists which are denoted by parens (1,2,3), and atoms which are not. Lists are super powerful. You probably remember abstract syntax trees from compilers. How do you represent them? Using lists. So scheme code is basically a list representation of the abstract synatax tree for the program. Pretty cool. Thats where all the parens come into play.

saiyr said...

Hi Bennett, long time no see.

Wonder if you'll see this--I don't think guest commenters can get e-mail notifications. Oh well.

Anyway, what I mean when I think functional languages look ugly relative to imperative languages is, I think the syntax is just weird-looking. Could I do a better job? Maybe not. But it feels like there should be a better way to express functional languages; maybe it's just because I'm so used to the C family.

As for bringing functional language features to imperative languages, I guess I can't really comment. I don't work with Java, aside from teaching 180 (which certainly doesn't teach closures), and it's been awhile since I've looked at C#, and am too busy to right now.

Concerning Scheme, meh. I'll be taking CS456 next semester, so I'll probably learn more about it then, and appreciate it more.

I put your blog on Google Reader, anyway. I notice you and Logan both started blogging recently as well...we're getting quite the CS blogging community around at Purdue, which could be cool.

Anonymous said...

I initially thought the syntax was ulgy . After spending some time with python and then ML, I noticed that the syntax was really refreshing. It's simple and concise and only expresses the meaning. It is definitly a personal taste as I can see how it can get awkward.

Yeah I like the little community we have going. I decided to jump on the bandwagon this weekend. I'll toss a link on my blog to your site. We should totally start a bunch of fights on each others comments. It will be a ton of fun haha.


I'm taking CS456 next semester also. It should be a fun class.

Luke said...

The blogging community is coming from the debate we had on my blog =) It's getting people interested in blogging. Good work =D

saiyr said...

I was actually thinking just now how it would be interesting if we had a central domain/server for hosting Purdue CS blogs...with in-house software, if we could handle that. Oh pipe dreams...

Anonymous said...

We could make a pretty sweet "Purdue CS Mashup". It would be nice to aggrecate all the blogs, events, and other import information on a central site. I think it would be a really nice idea for the undergrad students.

saiyr said...

Yeah, totally. Too bad I [still] hate web programming. I'm willing to at least sit in on a project if it arises though ;P In the mean time, I guess blog rolls will have to do.

Luke said...

Planet is what sites like Planet Gnome use. Who would want to run it after we graduate though?

saiyr said...

We just need to make it automated somehow...then nobody needs to run it!

Anonymous said...

Right. It it is simple and organic, then updating it won't much of a problem. Users would contribute.

Luke said...

I mean who will select the blogs for aggregation and prune the inactive/old ones when we're gone? Would we keep our blogs on it after we graduate?

saiyr said...

I'm sure you could script that--for example, every academic year, send an e-mail with a confirmation URL that keeps the blog active. Sign up could probably be automated as well...just make them confirm with a @cs.purdue.edu e-mail.

Though, I don't see why leaving old blogs on there is necessarily bad--maybe move it off to its own category?