Our resident expert in advances in Computer Science, Professor Bin-Haad, reviews the first details to emerge about the experimental language IM#1, which has been a remarkable University project jointly sponsored by the major players in the battle for the Desktop. On this special day, we hear about the radical features of the new language, designed once and for all to resolve the apparently irreconcilable demands of the proponents of all the different computer languages required in order to create portable applications.
Ever since computer languages were first introduced, their relative merits have been the subject of hot debate amongst developers. These debates have intensified after the release of .Net. If you have the temerity to disparage C#, you are likely to start a holy war second only to the holy war you’d start by disparaging VB.Net. Any mention of the superiority of F# is stamped on by both camps, suddenly united in the face of a common enemy.
While the goal is impressive, and this coalition is surprising, it was inevitable in the light of the fragmentation of effort. Google is worried about the influence Oracle might wield over the future of Java, and Apple was concerned about a flight from Objective C if Microsoft and Google were successful. Truth be told, Microsoft still feels some residual guilt over having released VB.NET in the first place, but a lot of culpability over the current state of language fragmentation.
The coalition members all felt that we would be stronger as an industry with a cross-platform language that would reduce the cost of application development and stop the infighting.
Enhanced Case Sensitivity
Many languages are case-sensitive, but this is often not considered a very popular language feature. In fact for many languages, this often ranks up there as one of the most irritating features. The problem is that case-sensitivity is not implemented properly and adds no value.
Fans of case sensitive languages will tell you that there is a difference between whiteHouse, WhiteHouse, whitehouse, WHITEHOUSE or even wHiteHouSe. There is a difference between a house that is painted white, a house owned by the White family, and of course the White House in DC. Without being case sensitive, a programming language cannot keep track of these differences. This is why we need the case sensitivity. Unfortunately even c# cannot tell you that whiteHouse is correct but whitHouse is not. This is where IM#1 is different and better.
Most people have a problem with the case sensitivity because it does not add enough value to compensate for the inherent annoyance. IM#1 overcomes this objection by adding value in exchange for the extra effort of handling this case sensitivity. IM#1 uses the case sensitivity to split identifiers based on case change and ensures that the various components are spelled correctly. This is a huge benefit.
With IM#1, you will get a compile time error if you misspell part of a property or a method or a class. No more embarrassingly discovery that your Employee object hides a FistName property or a CalcluateBasket method. Such embarrassments are especially painful to any developer who takes pride in his work. A little inconvenience of case sensitivity is a small price to pay to avoid such embarrassments.
For the many programmers who remember the reason why C was originally case-sensitive, and don’t buy the idea that it is good discipline, a version of IM#1, called im#1 will be released with a case-insensitive collation.
There has been a long-running debate over the wisdom of making array indexes start at 0 or 1. Most of us count our fingers by going ‘one, two, three, four and five’, but many find it intellectually superior to count them ‘zero, one, two, three and four’. IM#1 will have a release version for those with the latter preference called IM#0, or 1m#0 for those who want case insensitivity as well.
Streamlined Conditional Logic
You probably already know that switch statements are bad, and are, in fact, hidden GoTos. The problem is that these innocent looking statements are throw backs to a procedure programming mindset and often hides an opportunity for an elegant object oriented solution. With most languages it is too easy to fall back into such old patterns. With IM#1, the switch statement finally meets the fate of the GoTo statement.
For anyone not familiar with the problems with the switch statement, consider the following example:
public double CalculateSalesTax (string stateName)
. . .
This is a common procedural oriented way of handling state specific business logic. You know you have a problem in your code whenever you see switch statements with the same set of case blocks strewn throughout your code. Problems arise when you have to add a new case. You find yourself going through your code base seeking out each of these switch statements and making the necessary changes. This is both tedious and error prone.
The object oriented way to deal with problems such as this is to define a collection of objects with a common base class and potentially each implementing a common interface. In this case, you would have an object for each state. Everywhere that you had the switch statement would have a method in the resulting objects. Instead of having this switch statement strewn throughout your code, you would instead make a call to a Factory which will return the appropriate state object for you.
The above method would be rewritten as:
public double CalculateSalesTax(string stateName)
var state = StateFactory.CreateState(stateName);
This is a substantial improvement, especially if the number of case statements is long or subject to frequent changes. In this case, there could have been 50 cases or a very volatile collection of case statements, changing every time you started doing business in a new state.
With the object oriented approach, as you add states, you simply need to create a new object for the new class. The base class or interface will guide you through all of the functionality that you need to provide. You won’t have to go searching through your code for all of the switch statements.
While you could easily properly express such logic with VB.Net or C#, you could also easily revert to the procedural implementation. IM#1 eliminates this problem by removing the switch keyword. To further help you avoid these types of mistakes, IM#1 will give you a compiler error if you have a method with more than 5 if statements to prevent you from reverting to the same old patterns.
This will help guide your design processes and lead you to more elegant object oriented solutions.
One of the best predictors of errors in a program is Cyclomatic Complexity. This metric tracks the number of distinct logical paths through a method. Among other things this metric tells you how many test cases would be needed for full test coverage. This is a strong actionable metric. Higher numbers equate to more complex methods. While you can debate what the ideal number should be, you cannot argue with anecdotal evidence that 5 is better than 7 which is better than 10 and so on.
Personally, I believe that you should strive to keep the complexity below 10 for business logic and capped at 1 for any methods in the UI.
While this is a well-defined and widely accepted metric, its support has largely been an afterthought until now. Using tools like Reflector or NDepend, you can easily track the cyclomatic complexity of your code base, but this was a separate task usually done after the fact. With IM#1, you can specify the thresholds that you are comfortable with, and the compiler will give you an error message should you go over. You can set a warning threshold and an error threshold. For instance, I will configure it to give me a warning when the complexity hits 8 and a hard error when it goes past 10.
Now as you are writing code, with each recompile you can ensure that your code is conforming to the established complexity standards for your project.
One of the most exciting developments in modern application development is NoSQL and the liberation from traditional relational databases that it brings. Much work has been done to shield everyday developers from the difficulties and complexities of interacting with a RDMS. ORM Tools such as nHibernate or Entity Framework or SubSonic seek to shield the developer from having to be aware of or deal with the underlying database. NoSQL takes this a step further by removing the database altogether. Instead of being structured in rigidly defined table schemas, the data is stored in distributed almost free-flowing structured files. This allows the application to scale in several directions at the same time without having to buy sufficient hardware to accommodate peak usage, but which would normally sit idle.
In a typical web application, we could easily scale out by adding additional web servers, but we would eventually hit a bottleneck with what the database could handle. Then we were forced to commit more hardware to a single database. With a traditional RDMS, there will generally be only one database server active at a time. NoSQL removes this bottleneck.
This all sounds wonderful, but unfortunately most of the languages widely used today predate the emergence of these new concepts. With C# and VB.Net, we are forced to cobble together effective support. Sure LINQ provides a nice SQL style querying format, but that does not fit well into the NoSQL mindset, (The NoMindset) and most of the attempts at mapping back to the database are laughable.
Most of the mapping problems stem from the inherent object-relational impedance mismatch. Put simply a relational database and an object oriented application are really too different for there to be a smooth mapping. You might as well be trying to create a smooth mapping from Chaucer English to Modern English. It would be just as awkward.
Once again IM#1 comes to the rescue improving this sad lot with OM1. OM1strives to fill the same need that ORMs attempted to do but realizes that the problem is with the R, plus ORM were never sharp enough. With OM1, we accept that there is no need for a database. There is therefore no need for the R in an ORM. We can therefore allow the NoSQL library of our choice to persist our objects in all their native glory bypassing the effort of trying to fit a round peg into a square hole.
With OM1, there are no mapping considerations. The metadata for your objects themselves becomes the mapping data. You don’t have to do anything more than compile your code and the next time you start the application, OM1will automatically figure out what changed and make the adjustments on its own. This frees up a tremendous amount of time for developers to focus on other more pressing tasks like fly out animations, and multi lingual validation messages.
The other problem that needed to be addressed was the way that SQL kept creeping into our applications through LINQ. As long as we are content to keep the SQL mindset, this was fine. But if we want to truly break out of chains of bondage that have strangled innovation for far too long, we need to break off this last shackle.
This is why OM1defined MR query language. To retrieve data from the NoSQL data store, you can use MR to query it.
OSMR CM have LastName = “bin Haad”
LIB MR customers
Return customers with LastName = “bin Haad”
By embracing a new language and adopting a new metaphor we can free ourselves from the restrictions of the database with it set theory and graph theory and be free to truly innovate.
Forget About the Curly Braces
Another common complaint with many c style languages has been the dependence on the dreaded curly brace. Part of the problem with the curly brace is that it does not necessarily convey enough information for the human programmer to read. It is very helpful for the computer, but we need to look out for the humans as well. VB got around this problem by making a key word specific block terminator keyword.
While this sort of close-curliness may not have provided enough information to be useful:
This was never really acceptable:
Many people tried for a compromise through convention by forcing c# into a pattern like this:
} // end if
} // end while
} // end method
} // end class
} // end namespace
In my opinion this was the worst of both worlds. Sure you got more information, but you were also left with ugly formatting and you had to go back and add the comments in yourself.
When a block included only a single line, c# would allow you to forego the block delimiters all together.
if (amountPaid < amountDue)
amountPastDue = amountDue - amountPaid;
As long as you only had a single line, this works well, but once you need to add a second statement, your block of code grows to 4 lines.
if (amountPaid < amountDue)
amountPastDue = amountDue - amountPaid;
accountIsCurrent = false;
IM#1 reaches a compromise by allowing the curly braces to continue to be optional. The beginning and ending of program blocks is determined by the indention level.
if (amountPaid < amountDue)
amountPastDue = amountDue - amountPaid;
accountIsCurrent = false;
if (amountPaid > amountDue)
amountOfOverPayment = amountPaid - amountDue;
accountIsCurrent = true;
The curly braces were only ever there to make it easier for the compiler to parse the code. The compiler can easily detect the closing curly brace and close the most recently opened program block.
In today’s world, we don’t need to be making it easier for the compiler. The compiler can get along just fine. Instead IM#1 makes it easier for the developer. The compiler is stuck counting indention levels and tracking when that changes to determine which program block to close. The programmer is free to simply make sure that the elements line up under the containing block properly.
Obviously, not everyone will like this feature. For those of you, who do, enjoy. For the rest of you, the curly braces are still there to give you a warm fuzzy feeling that your blocks begin and end where you think they do.
Improved Event Handling
The error of not properly handling wired up events leads to most of the memory leaks that you will find in a DotNet application. Clearly this is the weakest link when it comes to DotNet memory management. IM#1 seeks to remove this weak link with an enhanced event handling model.
The problem with the traditional event handlers is that when they are not released properly, the object with the events will not be eligible for garbage collection until the object that wired up the events is out of scope. This often makes it difficult to track down memory leaks.
IM#1 seeks to eliminate this common trouble spot by introducing a new event handling pattern using Reflective Extendable Transient Abstract Reactive Delegates. This pattern is similar to the Weak Event Pattern introduced for WPF except more of the heavy lifting is handled by the compiler and it is more flexible.
The reflective component comes into play because of the mechanisms used to discover events that would benefit from this implementation. The extendable components show cases the differences from Weak Events. You are not limited to simply handling disposing of objects, although this will be the most common task. You can extend this functionality to take any number of actions when the system determines that the referencing object should be ready for garbage collection. This may include performing additional cleanup, logging metrics, or alerting the user. By referring to these items as transient, we highlight that they can be created and destroyed as needed by the framework without any direct interaction from the developer. Finally they are reactive delegates in that they can react to changes in the application usage to be created or destroyed as needed.
This is an exciting new addition to the framework holding the promise of eliminating a whole class of persistent memory management issues.
Marking an Assembly as IDWIMTD or “I Did What I Meant To Do” is a way of signifying to the compiler that while some of this code may look suspect, I do in fact know what I am doing. I did what I meant to do, and don’t worry about it. This is similar to making code as “unsafe” in C# except that even more rules are suspended based on the assertion that you did what you meant to do. Naturally there are some risks in using this modifier. The various safety features that DotNet brings to the table will not be in place with code modified as IDWIMTD. For an assembly compiled as IDWIMTD, the framework will disable the garbage collector, type safety checks, and overflow checks. Under normal circumstances, these features provide more than enough value to justify the added performance hit, but there are some select circumstances where the performance hit is unacceptable. In such cases, IM#1 marked as IDWIMTD can put your code on the same level as C or C++ in term of performance overhead, but still reap many of the other benefits of using the framework.
How many times have you lamented all of the barriers that come between you and the computer? All of these layers of abstractions have their place, but sometimes it is useful to skip all of these layers and communicate directly with the computer in its native language.
When you flag a method as being in binary mode, you can write your code directly in binary.
public void HelloWorld()
Obviously this can only be set in an assembly that is already marked as IDWIMTD, but this does open up a whole new world of possibilities that I look forward to exploring. One could even insert some GOTOs.
IM#1 represents a bold new language. While its adoption may not be easy for everyone, it does enjoy considerable industry support, and does represent our current best hope at bringing unity to the programming languages and finally ending the divisive debates over which language is best.
I urge you all to download, play with it. Explore the new features. Post your comments. There may still be a few kinks to work out, but your comments and feedback can only make this a better language.