eyt*

Find your next scenic drive!

August 17, 2004

The C++ Export Keyword...

In the InformIT C++ Newsletter, Danny Kalev discusses the export keyword. As Danny points out, not a lot of developers know this keyword, mostly because up until last year, it was not implemented. Comeau C++ is the only compiler to date to support it.

The article provides a good introduction to the keyword and how it works, however, I disagree with his conclusion. Danny concludes that since no one has implemented this feature and that developers want to see compilation errors early, that it is a doomed feature that failed. Most compiler vendors have not implemented this feature because most compiler vendors have not implemented the entire C++ ISO Standard; the last time I checked, Visual C++ 7.1 (2003) was the compiler that implemented the most, at 98%, and definitely a language feature that is widely used has more precedence over a language feature that no other compiler supports; its the nature of business.

Anyone that has worked with explicit template instantiation knows what it is to have link-time errors with templates. By default, most compilers default to implicit template instantiation, which means that when it sees you use a template, it instantiates that template immediately, and the linker does its best at sorting it all out. This generally leads to some code-bloat, since the compiler will instantiate more than is really required, and the linker does not remove enough.

Explicit template instantiations is meant to resolve this issue, by making the developer explicit state which templates should be instantiated. This generally leads to a file per project that explicitly instantiates only the required template functions that are required to link. Of course, when you forget one to instantiate one, you will get some error messages during link-time, or runtime with DSO's, and this usually takes a few times of going back and forth like this until everything is resolved. This especially makes people who did not like templates before to especially despise them after doing this a few times :-).

One advantage that was not mentioned of the export keyword is that since templates are presently implemented in header files, any change to the template requires a total rebuild of the the users of this. Some coding standards require that the interface and implementation be separated, using file.h to denote a header and a file.imp.h to denote an implementation. Using this standard, if a class references a template class, they only include the former, whereas if the class actually uses the implementation, the latter file is included, but never in an interface file (i.e.: only in the .cpp). This isolates such changes to only the need to recompile the true users of the template, but even still, if the change in the template is minor, there is no true reason to recompile all the users of the template. The export keyword would allow this to happen and solve all the aforementioned instantiation issues.

Of course, the tools are getting better at supporting templates, and I still think that the best is still to come. If you forget all the comparisons of the power of C++ templates verses the Java Generics for a moment and only consider the approach that Java has taken, the export keyword could be similarly implemented in C++. In Java, a generic module is compiled into a class object that is essentially incomplete, and when a reference to that generic module is made, the Java Runtime molds everything together.

A method similar to this could be done in C++, and given all the research that has gone into finding this solution for Java, I am sure that there is an even better, more transparent solution for C++ vendors. It is just a matter of time.

A Little More Than Write-Once, Run Everywhere...

Java's motto has always been “Write Once, Run Everywhere” (although many usually say “Write Once, Debug Everywhere”). When an application runs on an operating system, it is generally desired that the application works with the environment. Prior to Java 1.4.2, Wheel-Mice generally worked everywhere except in Java Applications, making this seamlessness less seamless.

Novell has an article about porting Java Applications to SuSE Linux. It is an interesting read, but I am not sure of their audience though. Never-the-less, the document does highlight the fact that Linux has two different facilities for Copy and Paste, viz. Selection and the Clipboard, and indicates that Java only supports the latter. Confusingly enough, the article starts off by stating that SuSE Linux supports 1.4.2, but the article really focuses on Java 1.3.1.

Either way, Java 1.4.2's java.awt.Toolkit's getSystemSelection(), I am glad to say, does the trick. But this being said, it is unfortunate the number of applications that are said to use the 1.4.2 release that still do not support it. One such application is Borland's JBuilder, which hopefully JBuilder 2005, which integrates more development tools into JBuilder (including parts of it's OptimizeIt Suite and a Code Analysis feature, probably similar to IntelliJ Idea 4.5), will also integrate this, too.

