Similarities And Differences Between Hardware And Software Testing
Kirk Radeck, Windows Embedded MVP Senior Software Engineering Consultant October 2003 Applies to: Microsoft® Windows® CE.NET Microsoft Windows XP Embedded Microsoft Pocket PC Microsoft Visual Studio.NET Microsoft Visual C#® Summary: Learn about the differences between C# and Java. (68 printed pages) Whether you are a desktop applications developer or a developer of applications and Web services for Microsoft® Windows® Embedded devices, this technical article will compare and contrast the C# and Java programming languages from an application developer's point of view. This white paper, downloadable from the right-hand corner of this page, describes specifically what is similar, what is different, and the motivation behind the language syntax. It includes side-by-side keyword and code snippet example tables, with a complete usage analysis.
Design exist, and the successful adoption of techniques originally developed for one field for use in the other suggests that these disciplines are related. The panel's goal was to analyze the similarities and differences between hardware verification and software testing and to identify technologies that mature in one field and.
It assumes that the reader has some knowledge about C# and/or Java, although it is sufficient to know C++, because both of these languages have C++ similarities, and C++ is often used for comparison. Contents Introduction Many programming languages exist today: C, C++, Microsoft Visual Basic®, COBOL, C#, Java, and so on. With so many languages, how does a software engineer decide which one to use for a project?
Sometimes, a language is chosen because the developers of a company like it or know it, which may be reasonable. Sometimes a language is used because it is the latest and greatest, and this becomes a marketing tool to generate more public-relations interest in a product, which may not be reasonable in and of itself. In an ideal world, a programming language should be chosen based on its strengths for performing a certain task—the problem to solve should determine the language to use. This paper would quickly become a book or series of books if it attempted to compare strengths and weaknesses, platform support, and so on for many programming languages. Rather, to limit its scope, it will compare only C# and Java. Some languages, such as C++ and Pascal, will also be used for comparison, but only to help demonstrate potential motivations for the creation of the newer programming languages with their newer features.
If some weakness exists and is exposed in the older language, and then shown to be nonexistent or hidden in the newer language, this may help understand the motivation for some change made by the architects of the newer language. Knowing this motivation is often important, because otherwise it is not possible to objectively critique a language. For example, if a so-called 'feature' that existed in a previous language is removed from the newer language, then a developer may feel that the latter is not a worthy candidate to use because it doesn't have the power of the former. This may not be the case; the newer language may be actually doing him a favor by saving him from falling into some known trap. Naturally, Java came before C#, and C# was not created in a vacuum. It is quite natural that C# learned from both the strengths and weaknesses of Java, just as Java learned from Objective-C, which learned from C.
So, C# should be different than Java. If Java were perfect, then there would have been no reason to create C#. If C# is perfect, then there is no reason to create any new programming language. The job would then be done. However, the future is unclear, and both C# and Java are good object-oriented programming languages in the present, so they beg to be compared. It is important to note that not everything can be covered here.
The subject matter is simply too large. The goal is to give enough information so as to help managers and software developers make a better-informed choice about which language to use in certain situations. Maybe some little language quirk in C# may make someone choose Java.
Maybe some blemish in Java will influence someone to pick C#. Either way, this document will attempt to dive deep enough into details to dig up some hidden treasures that aid in our goal. Road Test Tips Parallel Parking. (Items in italics such as the paragraph below and subsequent sections have been highlighted to separate my opinion from the rest of the paper.) While I am not covering everything about C# and Java in this paper, I will attempt to supply some in-depth analysis on most of the topics that are covered. I don't believe that it is generally worthwhile just to say that some functionality exists in a language and therefore try to imply that the language is powerful.
For example, I could simply say, 'C# is a good language because it is object oriented.' Naturally, that would assume that an object-oriented language is automatically good, which, from my experience, not everyone agrees with. So, I feel in this case that I have to show why writing object-oriented code is good first, which should strengthen the above assertion. This can get a little tedious, but I think that it is important.
Also, I generally do not like to promote anything that I have not used. If I say below that the 'language interoperability using Visual Studio.NET is outstanding because it is very easy,' then I have run at least some basic tests to really see if it is in fact 'easy.' More than likely, while not everyone will agree with my opinions, I don't just 'wave my hand' by just restating what others have said; rather I try to put what others have said to the test. What's Similar Between C# and Java?
C# and Java are actually quite similar, from an application developer's perspective. The major similarities of these languages will be discussed here.
All Objects are References Reference types are very similar to pointers in C++, particularly when setting an identifier to some new class instance. But when accessing the properties or methods of this reference type, use the '.' Operator, which is similar to accessing data instances in C++ that are created on the stack. All class instances are created on the heap by using the new operator, but delete is not allowed, as both languages use their own garbage collection schemes, discussed below. It should be noted that actual pointers may be used in C#, but they can only be manipulated in an unsafe mode, which is discouraged.
This paper will not deal with writing 'unsafe' C# code not only because it is discouraged, but also because I have very little experience using it; maybe even more important, because the comparisons with Java will nearly vanish as Java does not support anything like it. Garbage Collection How many times have you used the new keyword in C++, then forgot to call delete later on?
Naturally, memory leaks are a big problem in languages like C++. It's great that you can dynamically create class instances on the heap at run time, but memory management can be a headache. Both C# and Java have built-in garbage collection.
What does this mean? At least forget about calling delete. Because if you don't forget, the compiler will remind you! Or worse, Tony might make you a Soprano. Don't be a wise guy; neither language gives you the permission to whack any object that's become expendable. But you may be asked to call new fairly often, maybe more than you'd like. This is because all objects are created on the heap in both languages, meaning that the following is frowned on in either language.
Delete badaBoom; //illegal in C# and Java - the compiler will complain Use badaBoom as long as you want, then the garbage collector will dispose of him for you when you decide to give someone else your reference. Waste management is a beautiful thing.
Many developers complain about garbage collection, which is actually quite unfortunate. Maybe they want the control—'I'm gonna kill that puppy off now!' Maybe they feel that they're not 'real' programmers if they can't delete an object when they created it. Maybe having a more complex and error-prone language guarantees code ownership by the original developer for a longer period of time. Regardless of these reasons, there are some real advantages to garbage collection, some of them being somewhat subtle: • No memory leaks. This is the obvious advantage. Both garbage collection schemes promise to dispose of all objects at some point during program execution, but neither can guarantee when, except that no object shall be removed until at least all program references to it are removed.
• It rewards and encourages developers to write more object-oriented code. This is the subtle advantage. For example, in C++, developers creating class methods that must return data usually either set non-const reference or pointer parameters during method execution; or return a class instance of another type that holds a composite of all necessary data. I consider the latter 'better' than the former.
Who wants to call a function with 10 parameters? And more parameters passed between client and server code causes more coupling, which is not good. For example, if it is determined later that a function needs to return one more piece of data, then only this function's implementation needs to be changed with an addition to the composite class, which may only require a recompile for the client. Not only that, but when a function returns only one object, this function can be nested with other function calls, while returning data with in/out parameters disallows this nesting. When objects are returned with this 'better' method, usually the developer once again has only two choices: return a copy of temporary data initialized and manipulated in the function; or create a new object pointer in the function, side-effect its de-referenced values, then return the pointer, which is safe since the compiler will not destroy pointers or heap data across functions calls.
While returning a pointer has some advantages (a copy constructor won't have to be called so it may be faster, particularly with large data; a subclass of a pointer type can actually be returned to the caller for extendibility; and so on), it also has a serious disadvantage in C++: the client will now have to be concerned with memory management by eventually calling delete on the returned pointer. There are ways around this, one of them being to implement reference counting using generic templates. However, reference counting is not completely 'visually' satisfying because of the template syntax; and most if not all counting implementations do not handle cycles correctly while both C# and Java garbage collection schemes do.
(Here's a cycle example using simple reference counting: if two objects reference each other, and then only all outside references are released on both, neither will be deleted because they each still have one reference—namely each other—and an object is not deleted until its reference count reaches zero.) Therefore, developers generally take the safe approach, and just return a copy of a compile-time known class type. In contrast, because both C# and Java use garbage collection, developers are encouraged to return a new reference to data when writing function prototypes (instead of using in/out parameters, for example), which also encourages them to actually return a subclass of the defined return type, or a class instance implementing some interface, where the caller doesn't have to know the exact data type. This allows developers to more easily change service code in the future without breaking its clients by later creating specialized returned-type subclasses, if necessary.
In this case the client will only be 'broken' if the public interfaces it uses are later modified. • Garbage collection makes data sharing easier. Applications are sometimes built which require object sharing. Problems can arise in defining responsibilities for clean-up: if object A and object B share pointer C, should A delete C, or should B?
This eliminates the problem: neither A nor B should (or could) delete C using either C# or Java. Both A and B use C as long as they need to, then the system is responsible for disposing of C when it is no longer referenced by either (or any other).
Naturally, the developer still must be concerned about critical sections while accessing shared data, and this must be handled in some standard way. • Programs should automatically become more 'correct.' With less to worry about, application developers can concentrate on program logic and correctness rather than memory management, which should create less 'buggy' code. This benefit is sometimes understated; it is very important. • I am quite sure that there are other advantages that I can't even dream up right now. Both C# and Java are Type-Safe Languages states on his Web page: 'A language is type-safe if the only operations that can be performed on data in the language are those sanctioned by the type of the data.'
So, we can deduce that C++ is not type-safe according to this definition at least because a developer may cast an instance of some class to another and overwrite the instance's data using the 'illegal' cast and its unintended methods and operators. Java and C# were designed to be type-safe. An illegal cast will be caught at compile time if it can be shown that the cast is illegal; or an exception will be thrown at runtime if the object cannot be cast to the new type. Type safety is therefore important because it not only forces a developer to write more correct code, but also helps a system become more secure from unscrupulous individuals. However, some, including Saraswat, have shown that not even Java is completely type-safe in his.
Both C# and Java Are 'Pure' Object-Oriented Languages Any class in either language implicitly (or explicitly) subclasses an object. This is a very nice idea, because it provides a default base class for any user-defined or built-in class. C++ can only simulate this support through the use of void pointers, which is problematic for many reasons, including type safety.
Why is this C# and Java addition good? Well, for one, it allows the creation of very generic containers. For example, both languages have predefined stack classes, which allow application code to push any object onto an initialized stack instance; then call pop later, which removes and returns the top object reference back to the caller—sounds like the classic definition of a stack. Naturally, this usually requires the developer to cast the popped reference back to some more specific object-derived class so that some meaningful operation(s) can be performed, but in reality the type of all objects that exists on any stack instance should really be known at compile-time by the developer anyway. This is at least because it is often difficult to do anything useful with an object if the class's public interface is unknown when later referencing some popped object.
( Reflection, a very powerful feature in both languages, can be used on a generic object. But a developer would be required to strongly defend its use in this scenario. Since reflection is such a powerful feature in both languages, it will be discussed later.) In C++, most developers would use the stack container adapter in the Standard Template Library (STL). For those unfamiliar with the STL, Schildt (p. 5) states that it was designed by Alexander Stepanov in the early 1990s, accepted by the ANSI C++ committee in 1994 and available in most if not all commercial C++ compilers and IDEs today, including the eMbedded Visual Tools.
Sounds like an encyclopedia's version of reality. Essentially, it is a set of containers, container adapters, algorithms, and more, simplifying C++ application development by allowing any C++ class (and most primitives) to be inserted and manipulated through a common template definition. Sounds like a nifty idea. However, there are issues with templates in C++. Say that a new stack of ints is created. #include using namespace std; stack intStack; The template definition is found, then an actual int stack class definition and implementation code are created implicitly behind-the-scenes, using that template.
This naturally adds more code to the executable file. OK; so maybe it's not a big deal, really. Memory and hard drive space is cheap nowadays. But it could be an issue if a developer uses many different template types. From a purist's perspective, it could be viewed as wasteful to have a new stack class definition created and compiled for every type that a stack holds. A stack is a stack: it should only have a constructor, a destructor, a 'push', a 'pop', and maybe a Boolean 'empty' and/or 'size' method. It doesn't need anything else.
And it shouldn't care what type it holds, in reality, as long as that type is an object. The STL's stack, however, doesn't work this way. It requires compile-time knowledge of what type it will hold (the template definition doesn't care, but the compiler does). And it doesn't have the 'classic' set of stack functions. For example, the pop is a void function; the developer must first call top, which returns an address to the top of the stack, then call pop, which means that a single operation has now become two! The inherent problem in C++ that most likely motivated this awkward decision: if the pop function returned an element and removed it from the stack, it would have to return a copy (the element's address would no longer be valid). Then if the caller decides he doesn't want the element after inspection, he would then have to push a copy back on the stack.
This would be a slower set of operations, particularly if the type on the stack was quite large. So a top or inspect method was added which would not side-effect the number of stack elements, allowing the developer to peek at a class instance before he removes it. But when a developer does access this top element, then calls some function on it, he may be side-effecting an element in the container, which may at least be bad style in some scenarios. The original STL architecture could have required that developers only use pointers with containers (in fact, pointers are allowed, but you still need to be concerned with memory management), which might have influenced a prototype change causing the pop method to remove and return a pointer to the top element, but then the lack-of-garbage-collection issue returns. It appears as if the limitations and problems inherent to C++ required changing the STL's public stack definition from the 'classic' view, which is not good. Why is this not good? One example that I am personally familiar with: the first time that a developer reads the specification for an STL stack, he is sad, for one.
The first time that he uses the implementation and calls top but forgets to call pop, and gets mad, for two. The only arguable advantage in C++ using stack templates compared to C#'s or Java's stack: no casting is required on the template's top method because the compile-time created stack class has knowledge about what address type it must hold. But this is truly minor if the assertion above convinces a developer that he should know what type is allowed on his particular stack instance anyway. In contrast, the public interfaces for the stack classes in both C# and Java follow the classic paradigm: push an object on the stack, which places this object on the top; then pop the stack, which removes and returns the top element.
Why can C# and Java do this? Because they are both OOP languages, and perhaps more important, because they both support garbage collection using references. The stack code can be more aggressive because it knows that the client won't have to handle cleanup. And a stack can hold any object, which any class must be implicitly. When I code in C++, I use the STL as much as possible, which may seem strange since I seem to complain about it so much above. In my opinion, the STL is a 'necessary evil' when using C++. I once tried to build some C++ framework that was 'better' than the STL by playing around with my own stack class, using pointers, inheritance, and memory management, just for fun.
Suffice it to say that I was unable to do better than the STL, mostly due to problems dealing with destruction. The STL actually works very nicely within the limitations of C++.
Standard C++ would have been a much better language if only one addition had been made: make every class implicitly an object. Garbage collection is very nice, but not completely necessary. If every class were implicitly an object in C++, then a virtual destructor method could exist on the object base, and then generic C++ containers could have been built for any class where the container handles memory management internally.
For example, a stack class could be built, which holds only object pointers. When the stack's destructor is eventually called, delete could be called on any object left on the stack, implicitly calling the correct destructor. Methods on this stack could be created that would allow either a pop to remove the top pointer element and return it, which would require the developer to be in charge of its later destruction; or return a copy of the element then have the stack delete the pointer internally, for example. Templates would then be unnecessary. It may be worth your while to look into managed C++ code.
I have played with it a little, and discuss at least what I know briefly below. Managed C++ code uses 'my' recommendation (make every class instance an object) but also includes memory management. It's actually pretty good. There are many other reasons why it is preferable to use a 'pure' object-oriented language, including application extensibility and real-world modeling.
But what defines a 'pure' object-oriented language anyway? Ask five separate people and you'll most likely get five wrong answers. This is because the requirements of a 'pure' object-oriented are fairly subjective. Public __gc class Class1 The online documentation refers to this __gc as a managed pointer. These are very nice in C++, because the garbage collector will automatically destroy these types of C++ objects for you.
You can call delete if you want, but from some testing that I performed, you don't have to explicitly. Eventually, the destructor will be called implicitly.
Wow— C++ with garbage collection! (Something else that is 'nifty:' you can also create properties with managed C++ code by using the __property keyword, where these properties behave similarly to C#'s version below.) I defined and implemented a few simple member functions, compiled my library, then created a C# Windows application by using the following procedure: • Open Visual Studio.NET (another instance, if you want). • On the File menu, click New Project.
• In the left pane, click Visual C# Projects. • In the Templates pane on the right, click Windows Application. • Set the Name and Location for the project. Then I imported the C++ compiled dll (all libraries are now dlls, which is actually good) into my C# project by using the following procedure: • Click Project/ Add Reference.
• Click the Projects tab (maybe not necessary? Seemed logical). • Click Browse. • Search for the dll built by the managed C++ project above and select it. I then created an instance of the C++ class in the C# project, compiled my project, and stepped through the code. It is very strange walking through C++ code in a C# project.
Very strange but very nice. Everything worked. The C# code seemed to have no idea that the object was created in C++— the way it's supposed to be. I then created a C# class called Class2 (nice name by me) which subclassed the C++ Class1(!), and implemented a non-virtual method in the latter and a new method with the same signature in the former. Creating a new instance of Class2 and assigning it to a Class1 reference and calling this method on the reference, sure enough, the C++ version was called correctly.
Modifying this method to be virtual in the base, and override in the subclass, recompiling, and running the code, sure enough, the C# version was called. Finally, I installed the plug-in for Visual Studio.NET, and created a J# library project similar to the method above for the managed C++ project. I imported the C++ dll into this project, and subclassed Class1 with a Java class, and implemented the virtual function implicitly. I then imported this J# dll into the C# project, ran similar tests with the new Java object, and the correct Java (implicit) virtual method was called in the C# code. I don't know much about Visual Basic, so I had to leave this for another day. I have written and modified some VBScript, but that is the limit of my knowledge.
I apologize to you Visual Basic developers.... It would be fun to play with this for a couple of days, and test to see if everything works correctly. I cannot say that everything does, but it sure is cool, and it sure is easy. I can imagine creating applications with multiple libraries, where each library uses the language that is 'most fit' for the specific problem, then integrating all of them to work together as one. The world would then be a truly happier place. C# Is a More Complex Language than Java It seems as if Java was built to keep a developer from shooting himself in the foot.
It seems as if C# was built to give the developer a gun but leave the safety turned on. And it seems as if when C++ was built, they just handed the programmer a fully loaded bazooka with an open-ended license to use it.
C# can be as harmless as Java using safe code, but can be as dangerous as C++ by clicking off that safety in unsafe mode—you get to decide. With Java, it seems as if the most damage that you can do is maybe spray yourself in the eye with the squirt gun that it hands you. But that's the way that the Java architects wanted it, most likely. And the C# designers probably wanted to build a new language that could persuade C++ developers, who often want ultimate firepower and control, to buy into it. Below, I will provide some proof to this argument that 'C# is a more complex language than Java.'
C# and Java Keyword Comparison Comparing the keywords in C# and Java gives insight into major differences in the languages, from an application developer's perspective. Language-neutral terminology will be used, if possible, for fairness. Equivalents The following table contains C# and Java keywords with different names that are so similar in functionality and meaning that they may be subjectively called 'equivalent.' Keywords that have the same name and similar or exact same meaning will not be discussed, due to the large size of that list.
The Notes column quickly describes use and meaning, while the example columns give C# and Java code samples in an attempt to provide clarity. It should be noted that some keywords are context sensitive. For example, the new keyword in C# has different meanings that depend on where it is applied. It is not used only as a prefix operator creating a new object on the heap, but is also used as a method modifier in some situations in C#. Also, some of the words listed are not truly keywords as they have not been reserved, or may actually be operators, for comparison. One non-reserved 'keyword' in C# is get, as an example of the former.
Extends is a keyword in Java, where C# uses a ':' character instead, like C++, as an example of the latter. Vector v = new Vector(); Vector v2 = new Vector(1,2,3); Vector v3 = v.addTwoVectorsAndReturnTheResult(v2); //You killed operator overloading! What can you say about the C# code above? Well, if you appreciate my coding style and operator overloading: 'Sha-weet.....' What can you say about the Java code above? If you like or dislike my coding style, it's most likely, 'You killed operator overloading!'
(Maybe worse. But this isn't some television show aimed at kids, so we can't use really foul language here.) And you might still swear uncontrollably even if I had used some reasonable method name such as add in the Java's version—the long method name was only used for effect. Program Tv Minimax Ierimonti there. While the C# code is completely natural to developers who have taken some math, the Java code is completely unnatural. While the intent of the C# client is immediately obvious, the Java client code must be inspected before the light bulb turns on. Some people may argue that operator overloading is not really important, and so it is not a 'biggy' that Java does not allow it. If this is so, why does Java allow the '+' operator to be used on the built-in class, then?
Why is the String class more important that any class that you or I build? So string operations are common, you may argue. But just by this example Java shows that it feels that operator overloading can be a good thing in some situations. I guess these situations only exist where Java has the control.
Why did Java omit operator overloading? I don't know. One thing that I do believe: it was a mistake. Operator overloading is very important because it allows developers to write code that seems natural to them. It could be and has been argued ad nauseam that 'operator overloading can be easily overused, so it shouldn't be allowed.' That would be like saying that 'cars are in accidents so let's make people walk.' People can and do make mistakes but it would be a bigger mistake to make them walk 20 miles to work every day.
If you can't trust programmers to make good decisions, then their code won't work anyway, even without operator overloading. Give me back my car— I get enough exercise when I run that stupid treadmill. And give me back my operator overloading— I get enough typing practice when I write these 'smart' papers. Delegate A delegate in C# is like a function pointer in C++. They are both used in situations where some function should be called, but it is unclear which function on which class should be called until run time. While both of these languages require methods to follow a pre-defined signature, each allows the name of the individual function to be anything that is legal as defined by its respective language. One nice feature of both C++ function pointers and C# delegates is how they both handle virtual functions.
In C#, if you create a base class that implements a virtual method with a signature matching a delegate, then subclass this base and override the method, the overriding method will be called on a delegate call if a base reference actually holds an instance of the subclass. C++ actually has similar behavior, although its syntax is more awkward. What is the motivation for delegates in C#? One place they come in handy is for event creation and handling. When something happens during program execution, there are at least two ways for a thread to determine that it has happened. One is polling, where a thread simply loops, and during every loop block, gains some lock on data, tests that data for the 'happening,' releases the data then sleeps for a while. This is generally not a very good solution because it burns CPU cycles in an inefficient manner since most of the tests on the data will return negative.
Another approach is to use a publisher-subscriber model, where an event listener registers for some event with an event broadcaster, and when something happens, the broadcaster 'fires' an event to all listeners of the event. This latter method is generally better, because the logic is simpler, particularly for the listener code, and it's more efficient, because the listener code runs only when an event actually occurs.
Java uses this model to handle events, particularly but not limited to classes associated with GUIs. A listener implements some well-defined interface defined by the broadcaster, then registers with this broadcaster for callback in case an event of interest occurs. An example would be a, which can register for item changed events in a box. Another would be a, which can listen for such events on a generic such as. When an event occurs, the broadcaster then calls the pre-defined interface method on each registered listener, and the listener can then do anything it wants. In C#, an event and a delegate are defined and then implemented by some class or classes, so that an event can be broadcast to anyone registering for this event.
Most if not all C# Controls already have logic to fire many different predefined events to registered listeners, and all you have to do is create a Control subclass instance, create a 'listener' class that implements a delegate, then add that listener to the Control's event list. But C# even allows you to create your own events and event handlers by using the following procedure: • Define and implement a subclass of System.EventArgs with any pertinent properties. • Define the delegate function prototype of the form public delegate void (object sender,EventArgs e) at the namespace scope. • Define a class that internally defines an event of the form public event and implement code that fires this event to its listeners when appropriate, by passing this and a new instance of the EventArgs subclass. • Define at least one class that implements the delegate method as a listener. • Create at least one listener and one broadcaster instance, and add the listener to the broadcaster's event list.
It should be noted that, in some cases, the listener implementation code may want to spawn another thread so that other listeners may also receive this event in a timely fashion in case this code performs any lengthy processing. It should also be possible for the class firing the event to spawn a thread. But in these scenarios, you must be careful to use synchronization techniques on both the EventArgs data and the object sender, since multiple threads may attempt to access these simultaneously. Just running some simple tests, it appears as if the delegate implementers are called in a queue-like fashion in which they were added, with the same parameter references, so take this into account. There are some differences in implementation between C# and Java in regards to creating, firing and receiving events, but overall, they are very similar since they both use a publisher-subscriber model. However, there are some very subtle differences, particularly in client implementation, that suggest some advantages and disadvantages in the approaches. One problem with the Java approach is that, while a single listener can register for events on multiple like-Components, the same method will be called on the listener regardless of which individual Component actually triggered the event.
This happens because the broadcaster references this listener as a well-defined interface, and only one method exists for each event type on that interface. So, if the same listener registers for events on more than one like Component, it must have some nasty if-then [else] (ITE) statement inside the event handler method to first determine which Component triggered the event in case the action to perform is Component-dependent, which is usually the case. In C#, however, a class that registers for some event can create one specific handler method for each Component that may trigger this event.
Why can it do this? Because methods implementing a delegate must follow the delegate's exact signature except it may use any method name that it wishes.
So C# avoids this problem. IMyClassPtr myClass(__uuidof(MyClass)); myClass->Number = 3; long l = myClass->Number; //l gets 3 (Grimes, pp 84-89. His Easter example was used as a template for this COM example.) As you can see, ATL code can be quite complex. To be fair, the ATL class wizards in any version of Visual Studio will do the majority of work for you under-the-covers by creating and modifying files such as definition (.idl), header (.h), implementation (.cpp), and registry scripts (.rgs), where these files will be nearly complete minus most implementation code (even these are stubbed for you). But attempting anything beyond the basics will require hand-modifying these files, which can be somewhat tricky, and requires near-expert knowledge of the inner details of COM. In contrast, the following equivalent example demonstrates how simple and elegant both C# class implementation and client code can be. MyClass m = new MyClass(); m.Number = 3; //m_int gets 3 long m = m.Number; //m gets 3 Which one is easier?
I'll let you make the call. I've made my choice. So why are properties important? They allow a developer to access private data indirectly in a natural way. Why is it important to access this data indirectly? It allows the developer of the class which exposes these properties to perform other 'bookkeeping,' such as locking and unlocking the private data, make other function calls, and so on, during the get and set functions, and hide this functionality from the client code. And it is possible to declare a property as virtual, so that a subclass can override the implementation of this property if it so chooses.
Another nice feature of properties: if a developer uses Reflection, he can access these properties more easily in a generic way. It is possible to use non-standard set and get accessor functions, but the syntax of these functions must be well-defined and negotiated beforehand for this to work without built-in language support. Some language extensions have simulated accessor functions by instructing classes to use the forms get_ and set_, which implies that properties are important, since support is simulated after a language definition is defined. Are properties necessary? Java doesn't supply this functionality.
(Although does, using the above simulation method. Even managed C++ does, too.) A developer can always use non-standard get and set accessor methods for variables.
But it supplies a standard way for client and server code to interact and pass messages. Enum User-defined enumeration types are not supported in Java. A technical explanation: Yikes. OK; maybe not enough said here. But this one irritates me a little bit.
While an enum should be used sparingly, because it doesn't really imply an object-oriented approach, there are situations where they make sense to use. They are very nice to use in situations where you don't want to create an entirely new class to describe data, particularly hidden inside a class where only a few options exist. While I would agree that they should be used sparingly, a language doesn't seem complete without them.
In the words of an entertaining and controversial talk show host, 'What say you, Java?' This C# allows indexers on classes, while Java does not. 'This' is a very nice feature, when a class is designed to hold some enumeration of objects. You may only define one indexer on any class, but this is actually a good thing to avoid ambiguity. So, if your class will hold several different lists of objects, then it may be best to not use this functionality. If it holds only one, then it makes sense to use indexers. There are some interfaces and functionality that a class needs to implement to support this functionality, and I recommend that you read the online documentation about indexers.
If you implement the correct interfaces on your class using this information, the client of your collection may apply the foreach statement on it, which is very nice. Struct Structs are allowed in C# but not Java.
While this is not really a big deal (just use a class), there are some good things about C# structs, including being more efficient in some situations. I recommend reading about the differences between a struct and a class in the online documentation.
I also highly recommend using a class instead in most circumstances. Think twice before committing your data to a struct. Then think about it again. Out/ref These keywords allow a callee control over side-effecting the reference to formal parameters, so that the caller will see the change after the call is made. This is different than simply side-effecting internal data that the reference holds; it also allows side-effecting what the calling reference actually refers to.
Examining the out keyword first, it is very similar to using a non-const 'pointer to a pointer' in a C++ function call. When the method is called, the address of the original pointer is side-effected, so that it points at new data. Where would this be useful? Let's say that you are coding in C++, and you need to create a function which accepts an array, returns the index of the largest element and sets a passed-in pointer to access the actual element in the array that is the largest, just in case the developer wishes to modify this array element later. Maybe not the smartest or the safest thing to do, but hey, it's C++: we can do whatever we want. MyProject.MyClass ClassProperty MyProject.PropertyClass... In C#, you could write code that would use the System.Xml.XMLDataDocument class perhaps, that loads and parses an XML document, then allows you to walk the DOM at runtime.
Every time that an node is seen, then a new object should be created using its fully qualified name. Every time a node is seen, then its parent node's property should be set to some newly created object that will be shortly defined.
And every time that a node is seen, then the parent object created should have the function, by name, called on it using the parameters that are later defined. This would allow you to create any object type that you want, and set properties and call functions for initialization, in a very recursive manner. The code that does this will be surprisingly small because it takes advantage of recursion and the generic nature of reflection. Naturally, this can be overdone. The compiler will not give you very much help when you use reflection in either language, because it has very little knowledge of what you are intending to do, what object types you will hold, and what functions you will call, until run time—almost everything is handled as the most abstract class, object.
And, sure, it can be slow; much slower that making direct calls on a well-known interface. But if you use reflection only at the time that data is created and initialized, then take this data and make direct calls afterwards perhaps by casting some object returned to some known interface or your own base class, then very dynamic and powerful code can be written that allows you to modify program behavior without recompiling—just modify the XML document and refresh will work in this scenario—while still enjoying an application that runs at a reasonable speed.
While C# and Java are very similar, there are some differences in packages and libraries used. As a C# example, you might use the following classes and steps to create a new class instance and call some function on this new object (we are assuming that no Exception is thrown during these steps for simplicity, which you should not do in your code unless you can absolutely guarantee correct behavior—and by 'absolutely' I mean agree to resign your cushy development position if it fails—at least this is what a boss once told me). It should be noted that there are many ways to do this, but this one will do: • Use one of the System.Reflection.Assembly class's static Load methods to return the correct Assembly which defines your class.
• Call the returned Assembly instance's CreateInstance function which returns an object reference to your newly created class instance, as long as the class to instantiate has a constructor with an empty parameter list. • With the returned new object, call its GetType method to return the run-time System.Type of this object. • With this Type object (a Type is an object!), call its GetMethod function by passing the name of the method as a string (and maybe the types of the parameters if the method is overloaded) which returns a System.Reflection.MethodInfo object. • Call this MethodInfo's Invoke function, by passing the new object returned from the Assembly.CreateInstance method above, and an array of object parameters on this object's function if necessary, and accept the object returned which represents the data returned from the dynamic invocation. Pretty simple?
It's actually not as bad as it sounds, particularly when you write code that handles creating objects and method calls in a generic way. Returning to our xml sample above, it would be possible to create one function that hides these details from us, so we only have to 'jump through some hoops' once by writing code that creates some object.
Here is an equivalent set of steps using Java: • Use the 's static method method, passing the fully qualified name of the class to create, and receiving a the Class object with name className. • With this Class object, call its method, which returns a newly created object of type className, as long as the type to create has a constructor with an empty parameter list. • With the Class above, call its function, by passing the name of the method and a list of parameter types to pass to the method and receive a object. • With this Method object, call its method by passing the newly created Class instance above, and an array of actual object parameters, and receive the return object from the call. I would recommend that you take a day or so to 'play' with reflection in either or both languages, just to see what you can do. It can be fun, and it can be powerful. Down the road, I guarantee that you will run into a situation where this feature can really make your programs more dynamic, and you will be glad that you know the basics so that you will be influenced to take advantage of this powerful language feature.
As Socrates once said: 'How can you know what you do not know?' I think that he was referring to reflection. One day now may save you weeks-or-more development time later if you are unfamiliar with this support and don't use it in your design early. While I have not experimented with the IDispatch functionality in COM above from a client's perspective, I have used reflection in both C# and Java, and they are very similar. From my experience, C# is a little trickier to 'get started,' because the System.Reflection.Assembly class is used first to load an assembly which defines and implements classes of interest.
With the fully qualified name only of some class to load, you may have to write some C# parsing code to search first for the Assembly part, get a reference to this Assembly, then use the Assembly with the full name to create an object. In Java, simply use the fully qualified name to create an instance of a class using class Class (nice name for a class?). Naturally, there are tradeoffs, once again. The Java code may be easier to create an object, but it also may be the case that the C# and CLR infrastructure are easier from an administrative viewpoint over the additional classpath information which must be configured in your system using Java, regardless of operating system. But once you have this new object, both languages seem to be similar when it comes to making dynamic function calls and setting properties, for example (of course, Java does not support properties directly, however). Hits and Misses Both C# and Java have taken a different approach to programming than many languages that have come before them.
Some of these are 'hits,' and some of these are 'misses' or near misses. And some things could still be improved. But the majority of changes are very good. What Have Both C# and Java 'Fixed?'
There are some things that both C# and Java have fixed. Some of them are listed below.
Boolean expressions C++, C#, Java, and other programming languages, support if statements of the form if (expression) statement1 [else statement2] While expression in languages like C++ can be nearly any expression, C# and Java require it to at least be castable to a Boolean type. So, the following for statement is legal in C++. Colors c = (Colors)4; then c will have the value of 4. It seems as if the compiler should be able to flag this particular line of code as an error at compile-time, because '4' is a constant, and the min and max elements in Colors are 0 and 2, respectively. Even if a variable were used where its value could not be known until runtime, it seems as if an exception should be thrown in this out-of-bounds scenario to guarantee that an enum type is truly 'type-safe.'
It's great that C# allows enum types. Java does not, which I still believe was a mistake.
And it's great that an enumeration variable may be set to a numerical value using a cast, for many reasons. But it should be possible to guarantee that enum variables are not set to illegal values, either at run time or compile time.
In the above example, a Colors variable holding the value of '4' seems to have no meaning. What does '4' mean? What do you do in the scenario where some calculation must be performed as a function of a Color whose value is '4'? It's not so clear. Why did C# allow this? Was it for interoperability issues?
I'm not sure yet. Just be careful. What Would Have Been 'Nice' Additions to Both C# and Java Const method and formal parameter keyword modifier It would have been very nice if both languages would allow the use of const as a method and formal parameter reference modifier, with the same meaning as C++. Since all objects in both C# and Java are references, if a parameter is passed by a caller and side-effected in a method by the callee, then the former will see any changes made to his data after the call is complete. Sure, many C++ developers have complained about the use of const in C++, arguing that the 'constness' of a parameter can be cast away anyway, making this functionality useless.
However, it seems as if a simple rule could be added to C++ stating that 'a const reference may only be cast as another const reference,' which could be tested at compile-time and eliminate this problem at runtime. If this is true, then C# and Java could have included this functionality with this modified rule as well.
In addition, an implied guarantee is only part of the contract between the caller and the callee anyway on a const function or parameter. Adding this const keyword gives a reminder to the caller and callee that the data is not supposed to be modified, which creates more self-documenting code. In particular, a developer following good programming habits will be reminded by the compiler with an error message if he is trying to modify const data. If he is trying to circumvent the rules, then he will be the one who suffers anyway, even if the compiler cannot catch the illegal operation.
Readability is an important part of coding. This is a reminder of the debate over functions that return multiple values by side-effecting input parameters, which in some scenarios is reasonable. Some developers prefer non-const references, while others prefer pointers. It can be argued that the latter is 'better.' Headington (p.
303) has two versions of a common swap function that will help me argue the point. Float a = 1.5; float b = 2.0; Swap(&a,&b); //calling the pointer version Swap(a,b); //calling the reference version Looking at the client code, the second Swap appears cleaner. But if you write client code using the pointer function instead, then return to inspect your code much later, you are reminded that your parameters may be modified during this pointer Swap function call because of the additional '&' character on the client side, which is important, in a good way.
However, the Swap(a,b) call gives no reminder to this effect, which may also be important, in a bad way. While both functions may be logically equivalent, it can be argued that the pointer method is 'better' because of the extra communication that exists between the client and the server code, and increased readability. After playing with managed C++ code, which is actually pretty interesting but beyond the scope of this paper, I realized that this new.NET functionality also disallows the use of const as a method modifier. I received the compile-time error message: 'const' and 'volatile' qualifiers on member functions of managed types are not supported.' And while it is legal to use the const modifier on a reference parameter, the constness must be cast away inside the method to make any method call on the parameter! Presumably, this is because the compiler cannot guarantee that any method called on the object address will not modify the object or its data since the const modifier is disallowed on instance methods, noted above.
This begs the question: is it a waste of time to use the const modifier on reference parameters while using managed C++ code? The answer: not completely, as long as the class designer and implementer takes the above restrictions into account by defining, through comments, if an instance method should be in fact a const member function. Then if a const parameter address is received by a method, the developer can 'safely' cast away the constness but call only simulated const methods on the object. This way, if managed C++ code is eventually ported back to unmanaged code, then the comments could be removed and the classes will work as designed, minus removing that nasty cast, of course.
I realize that this advice immediately opposes my advice above: don't cast away the constness of a formal parameter address. But in my opinion, this does not break the 'spirit' of the original advice, because the class builder still guarantees that the client data will not be modified, although this guarantee is now made by human inspection rather than compiler logic. And it is a workaround to a limitation that allows greater ease of future C++ portability, if necessary. All this leads me to believe that there may be some language interoperability issues that forced Microsoft's hand, because a const method must be negotiated by both caller and callee, but a const parameter address really only needs to be guaranteed by the latter (the C# code calling a method written in C++ couldn't care less about the const reference anyway, for example, since this can't be done in C#).
If all this speculation is true, then I am assuming that Java may also have had the same problem during initial design since, even though it is trickier, Java can call functions written in other languages. Maybe managed C++ should have allowed the const modifier on an instance method with the understanding that the developer was in charge of verifying that no change is made to the internal data. Or maybe the const keyword should have been disallowed as a formal parameter modifier.
I don't know. From a portability standpoint, the former solution might have been a better choice. From a behavioral viewpoint, the way that managed C++ works now makes some sense, since it works as designed. At any rate, this seems to be somewhat inconsistent, allowing const parameters but disallowing const instance functions with managed C++. I would recommend reading information about Cross-Language Interoperability in the online documentation. I know that I am going to have to now look into this some more myself...
Access modifiers for class inheritance Languages like C++ allow the use of class access modifiers while using inheritance.