Need a little help understanding objects

  • (3 Pages)
  • +
  • 1
  • 2
  • 3

30 Replies - 3905 Views - Last Post: 12 March 2013 - 09:56 PM

#16 BobRodes  Icon User is offline

  • Your Friendly Local Curmudgeon
  • member icon

Reputation: 574
  • View blog
  • Posts: 2,989
  • Joined: 19-May 09

Re: Need a little help understanding objects

Posted 24 February 2013 - 06:37 PM

The point is that you can put any type of logic that you want in the methods, and you can't do that with a public attribute. For example, if you just had a Weight property, you could in the mutator method prevent a user from setting the value to a negative number. You couldn't do that with a public variable.

To attempt to answer your more specific concerns about my less to the point example, my first thought is that you can call an isUserInRole(someRole) method, and ask whether the user is in the Mechanic group. If not, the user can't set the property.

This post has been edited by BobRodes: 24 February 2013 - 06:37 PM

Was This Post Helpful? 0
  • +
  • -

#17 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3589
  • View blog
  • Posts: 11,158
  • Joined: 05-May 12

Re: Need a little help understanding objects

Posted 26 February 2013 - 07:07 AM

View PostBobRodes, on 24 February 2013 - 08:37 PM, said:

The point is that you can put any type of logic that you want in the methods, and you can't do that with a public attribute. For example, if you just had a Weight property, you could in the mutator method prevent a user from setting the value to a negative number. You couldn't do that with a public variable.


Yes, very true. I completely agree.

View PostBobRodes, on 24 February 2013 - 08:37 PM, said:

To attempt to answer your more specific concerns about my less to the point example, my first thought is that you can call an isUserInRole(someRole) method, and ask whether the user is in the Mechanic group. If not, the user can't set the property.


My point, though, is I can't see how this can't be done without polluting the class.
class Car
{
    public int Weight { get; set; }
}


Nice and concise. The car only need worry about its weight. Single Responsibility Principle applied to the max.

Now to take into account the user, the class needs to be muddied:
class Car
{
    int _weight;

    public int Weight
    {
        get { return _weight; }

        set
        {
            if (!IsUserInRole(CurrentUser, Role.Mechanic))
                throw new PrivelegeNotHeldException();
            _weight = value;
        }
    }

    public User CurrentUser { get; set; }

    private IsUserInRole(User user, Role role)
    {
        return user.Roles.Contains(role);
    }
}


Now, the Car class is all muddied up. Not only does the car code have to take care of its weight, now it also needs to know about the User class, and the Role enumeration. To make things worse, that extra code still does nothing to protect the car from unauthorized modification by the owner:
User owner = new CarOwner(Role.Driver);
User mechanic = new Mechanic(Role.Mechanic);

var car = new Car();
car.CurrentUser = owner;

// owner takes car to the mechanic:
TaskFactory.StartNew({
    car.CurrentUser = mechanic;

    // sleep for a week to simulate mechanic "working" on the car
    // to remove weight.
    car.Weight -= 125;
    Thread.Sleep(new TimeSpan(7, 0, 0, 0, 0));

    car.CurrentUser = owner;
});

// While the mechanic is "working" on the car for a week,
// the owner can also change the weight because the CurrentUser
// is the mechanic, but the owner still has a reference to the
// car.
Thread.Sleep(new TimeSpan(1, 0, 0, 0, 0)); // wait a day
car.Weight -= 25;



As I said, I'm having a very hard time visualizing a solution that is language neutral and still offers the protection the property access supposedly offers.
Was This Post Helpful? 1
  • +
  • -

#18 jon.kiparsky  Icon User is online

  • Pancakes!
  • member icon


Reputation: 7803
  • View blog
  • Posts: 13,198
  • Joined: 19-March 11

Re: Need a little help understanding objects

Posted 26 February 2013 - 08:55 AM

All of this talk about changing the weight of the car seems to be a little silly without some talk about the nature of the application in question. Are we modelling cars in the sense of an engineer trying to determine the results of certain design changes, or are we modelling care in a Cops and Robbers game, trying to represent the facts of some "real world" scenario, or are we in a cartoon, where cartoon physics are meant to apply, or what? What sort of car has a "change weight" option?

If you're modelling a real-world scenario, you'd derive the loaded weight of the vehicle from the base weight plus the fuel weight plus the weight of the contents, and that would be a calculated quantity. If you're trying to figure out how the car handles, and you have a good model of the physics of road conditions, you might want to just set the weight - let's say we can take fifty pounds off the vehicle, what happens in black ice conditions? (maybe we're trying to find a break point where the weight starts to affect handling more sharply, I don't know)


