Strings in C++...
A few weeks ago, Danny Kalev had an interesting article about Visual C++ 8.0 hijacking the C++ standard. The gist of the article is that Visual Studio proclaims a few string manipulation methods as deprecated, when the official standard does not. There are two things that I could not help wonder while I was reading through these articles though.
I find it interesting to have
this entire controversy on the various string manipulation functions.
If you look at strings from the perspective of an array of characters,
the problem they are trying to solve is already solved in newer
programming languages, such as Java and C#. The question of whether an
array is shorter or longer than the other in these languages
effectively boils down to calling array.length.
This in actuality removes not only the requirement of passing in this
argument, but it also prevents from you from lying about how long your
strings actually are. Everyone that has been programming for any period
of time knows that the length of that array will change at one point or
another, and unfortunately, there will be at least one area in the
program that makes some assumption of how large or small that array is
no matter how careful you actually are.
This, however, is unlikely to be added to C++, as the technique is quite powerful and useful in many cases, not to fail to mention that it may be quite painful to add at this time. But to quote the Spiderman movie, “with great power comes great responsibility,” in this case, the responsibility to know and honor the bounds of an array.
Regardless of that, the other
aspect that prevents this entire class of error without changing the
language is simply by using the std::string
class, as this class manages the memory and particularly, the length of
the string for you. It is not to say that
this class is not without faults, or at least perceived
faults. For one, there is no way to directly append an
integer to the string, which would generally lead to code like this:
- std::string myString = ...;
- int value = ....;
- char str[25];
- snprintf( str, sizeof( str ), "%d", value );
- myString += str;
This is unfortunate.
Java and C# have both addressed this issue, both from having automatic
conversion from objects to Strings (making the above myString
+= value;) and also
having formatters directly in the string object.
In addition to the
perceived
missing functionality (most developers will be able to quickly tell you
at least one more function that they think should have been included in
std::string),
one major concern with the string class is its dynamic memory
allocations. Interestingly enough, however, the introduction
to Effective
C++ suggests some excellent
advice: “As a programmer, you
should use the standard string
type whenever you need a string object. ... As for raw char*-based
strings, you shouldn't use those antique throw-backs unless you have a
very
good reason. Well-implemented string
types can now be superior to char*s
in virtually every way--including efficiency.” And this
excellent quote is from the Second Edition (1998). Of course,
there are reasons where you may not want the
std::string
class, but in those cases, you should use a class that abstracts out
the optimizations you require.
In addition to this, Item 13 of
Effective
STL suggests to prefer std::string
and std::vector
to dynamically allocated arrays, suggesting that they hide many of the
intricacies of dealing with pointers, and further, mentions how some
implementations of std::string
employ a reference counted and
Copy-On-Write semantics that could limit the number of allocations for
certain usage, which is further described in Item 15.
A couple years ago, Andre
Alexandrescu wrote an article
in CUJ's
Expert Forum describing
his experience with std::string.
He was asked to improve the
performance of an application, and it was believed that the issue was
with memory allocations. A little profiling lead him to believe that
strings were part of the issue, so rather than rip them out, he instead
decided to provide some policies to the classes, thus depicting how
they were being used. This significantly improved the applications
performance within a couple weeks of work.
All of this to say that the
std::string
class leads to code that is more readable, performs
nicely, and should you encounter some issues on your platform, you
could potentially upgrade your STL implementation or roll your own
string-classes.
While declaring functions deprecated that are not deprecated in the standard is a bit extreme, I think that this brings awareness to the seriousness of this issue and should developers pay attention to the warnings, it could yield more secure and stable software.
Of Hacks and Keyboards...
I am not sure if I missed something or not, but I am completely surprised at this conversation about being notified when a tab changes in a TabControl. I am surprised that no one has mentioned TabIndexChanged event or, if you are working on a platform that does not support that event (such as Windows CE), the SelectedIndexChanged event.
But what is even more surprising to me is that, not only did someone suggest setting up a mouse event handler to be notified when the user selects the tab, the original author had actually tried it! Fortunately, it seems that this does not work.
From a usability perspective, what about the keyboard? While most people use a mouse for selecting tabs, some people use the keyboard, and depending on what happens when the event occurs, the user experience of the keyboard user would be different than that of the mouse user. Debugging this over e-mail could be rather amusing, to say the least.
When creating hacks, you have to consider the cases for which the hack would not work, and in a user-interface, the inability to use the keyboard is definitely something that should be avoided, especially when a little further research would provide the desired and correct behaviour with minimal effort as the case above. Unfortunately, sometimes this is not the case, and for these cases, the caveats must be minimized and well understood and documented. Based on the discussion, I do not believe that this was the case for this particular issue.
Commonalities between Home Depot and .NET
In the last few weeks, I have been developing a couple tools in C#, half in Microsoft Visual Studio 2003 and the other half in Microsoft Visual Studio 2005. I maintain some of my initial reactions to C#, but I have begun to see why Kevlin Henney believes that C# is a more expressive language than Java. Take, for example, the following Java code:
- for ( String str : list ) {
- System.out.println( str );
- }
You would really have to know that this is a for-each statement or at least spending a couple seconds figuring that out the first time you see it. On the other hand, consider this C# example:
- foreach ( string str in list ) {
- System.Console.WriteLine( str );
- }
That is very obvious, and can be easily read aloud.
That said, however, this morning I read Billy Hollis’s How is the .NET Framework like Home Depot? and I couldn’t agree more. The .NET framework is not obvious when you do not know exactly what you are doing, and it can be daunting to find the answer.
I have witness this myself a couple times in the last week. For many things, you can simply Google and find enough hints to get you through the situation, but one problem I still have not solved. According to this MSDN Chat, you can implement an ActiveSync Service Provider using C# by implementing two COM interfaces, although he is unaware of anyone actually doing this, but I have not made major headway in this area after trying for a couple evenings (this is not particularly useful, BTW).
This is probably an extreme case (though you would think that C# would be a first-class citizen), but I regularly find myself knowing that I want a particular class or behaviour, but I am not sure what it is called. For example, the other day I was looking for the a map class, similar to Java's java.util.Map or C++’s std::map, and it was rather surprising to find out that this class named System.Collections.SortedList, a class that I would have assumed would have meant that the items in the list were sorted, not a list of key-value pairs, sorted by key.
One of the biggest issues with .NET is definitely the documentation. The documentation is generally brief or misleading. Some entries are simply filled with examples, such as when upgrading to 2005, the debugger will throw an InvalidOperationException if you attempt to perform an operation on a control that was created in another thread. When this occurs, it will refer you to How to: Make Cross-Thread Calls to Windows Forms Controls; the entry, however, does not describe the technique that you are employing, and the example is much longer and convoluted than it needs to be.
There are definitely some improvements in the newly released Visual Studio 2005, and while some of the things I have mentioned above will hopefully be addressed in future releases, some of them are not easily resolvable (like the Map-class), but at least they are going in the right direction.
Leonardo’s Laptop...
One of the books that I have recently read is Leonardo’s Laptop, by Ben Shneiderman. In some regards, this book is similar to some of the other books that I have discussed on this site, such as The Inmates Are Running The Asylum, which basically state that today’s software is, in a word, unusable. The amount of knowledge that people need to do to get a task done with a computer is still very substantial, and in some regards, this is a barrier between the user and their goals.
I have recently relocated, and with any joy of relocating comes the joy of opening new accounts. The variety and disparity of the user interfaces to accomplish the simple task of getting statements and paying bills is unbelievable. To single one out, my cell phone provider allows me to pay my bill automatically via credit card. To enroll in this service, however, it takes “one or two billing cycles to take effect.” Until this takes effect, you must pay your bill normally. Now, I find this odd on many fronts. First, why could they not add a little dialog box at the end to say, “Would you like me to charge the current amount due of $XX.XX to this card right now?” Thus it would appear that this service would take effect immediately. But because it is not this way, I must entire my information twice. It just does not make any sense.
On the same token, I have recently had to change my credit card information on this site, and I could not change it for a week. Why? Because my bill was pending be charged to my credit card. Yes, you read that correctly. Because they were about to charge my credit card, I was unable to change my credit card information for a week. Again, this does not make any sense.
We really need to take a step back, and look at the software we are writing and make sure that the underlying implementation details are not exposed. The latter example is a wonderful example of this. This is purely an implementation detail. In reality, they could have taken my new information with the caveat that the information would not take effect until the next billing cycle. Or at least, the error message would occur for at most one hour when they were actually processing my account, and not for the period of seven days.
This is the type of thing that Ben discusses in Chapter 2, “Unusable at any Bandwidth.” Like his example of the Therac-25, a device that delivered radiation treatment for cancer patients. While technologically advanced, its user interface was unusable, and caused many errors, including killing some patients. According to the book, no one could imagine that it was the Therac-25 that was causing this, especially since the logs did not indicate the issue. But many of these things were caused by incomplete documentation, poor user feedback, and error messages like “Malfunction 54”. Ben goes on with other examples similar to this.
While the book discusses these matters a bit, the majority of the book is not directly related to this. The author discusses Leonardo Da vinci’s multi-domain expertise, including technology, science, and arts, and how he was capable of using this expertise in all of his projects. For example, his accuracy and attention to detail such as the angle of lighting, natural garments disposition, and facial expressions in his paintings.
He uses this as the introduction to the idea that we should rethink the way that we create software. Instead of creating good-enough software or creating a portion of the software extremely well, really addressing every aspect of a software application, from the technology aspect, the user-interface aspect, the testing aspect, etc. The goal in doing so is to make a great piece of software that can be used by every one, regarding of ability, disability, language, experience, etc., and to create software that you can collaborate with other people. Ben spends a chapter discussing human activities and relationships and how they interact; collaboration and getting credit for things that you have done are takeaways from this chapter if you do not already believe that. One of the great misfortunes is that Leonardo did not share many of his experiments with others, and some believe that this cost the world a number of years of advancement, not to fail to mention the number of pages of his work that have gone missing through the years.
The author then proceeds to provide some ideas to get us thinking in the areas of education, business, health care, and government. I find that some of his ideas are not vastly different than what we have today; for example, he discusses the usability of Access Washington to encourage more usability like this. Other ideas are just simply outrageous, such as the idea of placing a device on each tree, which would be able to tell you what kind of tree this was, the history of the tree, and even maintains a guest book. I can only imagine the great expense of this type of project, not to fail to mention the number of these that would be vandalized in some form or another.
Some of the other ideas though simply require a lot of work in order to accomplish, and it would require a lot of people fully behind these endeavors. One of these examples is a world-wide medical database, in which the idea is that no matter where you are, no matter what language a doctor speaks or what time it is, a doctor could review your medical history, your allergies and current medicine, and from this information, be able to treat you. Furthermore, by placing all this information into a database, the information could be analyzed to find out if other doctors have successfully treated patients with a particular disease. In this case, doctors could communicate to each other to find out how this doctor was successful and what they would recommend doing. And as doctors apparently do not have a grading system, this could double as a reputation, similar to ebay’s feedback system. And this system could also give doctors instance even access to current medical outbreaks, since they currently get updates via periodicals. As you can see, such a system could easily grow out of control.
But at the heart of this is enriching our lives with technology, no matter who we are or where we are. This attention to detail is really important for a user experience. In essence, users should be oblivious to the fact that they are even using computers to accomplish their tasks. In this vein, I close with two quotes from the book:
Technical excellence must be in harmony with user needs.
Great works of art and science are for everyone.
protected in Java...
Here is an interesting question for Java developers. Consider the following classes, where class A is an abstract class that defines a protected method getInfo(), class B is a class that derives from A, and class C uses class A. In Java, is class C allowed to access the method getInfo()?

The answer may surprise some, but the actual answer is that it depends, because I have omitted one important piece of information that is required to answer this question, and that is piece of information, as surprising as it may be, is what package do these classes belong to.
If you refer to section 6.6.1 of the Java Language Specification, you will note that the definition indicates that:
Otherwise, if the member or constructor is declared protected, then access is permitted only when one of the following is true:
- Access to the member or constructor occurs from within the package containing the class in which the protected member or constructor is declared.
- Access is correct as described in 6.6.2.
Of important note here is that classes within the same package as class A from the above example can access the method getInfo().
To drive this point home a bit more, consider the following cases:

Here, we illustrate a Package A, which contains our abstract class A with the protected method getInfo(), class B which derives from class A, and class C and D which use class A and B, respectively. With this in mind, if class C instantiates an A and acquires information from it, it is OK.
- // From Package A, class C
- A a = new A();
- a.getInfo(); // OK
If class D does the same call via an object B, this is not valid:
- // From Package A, class D
- B b = new B();
- b.getInfo(); // OK
Now, if we do the above two calls in a separate package, this will not work. For example, in Package B, we have a class E, and should you attempt either of the above, this will result in a compilation error because now the two classes are not in the same package, and therefore, it is not accessible.
- // From Package B, class E
- A obj = new E();
- obj.getInfo(); // ERROR: We're not in the same package now!
In Package C, I show a new class F that is derived class from class A (from Package A); it does not, however, overload getInfo(). If class H instantiates an F via an A as follows, this will also result in an error since the compiler does not know that you are actually manipulating an F and thus treats this as an error.
- // From Package C, class H
- A obj = new F();
- obj.getInfo(); // ERROR: Maybe he compiler does not know A is really an F? Keep reading
But is that really the reason the compilation fails? Let's see. If we have another class G that accesses the F directly, you will still have a compilation error.
- // From Package C, class G
- F obj = new F();
- obj.getInfo(); // ERROR: F is not involved in getInfo()'s implementation
Interestingly enough, this is covered in the example in section 6.6.7, in which it states that this cannot be permitted since class G is not involved in the implementation of A.getInfo().
So that brings us to Package D, which defines a class I that derives from class A and overrides the getInfo() method. Now in this package, if we try what we tried in the previous example in class J, we will note that it will now work. This is because class J is involved in the implementation of getInfo.
- // From Package D, class J
- J obj = new H();
- obj.getInfo(); // Works!
This is extremely interesting, especially if you come from a C++ background where packages do not exist. It is definitely an eye opener and will change my approach to class design!
Earlier Entries
- Adding Stack Traces to C++ Exceptions...
- The Proposed New Purpose for the C++ auto Keyword...
- The Multiple Personalities of the Singleton
- Choosing the Price...
- Static Generic Methods in Java...
- Coding Standards...
- Got your back...
- Some Environmental Antipatterns...
- J#'s raison d'être...
- J2EE and .NET are friends after all...