Pardon me for flogging a dead horse here, but I'm trying to understand as clearly as possible some issues pertaining to the instantiation of objects.

Firstly, have I correctly analyzed the functions and uses of each of the various syntaxes related to instantiating objects? Please don't flame me, saying "why don't I read the documentation". I've read it thoroughly. The point is I want to understand the material in finer detail than for which I can find documentation.

To declare an object [create an object variable to hold a reference ("handle") of an object of the required class type]:

ClassName ObjectName;

(Am I not correct that a handle is simply an address?)

To instantiate an object (allocate space for it in the heap):

new ClassName ();

When an object is instantiated, it is usually within the same statement "assigned" to an object variable (see immediately below). This "assignment" means the reference of the object is placed into the object variable to make the variable "point to" the object. However, this reference may instead be returned to a calling method without assigning it to an object variable.

To instantiate an object and assign it to an object variable within a single statement:

ObjectName = new ClassName ();

To declare an object (variable), instantiate an object and assign the object to the object variable within a single statement:

ClassName ObjectName = new ClassName ();

To assign the reference of an object held by one object variable to another object variable (to make both object variables point to the same object):

ObjectName2 = ObjectName;

Secondly, what is the precise relationship of arrays and structures to classes and objects?

Objects are instantiations of classes, and as such are reference-type variables, space for which is allocated in the heap, not on the stack.

struct is said to be a "lightweight" form of class, and structures, like objects, must be instantiated. But structures can be instantiated without use of the keyword "new" (unlike classes), which means that no constructor is executed when structures are instantiated in this way.

Also, structures are of value-type, and so space for them must be allocated on the stack, not in the heap. Plus, like all value types, structures lack inheritance functionality.

So are structures objects or not?

I have read that arrays ARE objects. They also can be instantiated without use of the keyword "new", but only if they are also initialized (and sized) within the same statement:

DataType [] ArrayName = { < element list > };

In this case, it must be that, as with structures, no constructor is executed.

In addition, although the individual elements of an array may be of a user-defined data type, an array itself is never an instantiation of a user-defined data type (I think). Furthermore, like structures, arrays lack inheritance functionality.

So are arrays really objects? They seem so different from other objects.

And just as a matter of curiosity:

Arrays are inherited from the System.Array class. But ALL data types in C#, even value types including implicit types, are implicitly inherited from the System.Object class. (Of course, that doesn't mean all variables, regardless of data type, are objects.)

So is the System.Array class inherited directly from the System.Object class? (For that matter, is there any way I can actually read the namespace files?)

Recommended Answers

All 10 Replies

What is your definition of "object"? Things are what things are.

In .NET 2.0, arrays, in particular, are essentially full-blooded objects in the way that List<T>s are full-blooded objects. They have some weird constructor syntax (with initializer lists and new string[n] syntax) but they are the same kind of thing.

Really, you could say (1) that arrays have weird constructor syntax, and (2) that other types have a different weird constructor syntax

In pre-2.0 versions of .NET, arrays were special because they were parameterized on the type they held.

You can't inherit from arrays, but you can't inherit from any other sealed class anyway.

There are basically two kinds of types in C#: reference types and value types. Reference types can be null and you work with them by copying references to some (possibly mutable) object. Value types cannot be null and their values are immutable in the way that strings are immutable.

To start with the first issue :

(Am I not correct that a handle is simply an address?)

A handle is as far as I know an address to an address or if you like a pointer to a pointer.

A handle is as far as I know an address to an address or if you like a pointer to a pointer.

What are you talking about.

What are you talking about.

Give me your definition of a "handle".

I don't know of any such notion as "handle".

Now here's the rest of my reply to the original poster:

I think things are best made clear here by defining the relationships between things completely, so here are the definitions I follow:

A type can either be a reference type or a value type.

A class is a set of code that defines a reference type.

A struct is a set of code that defines a value type.

A reference is a memory address.

A constructor is a static function whose name is the same as the type of its return value. You need to use weird syntax to define and call this function.

A variable is a small piece of memory -- enough space to hold a value of the variable's type (which is known at compile time).

A value is, perhaps, something representable by a particular pattern of bits, or a number. A value is not some "thing" that can be modified. It has been stated that a variable is a piece of memory that can contain a value. This piece of memory can be overwritten, but a value itself is immutable. Again, you can overwrite variables, but you can never change values. For example, a variable of type int can contain the value 3, and then it can be overwritten with the value 5. A variable of type string can contain the value X, and then it can be overwritten with the value Y---where X and Y are references to some string object.

