Tech-Ed 2004: The Difficulties of Language Design

0 comments suggest edit

The best part of Tech-Ed 2004 is how Microsoft puts us developers in touch with the people who are creating the languages and tools we use. They’ve accomplished this in two ways.

First, with the Rio system (nothing to do with Duran Duran). This system allows you to search for attendees (who’ve registered in the system) by name or interests and request a meeting with them. This is the debut of the system and I don’t believe it’s being well utilized by attendees. This is great for me as most everyone I’ve wanted to talk to has been available and I’ve had a chance to meet members of the C# team such as Eric Gunnerson (PM for the C# compiler) and Anders Hejlsberg (a Distinguished Engineer at Microsoft and chief designer of Delphi and the C# language). Unfortunately Steve Ballmer was not in the system.

Second, by having Microsoft employees hang around the cabana areas (replete with comfortable couches), it’s easy to walk up to the devs who are building the next generation of tools I use (such as Anson Horton and Cyrus Najmabadi) and ask, “So whatcha got?”

If there’s one thing I’ve taken away from my various discussions about language design is that language design is hard. This may be obvious to you, but it’s not obvious to everyone. Look in any unmoderated newsgroup about programming language and you’ll hear plenty of “Java sucks!” or “C# stinks” (perhaps even more colorful than that). A lot of people carry a one language fits all mentality when in reality, each language has a purpose and target in mind.

There are three reasons that come to mind to explain the difficulty of language design:

  • Language changes shouldn’t break existing code…too much.
  • Total language purity is unattainable, but we try anyway.
  • Language design must take into consideration human behavior.

Language changes shouldn’t break existing code…too much\ This is one of the more difficult issues when designing a language. How do you update the language without breaking thousands if not millions of lines of code out in the wild. Even small changes that seemingly should cause no problems can break code. Well hopefully you have legions and legions of regression tests, but they can only go so far. This remains a difficult challenge.

Total language purity is unattainable, but we try anyway \ Let’s face it, if we’re not seeking the ideal pure perfect design, why are we in the business. It’s a natural tendency. However, a good designer realizes that total purity is unattainable. It’s a simple fact: real world pressures are factors in language design. These guys have to ship and deadlines will affect which features they keep or don’t keep. More subtly, sometimes the order in which a feature is designed affects the language design.

I asked Eric Gunnerson whether they’ve considered adding a timeout syntax to the lock statement ala Ian Griffiths’ TimedLock structure. He in turn asked me, would creating this new syntax have any more clarity than using the TimedLock structure? Ummm… I guess not since we can already do this in a clean and concise manner. Right. So why add syntax. Not only that, the TimedLock demonstrates what the C# team had in mind with the using statement. It wasn’t intended just for cleanup, but for situations just like this.

Naturally, if this were the case, why even have the lock statement, as the using statement makes it unnecessary. It turns out, the lock statement was introduced long before they introduced the using statement when creating the language. At that point it wouldn’t make sense to refactor the lock statement out of the language as it was likely used all over the place and would introduce a major breaking change (see the first reason why language design is hard). Wow, you mean real world issues such as timing will affect the purity of language design? Indeed, total purity is an illusion.

Language design must take into consideration human behavior\ Another reason language design is hard is that it must take into account human behavior. Just as we have usability testing for GUI applications, usability testing for APIs and languages are also important.

Take the “throws” statement in Java when declaring a method. This statement is followed by the type of exception (or exceptions) that the method may throw. When calling this method, the developer must catch and handle every exception declared by the throws clause. From a purity standpoint, this is beautiful. If a method could throw this exception, certainly the developer should be forced to do something about it. But now let’s examine the behavior of real developers in the field. They just want to call this method to get the work done and handle the exceptional cases later (or in a method up the call stack). However, the code won’t compile until they catch each exception. So what do they typically do? They catch(Exception e) and forget about it. No more compiler errors, but if they never return, they’ve lost a lot of valuable information about the exception.

Some will argue that we shouldn’t pander to developers with bad habits like this and teach them to do the right thing. But this isn’t necessarily a case of developer ignorance. The physics of software development states that developers naturally take the path of least resistance i.e. we’re lazy. We have to ship software. We don’t have time to do everything in the most pure fashion. The language has to work for us, not against us. We absolutely have to pander (to a degree) to lazy programmers because they’re creating the software that’s running our cars, flight control, etc… Figure out why developers don’t perform a best practice and learn how to make the best practice the path of least resistance. That should be a focus of language design. It’s not always possible. Sometimes we just have to admit that software development is hard. I certainly don’t want developers to be lazy about security. But whenever possible, I want to make writing secure code, the path of least resistance.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.