This is not to say that this is only a Java-related problem. By far not; Nvu, an HTML editor based on Mozilla' Composer, also has this issue, which is surprising, since Mozilla is well integrated.

Porting to a new operating system is more than just making it run there; it must be well integrated into the system. These little minor details make software inconsistent, and therefore, harder to use, even though, at least for this issue, it is not a lot more coding on your side.

August 11, 2004

Over-Engineering or Abusing C++?

In this week's InformIT C++ newsletter, Danny Kalev introduced his Over Engineering article as a disease that harms software development, testing, and documentation, and purports to provide some keys to identify and curve this ailment, and so I eagerly read.

When I think of over-engineering, I immediately think of developers adding features that are not required, similar to my post earlier this week on Leveraging Frameworks and The End of Catch-All User, where I mention this in relation to developers not really knowing what the end-user wants and trying to please every possible end-user, and as I mentioned in the former entry, this dates back to the very beginning of our industry.

As such, when I started looking at this article, I was rather surprised, because this is not what the article is about; the article is really about language features that Danny Kalev does not like or feels that are abused, and in many of those cases, I would not see this as over-engineering. For example, his first complaint is about exceptions, because he states that this leads to code that looks like this:

try {
  url = new java.net.URL( "http://www.eyt.ca" );
} catch ( java.net.MalformedURLException murl ) {
}

In this snippet of code, the exception raised by java.net.URL is ignored, and Danny claims that is a very common “idiom” in “in every Java-based application.” Every is a little too general, because in my coding standard, the above code is unacceptable, and in my projects, the above code will not appear, unless there is either a comment indicating why we are ignoring it (id est: in the above case, if that URL is invalid, we have a lot of issues), or at the very least, the exception is logged. But these two cases are extremely rare. IntelliJ IDEA's code analysis feature, for example, states that this is occasionally intentional, but warns that such instances are hard to debug. I prefer to either rethrow the exception or map the exception onto an exception that does exist, using the J2SE 1.4 feature of Throwable.initCause(), so that the history is completely available.

I do not see Exceptions as “lip service” as Danny says. Per se that java.net.URL's constructor did not throw an exception; how then would you know that there was a problem? Well, then you would have to do something like the following:

java.net.URL url = new java.net.URL( "http://www.eyt.ca" );
if ( !url.operable() ) {
  // Do something smart here
}

Or, if you prefer to write the above in the same style as the empty-catch:

java.net.URL url = new java.net.URL( "http://www.eyt.ca" );

There is plenty of code out there (and not just in C++) that looks exactly like the line above, and does not check for any type of errors. That being said, raising exceptions means that you are forced to write code that handles the problems. You may think this is a bad thing, but how many times have you written code that does not check for errors that works perfectly on your system because of your configuration, and once that it is installed at a customer's site, it blows up? Debugging these problems are extremely difficult, and so you either check for errors or you risk your application blowing up at random places. Its your choice.

The C++ exception specification is a mis-feature only because, in my opinion, that it was poorly specified. As I mentioned in my first exposure to C#, the problem with C++ exception specification is that the compiler does not really enforce it. If a function declares that it will throw an exception of type std::exception, and it throws an exception of type std::string (yuck), the language states that it should terminate, but a compiler has no way of knowing this if exception specification is not globally used, and therefore, this becomes impossible to ensure. This is why the exception specification is not used. It would be difficult to change this stance to be as strict as C++ and maintain full backwards compatibility.

I personally like Java's approach. In continuing with the java.net.URL example, the documentation clearly indicates that only a java.net.MalformedURLException can be raised. As such, today if I write some code that uses this class, I know exactly which types of exceptions are raised and I write error handling code to address these issues. Per se that when J2SE 5.0 (or 1.5 or Tiger) comes out that the constructor that I am using will now validate the host portion of an HTTP-based URL and now throws a UnknownHostException, when I attempt to compile my code with the new version, the compiler will tell me that I have a new error to handle.