But this all goes to a common mistake in OO programming, and in talking about OO programming: setting the wrong parameters. For example, a Car object should not have a "setSpeed()" method. In normal modelling, no outside entity should be able to set the car's speed, period. You can ask the car to accelerate or to brake, and the car will hopefully do its best to comply, you can inform the car that it's impacted an obstacle, and a reality-conforming car will slow down or stop, but you can't just set the speed - because that's a terrible model. Not only does it fail completely to model the world, but in terms of design it creates one massively coupled blob of functionality, the World/Car, which defeats the purpose of object-oriented design completely.

It's always a little weird to talk about this stuff in terms of Cars and Animals, but those are the examples we see all the time. What about a WordProcessor? Suppose the WordProcessor has a Display, which is where the user sees the results of their work, and a Contents, which is the actual text they're working on. Should the Contents be able to set the Display's fields? Of course not, that would be idiotic. The only objects which should provide direct "set" access are objects whose only purpose in life is to contain things - and even then, the "set" should be a request, not an order. (In a sense, you could consider this as a plea for more "collaborative" objects and fewer "master-servant" relationships.)
Was This Post Helpful? 1
  • +
  • -

#19 BobRodes  Icon User is offline

  • Your Friendly Local Curmudgeon
  • member icon

Reputation: 574
  • View blog
  • Posts: 2,989
  • Joined: 19-May 09

Re: Need a little help understanding objects

Posted 03 March 2013 - 09:49 PM

Good explanation of your concern, skydiver, and the example you give is a fine one of violation of the cohesion principle. I would instead have a static class that exposed a collection of users (say SystemUsers, a collection of SystemUser objects) and the isUserInRole property. Then I would access that class from the car class. Or any other class, for that matter. My car's CurrentUser property would have to assign a user from the collection of users.

So, two differences: isUserInRole isn't in the Car class. Next the SystemUser class prevents direct instantiation of users and handles the assignment of roles, and the Car class would have to assign an existing user from the collection.

Is that an improvement? (Edit: a further improvement comes to mind where fixing the car is decoupled from either of these classes, and encapsulates the business rules around what type of user can fix the car. Say a RepairOrder class. Then the car doesn't have to care whether the user is allowed to assign the weight, and we get your single responsibility principle. However, I still wouldn't use a public variable because we would want the mutator method to prevent reducing the weight to a negative number, etc.)

This post has been edited by BobRodes: 03 March 2013 - 10:02 PM

Was This Post Helpful? 1
  • +
  • -

#20 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3589
  • View blog
  • Posts: 11,158
  • Joined: 05-May 12

Re: Need a little help understanding objects

Posted 05 March 2013 - 09:40 AM

Good suggestions, but unfortunately, the same issue still exists even if you use a static collection class to maintain and manage the the Users. This is because even if you change the CurrentUser property on the Car instance, the old user still has a reference to the Car. Since the property is public, the old user can still access the property.

Even if you went with a RepairOrder class, the same issue still exists. The owner of the Car still has a reference to the object, and since the property is public, the property can still be changed.

To make something like this to work, you could have to go along the route of C++ and have the Weight as a private property, and have the RepairOrder class be a friend of the Car class. You may be able to simulate the "C++ friend" behavior by using the C# "internal" keyword instead of "public" and have the Car and RepairOrder classes in the same assembly, and have the User class(es) in another assembly. So from the point of view of the User(s), the Weigh property is private, but from the point of view of the RepairOrder, the Weight property is public. Since the RepairOrder is a "friend" and the property is effectively private, it's only good programming practice that is making us go through a property instead of accessing the backing variable directly. The backing variable could be "private" in C++, or "internal" in C#.

But at this point we've strayed away from a language neutral way to preventing unauthorized access, and have started to depend on our programming language of choice to try to limit the access to the property.
Was This Post Helpful? 0
  • +
  • -

#21 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3589
  • View blog
  • Posts: 11,158
  • Joined: 05-May 12

Re: Need a little help understanding objects

Posted 05 March 2013 - 10:10 AM

Jon and Bob make excellent points above. Listen to them.

Despite my seeming opposition in my replies above, I am a big believer in keeping private variables private, and filtering access to the through getters/setters or methods. It's just plain old good programming practice that will often help you down the road, specially if a class needs to be refactored. I'm just trying to point out that it's not a generic solution for preventing unauthorized modification of an object. The compiler or interpreter won't always prevent you from doing something bad, but you can setup speed bumps along the way by declaring variables private, and setting the appropriate access levels to properties and methods. In the end, programmer discipline (include code reviews) is still needed.