References are values. (You can modify some variables in the object that the reference refers to, but you can't modify a reference. You can modify a variable that contains a reference.)

References are either the value null or some value that represents a memory address.

For any type T, the type T[] is a reference type.

object is a reference type.

If the type of the variable x is a value type, then the expression (object)x (or any implicit conversion) will put a copy of the value of x on the heap and return a reference to that copy. (This is called autoboxing.)

If the type of the variable x is a reference type, then the expression (object)x (or any implicit conversion) will return the value of x.

If the type of the variable x is object, and if T is a value type, and if x's value is a reference to a value of type T, then the expression (T)x will return that referenced value. (This is called autounboxing, I guess.)

One more thing: A delegate type declaration defines a reference type.


With these relationships in mind, you'll note that the type T[] is treated under C#'s system no differently than other reference types. For example, the constraint "X : class" where X is some type is satisfied by T[]:

// This is a terrible code example, by the way.
class Foo<T> where T : class
{
    T blah;
    Func<T> func;
    public Foo(Func<T> func)
    {
        this.func = func;
        blah = null;
    }
    public T Get()
    {
        if (blah == null)
            blah = func();
        return blah;
    }
}

You can make a new Foo<int[]>(() => new[] { 2, 3 }) without any problems.

----

(One thing I've avoided mentioning is the name of the _thing_ that is _at_ the memory address of a reference. What is there? Why, a bunch of variables! What is it called? The "object that the reference is referring to"? The "instance"? I suppose "the instance" is a reasonable sounding thing to say, but I feel like the word "instance" is such a silly word, because it leads to the question "An instance of what?" And then some people will say "an instance of the class", but that's just silly---a class is just something that defines a type -- you shouldn't care whether the type's defined by a class or a delegate declaration or some other language feature. It's wasteful and taxing for your mind to come up with all these definitions and keep track of them, so instead of saying "instance", I recommend saying the reference points to a bunch of variables 'n stuff. You don't really care what's there -- what's important to understand is that some of what's there are variables that can be overwritten.)

Since that's a terrible code example, I better put the good version or else some noob will come along and copy and paste the bad version.

public class Memo<T> {
    T cached = default(T);
    Func<T> memoizee;
    public Memo<T>(Func<T> memoizee) {
        this.memoizee = memoizee;
    }
    public T Get() {
        if (memoizee != null {
            cached = memoizee();
            memoizee = null;
        }
        return cached;
    }
}

Glad to hear that you have no such notion as "handle".
It is one of the reasons wich pointed me to C#.
Only val and ref. Nice.

Further I am amazed by the way you formulate your answers. I don't know how you can do it in such short time. Besides your knowledge it must be because english is your native tongue, I think.

attention, Rashakil Fol:

Too much good stuff there for me to digest at the moment - I'll study it. Thanks.

...note that the type T[] is treated under C#'s system no differently than other reference types. For example, the constraint "X : class" where X is some type is satisfied by T[]:

public class Memo<T>
{
    T cached = default(T);
    Func<T> memoizee;
    public Memo<T>(Func<T> memoizee)
    {
        this.memoizee = memoizee;
    }
    public T Get()
    {
        if (memoizee != null
        {
            cached = memoizee();
            memoizee = null;
        }
        return cached;
    }
}

Sorry, I don't understand. By ' the constraint "X : class" ', are you referring to either inheritance or implementation of an interface? Perhaps you're talking about some part of the C# language I haven't studied yet.

Plus, if you have the time maybe you could explain your code in some detail. I'm just not seeing what you're trying to show me.

Suppose you have some function to get the maximum element of an array:

public static T Max<T>(T accum, T[] array)
{
    foreach (T elem in array)
        accum = accum.CompareTo(elem) < 0 ? elem : accum;
    return accum;
}

This function won't compile. The reason is that there's no guarantee that the type T has a CompareTo method. We could write a function with the type public static IComparable Max(IComparable accum, IComparable[] array); , but that would be no good for finding the maximum element of an array of ints, because an int[] cannot be converted to an IComparable[] (without copying all the elements). We need some way of saying that T is an IComparable (or better yet, an IComparable<T>). You do that using a where clause:

public static T Max<T>(T accum, T[] array) where T : IComparable<T>
{
    foreach (T elem in array)
        accum = accum.CompareTo(elem) < 0 ? elem : accum;
    return accum;
}

Now here's an example with "T : class". Suppose we just want the maximum element of an array, without the accum parameter. If the array is empty we'll just return null. We might try to write something like this:

public static T Max<T>(T[] array) where T : IComparable<T>
{
    T accum = null;
    foreach (T elem in array)
        accum = accum == null || accum.CompareTo(elem) < 0 ? elem : accum;
    return accum;
}

This won't compile. The reason is, the type of the function implies that you could pass in an int[] or any other value type array -- but you can't assign null to an int. So you need another constraint that says T is not a value type:

public static T Max<T>(T[] array) where T : IComparable<T>, T : class
{
    T accum = null;
    foreach (T elem in array)
        accum = accum == null || accum.CompareTo(elem) < 0 ? elem : accum;
    return accum;
}

This "class" constraint (along with the "struct" and "new()" constraints) is a magic C# (or maybe .NET) feature.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.