My example of java.net.URL is really a poor choice, because I cannot imagine this type of change in the Java Core (if anything, java.net.URL would be deprecated in favour of something else), but for some libraries and especially applications, these types of safe-guards are really important, and returning back the C#, I really felt that this was a missed opportunity. In either case, if I upgrade libraries and a method in that library now raises a new exception type in C++ or C#, it better be mentioned in the release notes and you better be reading those release notes because your compiler will not give you warnings or errors about this.

The example of the C++ Standard Library not throwing exceptions for each possible problem is a design issue, as is the C++ Standard Library's instance on a Stack having a pop() method that does not return the removed element (which is actually done for exception safety). As for embedded environments, I do not feel that this has any bearing on exception handling, since such environments usually do not implement other features, and you must generally adapt your use of the language to those features that are best supported and most optimal in your target environment.

Danny's next example is on templates, and here I see why he is placing this in an over engineering topic. After reading some extreme-template articles and books, such as those from Andrei Alexandrescu, you start to feel that you must create a template for every single function, which will take a trait for every single possible thing that a user will ever want to do with your template. While this goes a little into the direction of over designing classes, templates are a special case. My own take on templates is the same as Martin Fowler states in Refactoring (or its web site), in which he says that the first time you write it, the second time you copy it, and the third time you refactor it. There is no reason to write a template if you are simply going to use that template once; depending on how much code is involved, it is sometimes acceptable to simply copy the code the second time, but if it is large or complex, it may warrant refactoring, or at least by the third time you should be thinking of templatizing it. The point in all of this is simple: for most developers out there, perfecting non-templated code is much easier. Once you have a perfect algorithm, it is much easier to translate this into a template. Once that you have a few instances of this algorithm, it is much easier to generalize the algorithm, since the algorithm will probably be used with different types and in different cases. But even when refactoring into a template, it is important to keep in mind that you should only be implementing what you will use now. You can refactor the code later if you need to.

This problem, however, is not specific to generic programming, but generic programming seems to stick here, partially because many developers are not comfortable with them and secondly, not all compilers treat templates correctly, which can make them harder to port (although most modern, standard-conforming compilers are fine in this area). These two issues makes them stick out. Classes and functions are likewise occasionally over-engineered. The idea of creating classes iteratively is lot globally accepted, and instead, developers try to define every single method that a user of that class could possible use instead of focusing on a particular feature; you can always add more functionality latter, or even refactor the design completely. The fear is, however, that time to do this will never occur, and so we end up in this endless loop of not doing anything. In this regard, I find that having an extremely good idea of what your users need is most beneficial in both identifying the problem and rectifying this problem.

Danny's final point is with overloading operators. This is a C++ language feature that I seldom use, and as such, there have been very few times where I felt that it was lacking in Java. The times that I have felt that it was lacking was when dealing with numerical classes such as BigInteger, as a = b + c is easier to understand than a = new BigInteger( 0 ); a.add( b ); a.add( c ); or any other combination thereof.

As such, I tend to agree with Danny that operator overloading with numerical classes generally makes sense, and in others, it generally does not. If i is an iterator, is ++ i clearer than i.next()? This is arguable. His example of the function object using operator() is great; your class should declare members that make sense and are readable. If you need a function object, consider using an Adapter instead.

In closing, I do not feel that this article really dealt with over-engineering, and rather focuses on some language features that are abused or misunderstood. The only one that comes close to over-engineering is the example on generic programming, but even here, I feel that Danny missed the point that this happens in more places than just generics. Over-engineering is adding features that no one (or few) will use, and the only way to avoid that is to know your users, whomever they may be.

August 10, 2004

Microsoft-based Modeling...

Patrick Meader has an interview with Keith Short, an architect for the Microsoft' Visual Studio Tools Group, concerning Microsoft's upcoming Modeling tools that I discussed here before. Model Apps More Effectively and Build Distributed Apps a New Way discuss some the tools, the reasons why Microsoft is adding modeling to the language, and why they are not using UML.

