Advertisement

C# Workshop - Week 1 (Ch. 1 & 2) - Advanced

Started by July 01, 2007 12:15 AM
337 comments, last by paulecoyote 17 years, 2 months ago
Regarding properties, I'd like to give an example of properties used for more than just returning and setting a field with = value. If hiding the name of the private field would be the only reason for the existence of properties... well that's quite a sorry excuse for existing. Yes, private fields can change names, but so can properties. Oh no, what should we do? Add another property which just calls the first property just in case?

One use for properties is to be able to add "redundance". Rather limited example: consider a Person class whose instances have to provide both the age and the birthday date of the person they represent.

Three designs:

1) You could store both as fields, but then you have to deal with redundance, i.e. there are constraints which have to hold, otherwise the data is just incoherent, e.g. having a birth date with year 2000 and be 35 years old (in 2007). Internally, it's always best to keep this kind of redundance away (one reason for redundancy is efficiency, but let's not take that into consideration). This invariant (age == current_year - birth_year) needs to be preserved by all methods, this might be complex and it's easy to forget to make sure all involved fields are updated correctly.

2) You could store the age, and compute the birth date from the age (let's pretend this is possible, e.g. the age could be a float which tells your age to the day). Hence, you have one field _age, one property Age which just returns _age's value, and one property BirthDate which computes the birth date each time it is called.

3) Store the birth date: field _birthDate, simple property BirthDate and computed property Age.

These are three designs, but they all have the same public interface: BirthDate and Age. From the outside, you can't know how they're implemented, which are computed and which are not. The class just guarantees that their values will be coherent. How the class does this, does not matter to the client.

If you're using design #3, and Age happens to be called quite often, you could optimise the program by switching to either design #1 or #2. Clients will be unaffected, and your code will run faster. These are the wonders of abstraction.
With a ref you can use the passed-in variable immediately in the function.
With an out, you must assign a value to that variable before using it. That's the subtle difference between the two.

To illustrate the point:
public void whatDoIDo(ref int foo, ref int bar){    foo = foo * 2;    bar = bar * 2;}public void nowWhatDoIDo(out int foo, out int bar){    foo = foo * 2;    bar = bar * 2;}

If you tried this:
int x = 5, y = 10;whatDoIDo(x, y);    // the compiler gives the green light                    // x and y go in initialized but                    // but come out as x = 10 and y = 20int a, b;nowWhatDoIDo(a, b); // the compiler is going to scream at you                    // because you didn't assign x and y                     // a value in the function


From what I can tell the compiler forces you to assign a value to a out variable in the function.

Simple rule: use ref parameters if the variable already has a value; use out parameters if the variable hasn't been initialized or assigned a value and you need to give it one.

Beginner in Game Development?  Read here. And read here.

 

Advertisement
Quote: Original post by password
Quote: Original post by Alpha_ProgDes
If you tried this:



int x, y;

whatDoIDo(x, y); // the compiler is going to scream at you

// because you didn't initialize x and y



nowWhatDoIDo(x, y); // the compiler gives the green light

// x and y go in uninitialized but

// but come out as x = 10 and y = 20


In that case, always using the out keyword should be better, since it is just like a reference except that it also can handle unitialized variables. It's like a better version of ref, or i'm I misunderstanding?


Thats not quite right. I'll try and make some more sense with an example.

        //wont't compile        private void Square(out int x) {            x = x * x;        }        //will compile        private void Square(ref int x) {            x = x * x;        }


So whats the difference? Basically, the difference is that with an out parameter you have to initialise it within the method where it is used, so it can't be used for passing parameters. With a ref parameter however, the parameter must be initialised outside the method and then passed in, making the value available for use in the method.
Yes, the differences between ref and out can be confusing sometimes.

[opinion]
My rule of thumb is to always use ref so that you don't have to worry about having uninitialized variables. As far as I know, there are no side effects to always using ref, except that every variable you pass into as a ref parameter must be initialized.
[/opinion]