13 responses

  1. Avatar for Thomas Eyde
    Thomas Eyde June 2nd, 2004

    Not catching an exception is *not* a bad habit. Swallowing it could be, if you are not doing it for a reason.

    Perhaps there is no need to catch the exception. Why should I, if I don't have any information to add? What if I don't care? It could be an exception for the library developer, but it doesn't have to for me.

    The Kill statement in VB6, which is used to delete files, will raise an error if the file doesn't exist. I have discussed with people why this is an error. From my point of view, I just want the file to go away. If it's already gone, fine! Mission accomplished. To others, this is a technical thing: How can you delete something which is not there? It's impossible, hence it is an error.

    Add the fact that VB6 does not have a FileExists function. So to create a useful way to delete files, I need to:

    Public Sub DeleteFile(ByVal aFilename As String)

    On Error Resume Next

    Kill aFilename

    On Error Goto 0

    End Sub

    - or -

    Public Sub DeleteFile(ByVal aFilename As String)

    If Dir(aFilename) = "" Then Exit Sub

    Kill aFilename

    End Sub

    - or -

    Public Sub DeleteFile(ByVal aFilename As String)

    If FileLen(aFilename) = 0 Then Exit Sub

    Kill aFilename

    End Sub

  2. Avatar for Duncan Mackenzie
    Duncan Mackenzie June 2nd, 2004

    Thomas, the problem with your "On Error Resume Next" Kill() example is that you are ignoring all errors, not just "File Not Found"... so if your Kill fails because you have insufficient access rights, the file was in use, or any other issue, then you've just acted like it was successful without anyway to know that.

    I understand the thought process behind writing that routine in that fashion, I just think it assumes too much (that only one possible error can occur from Kill()). Based on your description of what you want to happen, you really want to catch any error then ignore FileNotFound, but otherwise raise the error onto the caller...

    The other two DeleteFile examples would produce that result I believe, so they are certainly better examples although I personally am always bothered by 'Exit' statements (they seem too much like GoTos to me) so I'd probably write;

    Public Sub DeleteFile(ByVal aFilename As String)

    If Dir(aFilename) <> "" Then

    Kill aFilename

    End If

    End Sub

  3. Avatar for Neil Mitchell
    Neil Mitchell June 2nd, 2004

    Actually the last of the DeleteFile statements is by far the most worrying. Just because FileLen returns 0 doesn't mean the file doesn't exist, it may just mean its empty.

    Also the one using Dir is not good practice either, in VB all Dir functions use the same FindFiles buffer, so calling one overwrites any previous call state. I.e. if you call Dir in an outer loop and this in the inner, then it won't work. In addition, if you have a directory instead of a file, then Kill will crash.

  4. Avatar for Clinton Pierce
    Clinton Pierce June 2nd, 2004

    Anyway, there's plenty of room for doubt. It might seem easy enough, but computer language design is just like a stroll in the park.

    Jurassic Park, that is. -Larry Wall

  5. Avatar for (Haac (Haac June 2nd, 2004

    I agree, not catching an Exception is not a bad thing. You shouldn't catch an exception if you don't know what to do with it. But swallowing an exception is very bad.

  6. Avatar for Jocelyn Coulmance
    Jocelyn Coulmance June 3rd, 2004

    Language changes shouldn't break existing code...Well, yes or:

    - obsolete features (like the lock keyword) could be flagged

    - tools could be developped to update existing source code

    - the language could be versionned:

    #version 1.1

    #version 2.0

  7. Avatar for Daniel Turini
    Daniel Turini June 4th, 2004

    Actually, being picky, the “On Error Goto 0” statement also has some side-effects: it'll clear any previous error values available. If you call the DeleteFile function in an error handler, this could be a hard to find bug to spot.

    And why am I bringing this to the language design discussion? Because a language feature should never change the program state unless explicitly asked for. It's the same mantra that we apply to our functions and methods, but I believe it is much more important on language design.

    Keywords, statements and framework components that have side-effects lends to highly unstable user code (as we all know VB is famous for).

  8. Avatar for Thomas Eyde
    Thomas Eyde June 4th, 2004

    Daniel, you are correct about On Error Goto 0. That's exactly why I use it. When I use On Error Resume Next to swallow an error, that's the thing to do. I have had even harder bugs to find, because of a missing On Error Goto 0. Errors can then leak out where they don't belong and make something else to fail.

  9. Avatar for Orion Adrian
    Orion Adrian June 7th, 2004

    One thing I've been comtemplating recently is the concept of modular language. Currently function libraries serve as vocabulary and syntax serves as grammar. While vocabulary regularly changes, syntax stays the same. Now the question becomes, why don't we take the same approach to syntax that we do with function libraries.

    The answer is we do to a limited extent now with the CLR. However given this miraculous, 2-Tiered compilation system why don't we take it a step further and introduce syntax modules. The concept would allow the introduction of new syntax in a limited space. If I need a simplified XML syntax, I just import the new syntax and within the confines of my function, I can code in a more usable fashion.

    Remember given the new concept of VM's only the IM has to transfer, compiler's don't. There's little reason to have compilers on multiple platforms. Why would you? Why not just have a platform dedicated to compilation. Can you say hardware accelerated compilers? :)

    I think it's time language designers took full advantage of the new 2-Tiered design that they've created.

    Orion Adrian

  10. Avatar for Daniel Turini
    Daniel Turini June 14th, 2004

    Thomas, I think you didn't understand me. What I've said is that On Error Goto 0 will swallow any previous and future errors. It's the previous errors part that I worry about. This causes the DeleteFile function, as written, to have a unwanted side-effect.

    The correct name for the function should be DeleteFileAndClearAllErrors()

  11. Avatar for Gary Cornell
    Gary Cornell June 15th, 2004

    Re catching exception: Java's approach is too much one way, C# is too much the other way. What is needed is a way of being told if you failed to catch an exception - whether from code you write or code you call. Not an easy task to develop this kind of compiler but worth it in the end. The developer should be allowed to say "OK I won't catch that one but should be notified via a compiler warning if they didn't!

  12. Avatar for Haacked
    Haacked June 16th, 2004

    I actually talked to some of the C# guys about this: adding static analysis to the IDE or compiler to give warnings about exceptions that can be thrown when calling a method.

    I'd like it if the intellisense gave a list of exceptions that are thrown by a method along with the method's information.

    However, be aware that when calling a virtual method, you might not know in advance what exceptions can be thrown by the class that actually implements the method (think of a plug-in architecture for example).

  13. Avatar for Justin
    Justin April 9th, 2008

    Some posts are timeless. :D C# has undergone lots of changes since 2004. These types of discussions never really end do they?