Keith Short states that many of the existing UML tools have failed because how the code is separate from the diagrams, and keeping them synchronized is not a simple task. The Microsoft approach is completely integrated, such that you can see your code or see a diagram that is based on your source, but this workflow is not required, and developers can continue to work as they do today.

Keith Short also states that the reason that they choose to use their own diagramming language is mainly because UML currently does not support notation for the SOA, and they viewed UML as not extensible, stating that they would have to support stereotypes and profiles. But also a large part of this is that they believe that UML presently has its own type system, and that you must map this type system to your implementation system. Microsoft plans to rectify this by making their modeling language tied to .NET's type system. But how is this different than our existing tools? I mean, tools are optimized for a particular language, and if you do not use that language, you will fall into this problem.

The notation to Microsoft's diagram language, however, is said to be intuitive to anyone who currently knows UML; I presume that piggy packs on how C# looks intuitive to anyone who knows C++ or Java. The UML tools themselves, Microsoft still insists, will come from the Modelers, who will build “on top of our framework,” supporting Keith's statement that their move is not anti-UML, but rather pro-modeling. Keith also mentions that UML supports a lot of diagrams that developers do not use, and while this is true, my question would be if there are any types of diagrams that are not used, and by this I mean that Collaboration Diagrams and Sequence Diagrams are very similar in nature, and picking between them can be more of a preference. As such, I can imagine that some developers never use Collaboration Diagrams, just like some developers never use Sequence Diagrams, not to fail to mention those that use neither or a mixture of them. The point being that this is flexibility, and not necessarily a problem.

I am not sure what Keith's means when he states that UML is “a standard that was not precisely specified.” As What UML is isn't states, UML is nothing more than a diagramming language, and as this, I believe it is well defined, but the process used with UML is not defined with the UML standard. Instead, processes are defined that use the UML notation, and these some of these processes are well defined, and others are not, but strict processes are difficult to implement, and this is where some flexibility can mold the process into an environment. Other than this interpretation, I am not sure what else he could have meant, as there are many UML-based tools on the market today that had no problem interpreting the standard (the only problem is that they have all implemented a portion of the standard, but that portion differs from product to product, similar to ISO Standard C++ support in compilers).

When asked the question about interoperability with J2EE, Keith Short's answer was rather vague, in the sense that he focused more on the interoperability question, and I would personally be quite surprised if Microsoft's tool could not model standard WSDL files, but what about modeling Java? I suppose the answer to this question is partially J#, a Java wanna-be for the .NET Framework. But even at this, how will its tool focus on the other languages in the standard Visual Studio package, not to fail to mention the other languages that now target CLR? I would imagine that they would use some reflection-based scheme to reverse engineer, but what about code generation? The interview focused primarily on C# and Visual Basic, but I would like to think that the other languages are also supported easily.

I think that Microsoft's solution is a partial step in the right direction to keep the code and diagrams together, but I am concerned on its modeling language, and some of the things that the tool can do sounds as if it will just be an extension of what we really already have today, but this will be hard to completely say until it is released though.

August 9, 2004

More on Microsoft's Purchase of Lookout...

A bit ago, I talked about Microsoft buying Lookout. Joel On Software has an interesting analysis on it, suggesting that Microsoft is only purchasing Lookout as a means to get talent, and disposing of the technology. Part of this stems, it seems, because Lookout uses open source components, which prevents Microsoft from redistributing it.

I am pretty sure, however, that the Lookout for Outlook was not available for download when I first talked about it, but although unsupported, it is now available.

It is unfortunate that such technology must be shelved because if Joel is correct, Microsoft wants a particular talent. But it is not the first time, nor will it be the last...

Earlier Entries

<  13  14  15  16  17  18  19  20  21  22  23  >

Navigation

Recent Posts

eyt*