Come to think of it, I can't understand why out was even included in the language in the first place. The designers of C# did an excellent job of getting away from a common C++ error, namely uninitialized variables. Giving a chance for someone to have an uninitialized value is just asking for trouble.

Can somebody give some insights as to why they allowed out into the language?
Mike Popoloski | Journal | SlimDX
@Sam, Mike., Vyper_: I'm glad you guys haven't contradicted what I've been trying to explain. Otherwise, I'd feel really bad about my level of understanding [sad]

Beginner in Game Development?  Read here. And read here.

 

I see. I was just wondering, because I thought that out seemed to be a completetly unnecessary keyword in the language. From what Mike.Popoloski said, I think that even more now.
Advertisement
Quote: Original post by Mike.Popoloski
Yes, the differences between ref and out can be confusing sometimes.

[opinion]
My rule of thumb is to always use ref so that you don't have to worry about having uninitialized variables. As far as I know, there are no side effects to always using ref, except that every variable you pass into as a ref parameter must be initialized.
[/opinion]

Come to think of it, I can't understand why out was even included in the language in the first place. The designers of C# did an excellent job of getting away from a common C++ error, namely uninitialized variables. Giving a chance for someone to have an uninitialized value is just asking for trouble.

Can somebody give some insights as to why they allowed out into the language?


[observation]
I can think of a couple of situations.

Firstly, if the method is designed to create an object which has computationally expensive creation logic, you might not want to do that logic twice like you would need to using a ref (though in this situation you probably shouldn't be using either ref or out anyway, just a standard method return would do. A simple dummy constructor which does no logic could also be a work around)

The second would be when using large objects in some kind of distributed app. You wouldn't want to have to send a large 'dummy' object across a network just for the sake of using ref. In this case it would be better to use out, so the object is only sent one way
[/observation]
Quote: Original post by Mike.Popoloski
Yes, the differences between ref and out can be confusing sometimes.

[opinion]
My rule of thumb is to always use ref so that you don't have to worry about having uninitialized variables. As far as I know, there are no side effects to always using ref, except that every variable you pass into as a ref parameter must be initialized.
[/opinion]

Come to think of it, I can't understand why out was even included in the language in the first place. The designers of C# did an excellent job of getting away from a common C++ error, namely uninitialized variables. Giving a chance for someone to have an uninitialized value is just asking for trouble.

Can somebody give some insights as to why they allowed out into the language?


Uninitialized variables do not come with out, they come with local variables. Plus, the compiler (conservatively, i.e. it will never allow errors but might bark at non-errors) checks that you never try to read uninitialized variables.

I like out because C# does not provide tuples, which I would use in order to return more than one value from methods. I'm too lazy to start defining Pair<A, B>, Triple<A, B, C>, etc.

Quote:
Firstly, if the method is designed to create an object which has computationally expensive creation logic, you might not want to do that logic twice like you would need to using a ref (though in this situation you probably shouldn't be using either ref or out anyway, just a standard method return would do)

Or use null? Of course, value types can't be null-ed, but then again, they always have default constructors, which shouldn't be too expensive.

[Edited by - SamLowry on July 2, 2007 11:23:17 AM]
Quote: Original post by SamLowry
Quote:
Firstly, if the method is designed to create an object which has computationally expensive creation logic, you might not want to do that logic twice like you would need to using a ref (though in this situation you probably shouldn't be using either ref or out anyway, just a standard method return would do)

Or use null? Of course, value types can't be null-ed, but then again, they always have default constructors, which shouldn't be too expensive.

Oh yeah, silly me :)

Quote: Original post by Vyper_uk
Firstly, if the method is designed to create an object which has computationally expensive creation logic, you might not want to do that logic twice like you would need to using a ref (though in this situation you probably shouldn't be using either ref or out anyway, just a standard method return would do. A simple dummy constructor which does no logic could also be a work around)
[/observation]



when an object is passed by ref, isn't it sent as a pointer and wouldn't be recreated inside the function?

This topic is closed to new replies.

Advertisement