tags:

views:

1070

answers:

4

I am making a Color class, and provide a standard constructor like

Color(int red, int green, int blue)

And then I want to provide an easy way to get the most common colors, like Color.Blue, Color.Red. I see two possible options:

public static readonly Color Red = new Color(255, 0, 0);

public static Color Red { get { return new Color(255, 0, 0); } }

What I don't fully understand is if there is an advantage of one over the other, and how exactly the static keyword works. My thoughts are: The first creates one instance, and then that instance stays in memory for the entire duration of the program, and every time Red is called, this instance is used. The latter only creates something when first used, but creates a new instance every time. If this is correct, then I would argue that if I supply a lot of predefined colors, then the first would use a lot of unnecessary memory? So it is memory usage vs the runtime overhead of instantiating an object every time I guess.

Is my reasoning correct? Any advice for best practices when designing classes and use of the static keyword would be great.

+3  A: 

Your reasoning and identification of the trade-off seems sound. If you look at the System.Drawing.Color structure, you'll see it uses the second technique. The overhead of initializing a new struct is trivial, so this is probably better than having a large number of known colors pre-created.

I would expect Color to be an immutable struct. But if you're planning to create a class, you'd want to ensure it's immutable if you decide to use the first technique.

Joe
I'll comment rather than duplicating what is said here. If you can't use System.Drawing or System.Windows.Media then mimicking their designs is probably the best way forward. For something simple you should use a struct.
Nidonocu
+1  A: 

One note I'll add about using static is that you should make sure not to abuse it for doing things such as storing global data.

The pattern if you do need global data at least in WPF is to have a static property that refers to a non-static instance of its self. eg Application.Current. This is the pattern that I have duplicated for my applications.

Nidonocu
A: 

It is as you say the first will create create only one instance of the color:

public static readonly Color RED = new Color(255, 0, 0);

Under the hood I believe that in runtime it will only be instanciated on when it is called for the first time. But I haven't checked it for myself in a debugger though.

And as you say with the static getter alternative, that you're providing an implementation of, will fill up the heap uneedingly as you're calling it. The reason is that each invocation will create a new object.

If you really want to go for the getter alternative but not fill up the heap then at least make the creation of the Color class static as well. Like this:

private static readonly Color RED = new Color(255, 0, 0);
    // RED is created once when it is invoked for the first time.

public static Color Red { 
    get { 
        return RED; 
            // Will return a created RED object or create one 
            // for the first time.
    } 
}
Spoike
Static initializers are run the first time the _class_ is referred to, not the first time the _field_ is referenced. Accessing Color.Red, if it were the first time the Color class was used, would initialize Color.Green, Color.Yellow, etc., too.
P Daddy
+5  A: 

I'm guessing that you're probably already aware that the framework provides a Color struct. I'm guessing that you're creating a Color class just for practice.

You expressed uncertainty about the meaning of the static keyword, although you've used it correctly. When static is applied to a member of a class or struct, it means that that member belongs to the class as a whole, and does not apply to individual instances. Static data members (fields) are created only once; instances do not get their own copies. Static functions (methods and properties) are called without an instance reference.

As far as memory usage goes, I wouldn't worry too much about it in your case. Your Color class shouldn't use more than a few bytes per instance (for instance, the framework's Color structure stores red, green, blue, and alpha in one 32-bit int.). If your Color is a really a class instead of a struct, then you'll have a few more bytes in overhead (each instance will have an additional 32-bit v-table/typeinfo pointer, and each reference is an additional 32-bits), but even so, you're talking about 12 bytes or so per instance. If you have 100 different colors predefined, you'll use <= 1200 bytes. Really no big deal.

There are reasons for lazy-instantiation, though. There are classes that do use a lot of memory, and ones that hold on to limited system resources, and ones that take a long time to construct themselves, etc. For these classes it's sometimes better to use a pattern like:

class Heavy{
    static Heavy first;
    static Heavy second;

    public static Heavy First{
        get{
            if(first == null)
                first = new Heavy();
            return first;
        }
    }
    public static Heavy Second{
        get{
            if(second == null)
                second = new Heavy();
            return second;
        }
    }
}

Another consideration is mutability. Is your Color class mutable or immutable? In other words, can instances of your class have their value changed, or do they always, once created, represent the same value?

If your Color is mutable, then the only correct way to have a static "Red" accessor would be your second example, where you create a new one every access. That way someone can't do something like:

Color.Red.G = 255;

and make the single shared Color.Red instance actually represent yellow, instead.

But also keep in mind that in a case like:

for(int y = 0; y < bmp.Height; y++)
for(int x = 0; x < bmp.Width; x++)
    if(bmp.GetPixel(x, y) == Color.Red))
        MessageBox.Show("Found a red pixel!");

A lot of instances of your Color class are going to be created. They'll be garbage collected later, of course, but this is still a case argument for your first construct above (or the "Heavy" example I gave).

Now if your Color is actually a struct, then it's a slightly difference story. There's no heap allocation when you new a struct, and there's no v-table or reference pointer, so the real consideration is then just how long your constructor takes.

P Daddy
Excellent answer! Removing mine, upvoting this.
Shog9