No More Jargon


The coalescence of thoughts with regards to technical subject matters in the areas of software design and computer languages.

Twitter:

    Friday, March 31, 2006

    The Language of 2016? Part 1: Simple Semantics

    "I conclude that there are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies." -- C. A. R. Hoare
    It's often said that since all languages are Turing complete, you can do the same thing in any of them.

    This is a dirty, dirty lie (no offense to Turing).

    What you can do is get the same output from two programs written in different languages given the same input. Internally, depending on what the individual semantic models of the language are and what the desired conversion from input to output is, you will be doing very different things. If you attempted to do them both with the same methodology, you would have to implement the semantics missing from the other language in the language you were attempting to fit the methodology to.

    Because at some point, you will find a problem that is exponentially easier in one set of semantics than the one supported by the language you're using, making it easy to modify the semantics of that language is critical. What's the best way to do this? Having a simple underlying semantics to the language. This will be absolutely critical to the Language of 2016.

    Smalltalk and the Lisp's both practice this. Since I haven't used Smalltalk, I will refer to it via the proxy of Ruby (which shares similar semantics).

    In Ruby, since everything is an object and all actions happen because of messages, I can model and manipulate new behavior easily. Changing the behavior of an object is as simple as creating a new function and slapping it into the object at the needed point. Likewise, Classes being objects allows me to talk to them and tell them how they should start acting. Since even the environment of execution is an object, I can capture that and use it to my nefarious purposes.

    Lisp goes in a different, but possibly even more powerful direction. The readtime Macros allow programmers to turn semantics into syntactic abstractions with nigh unlimited power. This power is enabled because every statement in Lisp is an S-Expression: that is, the execution of some code. Because all Lisp Code is in S-Expressions and all Data likewise (after all the Data has to be stated in some form), Macros enable the manipulation of code exactly like data. Since I have little real experience with Lisp, I hesitate to venture further into a discussion about the Macro system.

    Though I haven't read them yet, the two books in this area that I have heard as most relevant are The Art of the Metaobject Protocol and On Lisp.

    This is an article in my series of entries entitled "The Language of 2016?"

    The Language of 2016?

    It's been estimated by a few people that popular industry languages have a lifetime of about 10 years.

    It's been cited that in the 70's FORTRAN was what you needed, in the 80's C++, in the 90's Java, and that right now we're on the precipice of a new language taking over the "Enterprise" or whatever the hell you want to call it.

    To be honest? I don't care about that. I feel like I'm on a course to knowing the sorts of things that are going to be necessary to be a succesful programmer in the next 10 years. By no means am I there yet, but I feel comfortable with where I'm headed right now.

    What I want to start getting answers to is where I and everyone else will be going in a decade, give or take.

    This entry is inspired by the "World's Most Maintainable Programming Language" article series written by chromatic.

    Because of its Length, I'm breaking this down into a number of entries for easy consumption:

    Part 1: Simple Semantics
    Part 2: Common Datastructures and Manipulations Thereon
    Incomplete Entries:
    Part 3: Trivializing Common Tasks
    Part 4: Distributed Computational Models
    Part 5: Optimization Over Usage
    Part 6: Declarational Co-Language
    Part 7: Community

    Tuesday, March 28, 2006

    When the Walls are Closing In

    For my Distributed Computing class, I'm writing an Actor Computation framework in Ruby. I've got a little code written and the rudimentary architecture laid out.

    So far, I've had three, "Oh Shit... is this gonna be a huge problem?" moments.

    The first came when I was trying to figure out how a computation on one machine was going to be delivered back to the place where it was requested. I knew that this was going to be something that I'd need to solve in the course of writing the framework, but I hadn't yet worked out a theoretical solution. I eventually figured out what I needed to do when I was in the shower (a classic "Eureka" moment to be sure).

    The second came when I was trying to determine how an Actor would migrate from one machine to another without losing any messages sent to it. I had a little help with this problem because my Professor has written a slightly similar system that implements a solution to this and he pointed me in the right direction.

    The third came over the course of the past few days when I realized that I had failed to figure out how short lived actors would be garbage collected (that is, actors who, once no one holds references to them and who have exhausted their message list, are deallocated). I began poking around the Remote Method Invocation library I'm using and looking for discussions on Distributed Reference Counting. The walls started closing in. It looked like I was going to have to write something that would be brutish and nasty and abusive of Ruby's meta-object model.

    I didn't like it, but I became resolved to my fate. I'd just have to find the tests for the RMI library to make sure I wasn't breaking anything. Oh well, life sucks and then you die.

    Today, I was thinking about the probelm again. Then I remembered something: The objects those distributed references point to are mobile! The RMI library's distributed references are static! I couldn't proceed with my nasty, brutish solution anyhow.

    Oh noes.

    Not 20 seconds later I thought of a solution that was immensely more satisfying and would be much more consistent with the rest of my system if not necessarily easier to program.

    I tell you this, not because I want you to be impressed with how fast I think my way out of problems and into solutions, but because of how I came to my solution: Another Level of Indirection. My problem was because I was thinking to close to the tool I was using, I was trying to come up with the answer to a problem that was bound by the constraints of the wrong domain. I should've known better whilst I was fretting over what my library does to just go up a level and not worry so much.

    If Lazines, Impatience, and Hubris are the three greatest traits of a Programmer, Indirection is surely his greatest tool.

    Saturday, March 25, 2006

    Reason 20X6 Why Java Sucks: Discourages Laziness

    (A pronunciation guide for 20X6, for the uninformed).

    Right, so I was writing a few test cases for my Graphical User Interfaces assignment and I banged my head against Java AGAIN (quite nautrally, I might add, I wasn't trying to be dynamic, it just happened).

    The first moment occurred when I was looking through the JUnit Assertions for something that would let me test whether an exception was thrown or not. I didn't see anything right off the bat, so I chalked it up to laziness and went to write one myself. I typed in the method name when I realized "Ahhhh yes, no closures... oh and no easy way to invoke a method dynamically. Poop." Oh well.

    The next time was when I saw that I'd be writing a couple of assertions repeatedly with minor variations depending upon the attribute I was vetting. No reason to repeat myself, right? Wrong. Once again, the lack of easy dynamic method invocation bites my ass (it also bites ass).

    Heck, for that matter, if Java had decent introspection facilities, I could've probablly just written one special assertion and done all the attribute tests in one fell helper method.

    Now, if you're reading this, please note that I'm not saying these things are impossible, just that the path of least resistance is to not use them, but rather write more, repetitive code.

    When a language enables laziness to create better code, better code WILL be created. Every Programmer wants to do the right thing, they just don't want to work at it, and there's no good reason that they should have to.

    Wednesday, March 22, 2006

    UML Doesn't Know When to Stop

    I was looking at a UML sequence diagram today (one that had an internal state diagram inside one of the objects), when it dawned on me precisely what bothers me about UML: There's no easy way of knowing when to stop.

    I was looking at this diagram (beautifully rendered by the way) and I thought to myself: "What is the inherent advantage of putting this state notation in a document over into the source code?" On the surface, for the particular example, none, of course. It was a trivial sample meant to show how you would diagram such a thing in UML. Here's the question that goes unanswered though: When then, if not now?

    When would it be appropriate for a designer to put that state diagram inside of his sequence diagram, or as a seperate diagram altogether or any of the other hojillion diagram types (which is another barrel of monkeys, but not central here) that UML provides? Well, none of the tutorials I've seen talk about it, none of the documents on UML talk about that.

    The reason they don't, I think, is because it's called a "Language". And technical guys think about it like a language in that all of the paradigms should still apply. So they go and write the tutorials like its a language and show you all the doodads inside of it without explaining the use, assuming that you can parlay your expertise of how to program into writing UML.

    This is a dirty fallacy that's hurting everyone. UML is a tool (they should probablly call it UMT). It has highly specific tasks that it is very good at. Namely fleshing out ideas in areas of a system where there is ambiguity, either between the customer and the designer, or the designer and the coding team. If you treat it like a language, something that gets used almost uniformly thoughout a project, then all of the different screws and bolts start looking like nails. If we treat it like a tool, like a unit testing framework or a version control system, then we can use it when it's appropriate and leave it alone when it's not. After all, you don't try to implement your network stack with Subversion.

    Maybe this is a culture problem. I remember taking Software Design and Development and we spent a whoooole lot of time talking about requirements, understanding them, and expressing them in UML diagrams. But, again, there wasn't a lot of discussion about when enough is enough, issues of scale, issues of responsibility for different parts of design. Those things, the things that I would think are more important, less specific technical knowledge, just got glossed over.

    That's all I'm going to write about that for now. I've got some more ideas brewing on this subject, but there's nothing worse than a long-winded blog entry.

    About Me

    My photo
    Truly a Simple Minded Fool