C++ and Java Gumption Traps
It's time for another break from theory and on to some real world programming
challenges. In this chapter, you take a detour into the world of gumption traps.
A gumption trap is a situation that is so frustrating that it sucks the "gumption" or
energy out of you. Surprisingly, a lot of gumption traps come from preconceived
notions of what "should" be correct. C++ and Java programmers are
prone to gumption traps due to their assumptions about the C# language. In
other words, C++ and Java programmers have a bit of "language baggage" that
needs to be left behind. So, if you have a language neurosis, this chapter
is for you.
Top Ten C++ Gumption Traps
In no particular order.
1) Arrays in C# are Objects
In C#, arrays are objects derived from System.Array. The following code snippet
creates an array object that can contain ten elements of MyClass:
MyClass[] arrayMC= new MyClass[10];
What may surprise you, is that this call does not create any instances of
MyClass! In fact, if you iterate over the array, you will find that the array
contains ten null elements. To fill the array, you must explicitly create ten
instances of MyClass and fill the array:
MyClass[] arrayMC= new MyClass[10];
[STAThread]
static void Main(string[] args)
{
//
// TODO: Add code to start application here
//
Class1 c1= new Class1();
for (int i=0; i<10; i++)
{
c1.arrayMC[i]= new MyClass();
}
Console.ReadLine();
}
2) Declaring an Object Simply Creates an Un-initialized Object Variable
In C++, when you declare an object, the object is created. Not so in C#.
The following code simply declares an un-initialized reference variable
of Type
MyClass. The variable occupies memory on the stack to hold an address.
No object is created on the heap. If you try to use c, the compiler will
complain
that the variable has not been initialized.
MyClass c;
The following code snippet, creates a variable and initializes the variable
to null, so that the reference does not refer to any object. If you try to
use the reference variable to touch a field or method of the class, the code
will throw a null reference exception.
MyClass c= null;
So, if you want to declare and initialize a reference variable and create
an object in C# you must use the new keyword like this:
MyClass c= new MyClass();
"c" is now a reference variable of Type MyClass. If this is a local
variable, then "c" uses memory on the stack which contains the address
of an object of Class MyClass on the heap.
As discussed earlier, the string class (strings are immutable and shared)
is an exception to the rule. You can create a string like this:
string s= "Hello";
3) C# Uses Automatic Garbage Collection, Destructors are not Deterministic
The call to new may bother a C++ programmer who may now feel obligated to call
delete appropriately. All I can say is lighten up! Objects are (mostly) reclaimed
automatically in C#. In a nutshell, when available memory falls, the garbage
collector is called, freeing up any objects that are unreachable. If you
are done with an object, you can assist the garbage collector by releasing
all references to the object. Even if two objects contain references to each
other (circular references), the objects can still be collected if they become "unreachable."
Since objects in C# are garbage collected, it is not a good idea to reclaim
resources in the destructor. A destructor will not be called until the object
is reclaimed by the garbage collector. In other words, destructors are not
deterministic in C#. Critical external resources are best released by inheriting
from IDisposable and implementing the Dispose method, or by using C#'s try,
catch, finally construct to insure that any allocated resources are reclaimed
in the finally clause. Here is a twisted example of try, catch, finally in
C#:
try
{
OpenToiletLid();
Flush();
}
catch(OverflowException e)
{
CallPlumber();
}
finally
{
CloseToiletLid();
}
4) The Assignment Operator Does Not Call the Copy Constructor
This one really confuses a lot of coders. In C# the assignment operator simply
assigns a reference variable to an existing object, to a new object, or to
null. After the assignment, the reference variable contains a reference to
an object or to no object (is null). The assignment operator does not call
the copy constructor to create a new object. It is quite legal in C# to have
two reference variables that contain references to the same object. The two
variables occupy different memory locations on the stack, but contain values
that point to the same memory address on the heap. Both references would have
to be released (e.g. the reference variables go out of scope, be reassigned,
set to null) before the object can be reclaimed. As a result, the "destructor" will
only be called once. The following code simply creates two references to the
same object:
MyClass c1= new MyClass();
MyClass c2;
c2= c1;
bool isSameReference= (c1 == c2); // c1 and c2 contain references to the same
object on the heap
Console.WriteLine(isSameReference.ToString()); // output--> true
Be clear that if variable c1 contains the only reference to an object, setting
c1 to null or reassigning c1 to another object will make the original object
unreachable and eligible for garbage collection.
5) Values and References to Objects are Passed By Value
By default, objects in C# are not passed by reference. (Unlike Java, C# does
support passing by reference using the ref keyword.) In C#, you pass a
reference or a value to a method. You cannot pass an object to a method.
By default,
all calls to methods are by value. Now is that clear! In other words, you
pass a reference to an object to a method, not the object itself. The reference
is passed by value so that the a copy of the reference goes on the stack.
The
key here is that the object is not copied onto the stack and you can touch
the object while inside the method. If you want to truly pass an object
by reference (for a swap routine) use the ref keyword. Remember, you cannot
pass an object, so you are actually passing a reference by reference. Oh,
I have
a headache.
6) Const is Hard Coded Into the Caller and not Version-able
I find this one a bit weird. A const field value is hard coded into the
caller for optimization so that the value is not updated until you
recompile the
caller. If you want to version-able read only field declare it readonly.
Finally, you
can provide a get only Property like this:
public string ModelName
{
get
{
return modelName; // danger, return ModelName --> stack
overflow!
}
}
7) Supports Single Inheritance of Implementation and Multiple Inheritance
of Interfaces
C# does not support multiple inheritance of implementation. It does support
multiple inheritance of interfaces (pure virtual classes) and single inheritance
of implementation.
8) Program to Return Single Values
Although C# does support an out parameter, in general, C# programs are designed
to return single values. Consider redesigning your application or returning
immutable objects.
9) Strings are Immutable
The string class is a very special class. First strings are immutable. Every
time you concatenate a string, you may be creating a new string object. If
you want a mutable class, use StringBuilder. Second, you can create a string
object using the assignment operator. Third, strings are shared so that two
strings that you create may occupy the same space in memory. Fourth, the
equality operator is overloaded for string and checks for content equivalence,
not "reference based equality."
Note: The overloaded string equality operator only works on reference variables
of Type string. Be careful! Thanks to Jon S. for this insight.
object a= "Hello";
object b= "Hello";
bool isSameReference= (a == b); // test if a and b contain references to the
same object or to no object (are both null)
bool isSameContent= ((string)a == (string)b); // test if string referenced
by a and string referenced b have the same content/value or a and b are both
null
Session["KEY"]="VALUE"; // Error! The left hand operand
is of type object! This is a reference based comparison. Do this:
(String)Session["KEY"]="VALUE"; // content equivalence
10) bool is a Value Type
C# has a built in type for Boolean which can have a value true or false.
The default value of bool is false. Enough said.
Top Ten Java Gumption Traps
In no particular order.
1) No Checked Exceptions
The compiler in C# will not enforce catching of any checked exceptions. So
there is no support for declaring a checked exception (no throws keyword).
2) All Methods are Not Virtual By Default. All Members are Private by Default.
In Java, all methods are virtual by default and can be overridden. Not so
in C#. You must explicitly declare a method virtual if you want it to allow
it to be overridden. You also cannot implicitly override or hide a virtual
method, but must explicitly use the override or new keyword. In Java, members
have package level access by default. In C# all members are private by
default.
3) Const, ReadOnly and Get Only
I find this one a bit weird. A const field value is hard coded into the caller
for optimization so that the value is not updated until you recompile the
caller. If you want to version-able read only field declare it readonly.
Finally, you can provide a get only Property like this:
public string ModelName
{
get
{
return modelName; // danger, return ModelName --> stack
overflow!
}
}
4) All Types in the NET Framework Derive from Object
C# has a unified type system so that all reference and value types derive
from Object. For instance, int is an alias for System.Int32. As a result,
you
can call ToString() on any value or reference type. This simplifies debugging
in the Console mode.
5) The Visual Studio IDE Startup Object is Empty By Default
If the startup object string is empty and you declare more than one "Main" method
in a Visual Studio project, the project will not compile. This is very frustrating.
Trying to set the startup object property in the Visual Studio IDE is non-trivial.
Let me save you some pain. To set the startup object, select View --> Solution
Explorer. In the Solution Explorer window select the name of the project. Now
select View --> Property Pages. (Do not select the Property Window!) Alternatively,
right click on the project name and select Properties. Now select the Common
Properties folder in the left window. You can now select the appropriate startup
object from the drop down list. Don't forget to click on "Apply."
6) Method Names Start with Upper Case
This one is pretty self explanatory.
7) Getters and Setters are Implemented Using Properties, Which are Upper Case
C# formally supports the concept of getters and setters with Properties.
Note that properties are upper case by convention. Here are the setter
and getter
methods as properties:
// Properties
public int SecondsToToast
{
get {return secondsToToast;} // danger, return SecondsToToast --> stack
overflow!
set
{
if (value > 0)
{
secondsToToast= value;
}
else
{
secondsToToast= 0;
}
}
}
The reserved word value is used to represent the caller’s input. Note
the syntax used to call a property. To set a property use:
t.SecondsToToast= 12;
8) Use "is" instead of "instanceof", ArrayList
instead of ArrayList/Vector, StringBuilder instead of StringBuffer, Hashtable
instead
of HashMap/Hashtable, System.Environment.NewLine instead of line.separator..
Just trying to save you some headaches.
9) There is an "enum"
Java evolved before the concept of type safe enum. C# has built in support
for type safe enums like this:
public enum ColorType {Black, Red, Yellow, White};
private static ColorType DEFAULT_COLOR= ColorType.Black;
You can still create a custom enum in C# like this:
sealed class MyEnum
{
private String name;
private static int nextOrdinal= 1;
private int ordinal= nextOrdinal++;
private MyEnum(String name)
{
this.name= name;
}
public override String ToString()
{
return name;
}
public int ToOrdinal()
{
return ordinal;
}
public static MyEnum INVALID= new MyEnum("Invalid"); // ordinal
1
public static MyEnum OPENED= new MyEnum("Opened"); // ordinal 2
public static MyEnum CLOSED=new MyEnum("Closed"); // ordinal 3
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
//
// TODO: Add code to start application here
//
Console.WriteLine(MyEnum.OPENED.ToString());
Console.WriteLine(MyEnum.OPENED.ToOrdinal().ToString());
Console.WriteLine(MyEnum.INVALID.ToString());
Console.WriteLine(MyEnum.INVALID.ToOrdinal().ToString());
Console.WriteLine(MyEnum.CLOSED.ToString());
Console.WriteLine(MyEnum.CLOSED.ToOrdinal().ToString());
Console.ReadLine();
}
}
10) String Equality Operator is Overridden for Content Comparison
Thankfully, the string equality operator in C# has been overloaded and checks
for content/value equivalence. One less gotcha for the C# novice.
Note: The overloaded string equality operator only works on reference variables
of Type string. Be careful! Thanks to Jon S. for this insight.
object a= "Hello";
object b= "Hello";
bool isSameReference= (a == b); // test if a and b contain references to the
same object or to no object (are both null)
bool isSameContent= ((string)a == (string)b); // test if string referenced
by a and string referenced b have the same content/value or a and b are both
null
Session["KEY"]="VALUE"; // Error! The left hand operand
is of type object! This is a reference based comparison. Do this:
(String)Session["KEY"]="VALUE"; // content equivalence
OK, boys and girls. It's not your father's language. Get over it<g>.
The Equality Operator Revisited
Thanks to Jon S. I have revisited the concept of equality on operands of
the reference type. The equality operator, in general, compares operands
by reference.
The string equality operator is overloaded to compare operands by value.
In plain English, the equality operator normally checks to see if two object
variables refer to the same object on the heap. The string equality operator
is overloaded to check for content or value equivalence.
In not so plain English, the equality operator normally checks to see if two
reference variables contain references to the same object on the heap. In C#
local reference variables go on the stack and contain the address of the object
on the heap. So local reference based equality in C# checks to see if two reference
variables, stored on the stack, contain addresses which are equal. In other
words, it checks for address equality. This is referred to as "reference
based" equality or "compare by reference" or "referential
equality". Whew!
As previously stated, the string equality operator is overloaded to check
for value or content equivalence. In not so plain English, the string equality
operator compares the content or value of string objects on the heap. It does
this by obtaining the address of the objects from the values of the reference
variables stored on the stack.
Now I would like to simplify this discussion to that of "object" equality
vs. "content" equality, but I cannot! By convention, object equality
refers to content equality! I would also like to reduce this discussion to
referential "equality" vs. content "equivalence", but I
cannot. Unfortunately, by convention, the Equals() method is used to determine
content equivalence!