This post has been edited by Skydiver: 05 March 2013 - 10:10 AM

Was This Post Helpful? 0
  • +
  • -

#22 BobRodes  Icon User is offline

  • Your Friendly Local Curmudgeon
  • member icon

Reputation: 574
  • View blog
  • Posts: 2,989
  • Joined: 19-May 09

Re: Need a little help understanding objects

Posted 06 March 2013 - 10:20 PM

How can the driver change the property if the mutator method is coded in such a way as to prevent him? Whether he has a reference to the car or not?
Was This Post Helpful? 0
  • +
  • -

#23 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3589
  • View blog
  • Posts: 11,158
  • Joined: 05-May 12

Re: Need a little help understanding objects

Posted 07 March 2013 - 06:51 PM

How can you code the mutator to prevent update in such a way that:
- it is language neutral; and
- the class that contains the mutator follows the single responsibility principle?
Was This Post Helpful? 0
  • +
  • -

#24 BobRodes  Icon User is offline

  • Your Friendly Local Curmudgeon
  • member icon

Reputation: 574
  • View blog
  • Posts: 2,989
  • Joined: 19-May 09

Re: Need a little help understanding objects

Posted 07 March 2013 - 08:41 PM

Thinking this through a bit further, put two classes that inherit from car, one for a driver and one for a mechanic. Don't put any mechanic-type methods in the driver class. Make the car's constructor protected, so only driver and mechanic classes could instantiate it. Then we can apply the constraint in a class designed for that. What do you think of that idea?

p. s. how would you code anything in a language neutral way, given that you need to code in a language?

This post has been edited by BobRodes: 07 March 2013 - 08:47 PM

Was This Post Helpful? 1
  • +
  • -

#25 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3589
  • View blog
  • Posts: 11,158
  • Joined: 05-May 12

Re: Need a little help understanding objects

Posted 08 March 2013 - 07:29 AM

Language neutral as in just using basic object oriented principles, that can be implemented in any language, but not having to rely on a particular language feature. For example, a couple posts back, I explored using the C++ "friend" or C# "internal" keywords to prevent access. Try doing the same access prevention in plain old C or Pascal.

I'm actually intrigued by your idea above. I can almost see the potential of it working, but the hole I'm seeing is that you now have two instances of a car. When the driver brings the car into the shop for repair, the mechanic has to create a new instance of a car because casting across heirarchy tree branches is a Bad ThingTM. And the same is true when the mechanic returns the car to the driver, a new instance needs to be created. It's not the same car anymore.
Was This Post Helpful? 0
  • +
  • -

#26 jon.kiparsky  Icon User is online

  • Pancakes!
  • member icon


Reputation: 7803
  • View blog
  • Posts: 13,198
  • Joined: 19-March 11

Re: Need a little help understanding objects

Posted 08 March 2013 - 08:18 AM

View PostSkydiver, on 08 March 2013 - 09:29 AM, said:

I'm actually intrigued by your idea above. I can almost see the potential of it working, but the hole I'm seeing is that you now have two instances of a car. When the driver brings the car into the shop for repair, the mechanic has to create a new instance of a car because casting across heirarchy tree branches is a Bad ThingTM. And the same is true when the mechanic returns the car to the driver, a new instance needs to be created.


Again, we're confusing ourselves with bad examples. Instantiating a Car is not like making a new car.
Is it really so bad to instantiate a new object? Depends on the situation. Immutability can really simplify life, and it can be worth a tradeoff.

Quote

It's not the same car anymore.


We don't know that until we get busy with the .equals method... :)
Was This Post Helpful? 1
  • +
  • -

#27 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3589
  • View blog
  • Posts: 11,158
  • Joined: 05-May 12

Re: Need a little help understanding objects

Posted 08 March 2013 - 09:39 AM

If a class is immutable, then there is no need for a mutator. :)
Was This Post Helpful? 1
  • +
  • -

#28 BobRodes  Icon User is offline

  • Your Friendly Local Curmudgeon
  • member icon

Reputation: 574
  • View blog
  • Posts: 2,989
  • Joined: 19-May 09

Re: Need a little help understanding objects

Posted 08 March 2013 - 11:31 PM

View PostSkydiver, on 08 March 2013 - 08:29 AM, said:

Language neutral as in just using basic object oriented principles, that can be implemented in any language, but not having to rely on a particular language feature. For example, a couple posts back, I explored using the C++ "friend" or C# "internal" keywords to prevent access. Try doing the same access prevention in plain old C or Pascal.

I'm actually intrigued by your idea above. I can almost see the potential of it working, but the hole I'm seeing is that you now have two instances of a car. When the driver brings the car into the shop for repair, the mechanic has to create a new instance of a car because casting across heirarchy tree branches is a Bad ThingTM. And the same is true when the mechanic returns the car to the driver, a new instance needs to be created. It's not the same car anymore.

Not necessarily. The single car instance can expose two interfaces, one for drivers and one for mechanics. Two references to the same object, one of the cardrive type and the other with the carmaintain type.

As for your first paragraph, the fact that some languages don't have the access restrictions that you describe suggests that the restrictions aren't language neutral. However, I would think that the concept itself could be programmed in any language--after all, C++ was probably written in Assembler, and therefore by extension so were its features.

As such, I submit that a "constraint" is a language neutral concept. The fact that constraints are part of the UML spec I would say bears out that position. I was more inspired to improve my model by your point about single responsibility/cohesion.
Was This Post Helpful? 1
  • +
  • -

#29 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3589
  • View blog
  • Posts: 11,158
  • Joined: 05-May 12

Re: Need a little help understanding objects

Posted 10 March 2013 - 08:27 PM

Quote

Not necessarily. The single car instance can expose two interfaces, one for drivers and one for mechanics. Two references to the same object, one of the cardrive type and the other with the carmaintain type.

The same problem occurs: How do I restrict editting a public property to just a select few? How do I restrict giving out an interface to a select few?

Quote

As for your first paragraph, the fact that some languages don't have the access restrictions that you describe suggests that the restrictions aren't language neutral. However, I would think that the concept itself could be programmed in any language--after all, C++ was probably written in Assembler, and therefore by extension so were its features.

The C++ code gets compiled down to machine code that has no concepts of restrictions, but it is the C++ compiler that is enforcing the access restrictions.

Quote

As such, I submit that a "constraint" is a language neutral concept. The fact that constraints are part of the UML spec I would say bears out that position.

I completely agree that a "constraint" is a language neutral concept. But UML is just a model of how we want the software to function and be organized, or a reflection of how with think it is functioning or is organized. I can put together a UML diagram that mark a property as "public", and write a constraint that say "can only be modified by Mechanic" classes, but that is only as good as the paper model is printed on.

If the class is declared as:
class Car
{
public:
     void setWeight(int delta);

private:
     int _weight;
};



Joe random programmer who has not seen the UML diagram can simply write:
Car * pcar = new Car;
pcar->setWeight(10000);


without any speed bumps to tell him that he is going against the intended design.

We started off this discussion with along the lines of "Don't use public attributes. Any random person can just change the value. Instead make the attribute private, and create a public mutator."

I completely agree that creating the public mutator is a good practice, but as I said, I'm having a hard time envisioning a way to generically implement preventing Joe random programmer from calling the public mutator that we used to replace the formerly public attribute.
Was This Post Helpful? 1
  • +
  • -

#30 jon.kiparsky  Icon User is online

  • Pancakes!
  • member icon


Reputation: 7803
  • View blog
  • Posts: 13,198
  • Joined: 19-March 11

Re: Need a little help understanding objects

Posted 10 March 2013 - 09:28 PM

And I still have to ask myself, why does the object have a mutator?

Very, very often it turns out that there is no need at all for a method which sets a field of an object, conditionally or unconditionally, as its purpose. Instead, what you want are methods that inform the object about a change in its circumstances - the object then manipulates its own state accordingly.

This still leaves you with some issues to resolve, I admit, but it pushes them back to a more reasonable place. Namely, you do not have a situation where someone can change the weight of your Car arbitrarily, either by calling setWeight or by reaching in and changing a value. Instead, they might call removeBackSeat() and lose fifty pounds that way. Now you're still trying to establish that it's their car and they have the right to do that, but this mirrors real life pretty well. (I can pry open your car and remove the back seat, as long as I have access to your car)

It's something I keep coming back to over and over again: if you ever write a getter or a setter, you should stop and think long and hard about whether you actually need that, and why.

If you start worrying about whether you need to restrict access to that setter, then it's probably not a setter you want to write, and some other approach probably makes more sense.
Was This Post Helpful? 1
  • +
  • -

  • (3 Pages)
  • +
  • 1
  • 2
  • 3