Tuesday, March 06, 2012

Bad langauge features

As a programming languages researcher I put a lot of thought in to what makes a good language, or even what would make the best lanaguge. I have a lot of strong opinions about this (there is a blog post about some of the things, but of the top of my head: optional types, virtual classes, ownership types, first class funtions and an emphasis on functional style programming are a good start), but unfortunately so does everyone else, so it seems unlikely we'll ever see the best language (i.e., the one I think is the best).

The last few days I've been thinking about what would make a really bad language. I don't mean bad for a purpose, some great languages can be really bad if used for the wrong thing (think dynamically typed languages for very large projects, C for high level programming, Javascript as the assembly language of the web). But more, which language features are inherently bad choices in every (or nearly every) situation, and which features interact really badly when put together.

Goto (or it's ridiculous cousin, comefrom) must be near to the top of the list, especially when it's combined with properly scoped features like closures. There has also been some really poor syntactic choices such as sticking a dollar sign in front of variables in Basic or the extreme overloading of symbols in C++. Also Lisp.

More generally any PL behaviour that is surprising is probably a bad choice, such as Java wildcards, non-reifed generics, nearly everything about pointers, static method overloading, some operator overloading, scoping of switch statements, the behaviour of nested classes in Java. Prioritising writability over readability is also a bad idea, although this is more debatable, and not thinking of tools, such as requiring type information to parse C++.

Any nominations for truly terrible language features?


Tom said...

I don't quite get it why you call "unreified generics" a bad idea, or even surprising from the standpoint of PL. In most programming languages that feature generics, they are unreified (e.g. SML, OCaml, Haskell), with C# being the only major exception (and maybe Scala). Furthermore, from the perspective of PL theory, unreified generics (i.e. parametric polymorphism) are the only theoretically sound/permissible generics, as they give you "theorems for free".

For example, in PL theory, there is a single function of type forall[a] a -> a which is total (doesn't raise exceptions and doesn't diverge), and that is the identity function. On the other hand, in C# you could for example access the runtime type of the parameter, use its default constructor and return a different value of the same type as the parameter!

Nick Cameron. said...

@Tom in Java you can reflect on the type at runtime and you get a different type than the runtime type. Furthermore, this is not done in a very nice way, you just get the erased version of the type with no indication of the erasure. Plus the combination of generic and non-generic types is a bit messy in order to support the erased versions.

The difference between theory and real PLs is that in the theory, the types are erased at runtime, whereas in Java (the poster child for erased generics) the types are erased at compile time.

In that sense, I think that parametric polymorphism is closer to reified generics than erased generics.

(Also, this post is kind of old, I'm not entirely sure I agree with myself anymore - you are quite right that reified generics have plenty of problems of their own).