Wednesday, September 07, 2005

Why is non-virtual the default in C++ and C#?

Question:
Why are instance methods non-virtual by default in C++ and C# as opposed to Java where the default is virtual?

Answer:
Source of this answer: http://www.artima.com/intv/nonvirtual.html.
I quote the The C# language designer verbatim as he has explained it in quite a lucid manner.

1. Performance:
When people write code in Java, they forget to mark their methods final. Therefore, those methods are virtual. Because they're virtual, they don't perform as well. There's performance overhead associated with being a virtual method.

2. Versioning:
Here is a very real world versioning problem, one that indeed we see now from experience with Java. Whenever they ship a new version of the Java class libraries, breakage occurs. Whenever they introduce a new method in a base class, if someone in a derived class had a method of that same name, that method is now an override—except if it has a different return type, it no longer compiles. The problem is that Java, and also C++, does not capture the intent of the programmer with respect to virtual.

When you say "virtual," you can mean one of two things. If you did not inherit a method of the same signature, then this is a new virtual method. That's one meaning. Otherwise it is an override of an inherited method. That's the other meaning.

From a versioning perspective, it is important that the programmer indicate their intent when they declare a method virtual. In C#, for example, you must explicitly indicate which meaning of virtual you intend. To declare a new virtual method, you just mark it virtual. But to override an existing virtual method, you must say override.

As a result, C# doesn't have the particular versioning problem I described earlier in which we introduce a method in a base class that you already have in a derived class. In your class, you would have declared foo virtual. Now we introduce a new virtual foo. Well, that's fine. Now there are two virtual foos. There are two VTBL slots. The derived foo hides the base foo, but that's fine. The base foo wasn't even there when the derived foo was written, so it's not like there's anything wrong with hiding this new functionality. And things continue to work the way they're supposed to.

Thursday, September 01, 2005

critical sections - mutexes and semaphores

Mutex:
  1. Mutual Exclusion object that blocks simultaneous access to a shared resource.
  2. Locks a shared resource, if already being acessed. Any attempt by other thread to access the shared resource would simply block.
  3. Guards critical section i.e. part of code where shared resource is accessed and may be modified.
Semaphore:
  1. A visual signaling apparatus with flags, lights, or mechanically moving arms, as one used on a railroad :)
  2. Mutual Exclusion + Synchronisation + Signalling + Counting
  3. Can be used as mutex.
  4. Multiple threads if simultaneously try to access a shared resource, which they may modify, may be synchronized using a semaphore. When the first thread arrives and enters critical section then simultaneously if other threads also try to enter the critical section, they are sequentially queued (FIFO) into wait state by the semaphore object implementation. When the first thread in critical section would leave it, semaphore would update count, and signal next i.e. second thread to enter the critical section. Thus shared resource access is synchronized / serialized sequentially.
  5. Maybe slower than mutex, as extra implentation is involved.

critical sections - thread-safety and re-entrancy

Re-entrant function definitions:
  1. Code which can have multiple simultaneous, interleaved, or nested invocations which will not interfere with each other.
  2. A function is reentrant if, while it is being executed, it can be re-invoked by itself (recursion), or by any other routine, by interrupting the present execution for a while.
Thread-safe function definitions:
  1. A description of code which is either re-entrant or protected from multiple simultaneous execution by some form of mutual exclusion.
  2. A function which can be called simultaneously by multiple threads when each invocation references shared data.
Comparisons:
  1. Re-entrancy is stronger condition of the two (Thread-safety and Reentrancy).
  2. Thread-safety guarantees mutual exclusion or serialized access of shared resources that may be modified. Re-entrancy guarantees no shared resources or just read-only access to shared resources and maintenance of local state for every re-entry.
  3. Every re-entrant function is necessarily thread-safe, but vice-versa is false.