Page 4 of 7

Re: oop question

Posted: Wed May 20, 2009 8:49 am
by onion2k
Jenk wrote:
onion2k wrote:
Jenk wrote:Heaven forbid colleagues would actually need to talk to each other.
Communicating is ace if it's worthwhile and constructive, but if you're talking about a code failure that could have been avoided by using private variables rather than public you're wasting everyone's time. Why would you want to do that?
You mean wasting time by mis-using a library. The variable will be clear as to what it's purpose is, so why would they assign something to it that will break it?! :?:
They might not realise they're breaking the code when they write something. In the example I gave earlier, where $player->points should always be positive, it's not necessarily obvious that it should be. There's nothing in the variable name to say so. It might only be a very unusual set of circumstances where a negative score breaks the game.

If you've made a variable public a developer might accidentally typo a + as a - instead.. "$player->points -= 5;" for example.. it's easily done. That might be fine 999 times in 1000 when the players score is more than 5, but as soon as the code is called when the player has less than 5 points the game breaks.

If I'd written the code, and the developer had to use the setPoints method, because $player->points is private, there's no way their typo could break the game because the method uses abs() to correct the value.

What I'm failing to understand is why, if as you say yourself you never use public class variables, and you use a naming scheme to make this stuff obvious, you wouldn't enforce it in the code just to make sure. There's no difference really between using a naming scheme and using directives, apart from the directives actually make sure people don't ignore it. Which is good.

Re: oop question

Posted: Wed May 20, 2009 9:43 am
by Jenk
Because, back to what was posted earlier, there's no point changing anything until it needs changing. I'm not going to restrict something on the off chance someone mis-uses it, simply because I don't know if what they are trying to do actually consists of mis-use or is just a different usage to what I am attempting. In fact I'd rather they did misuse it, and learn from their mistake.

Also, a simple PHPDoc syntax comment, which is parsed by any decent IDE such as Eclipse, Zend Studio, etc. will show what the comment is and my comment would be along the lines of:

Code: Select all

class Player
{
 /**
  * The number of points a player has, should be greater than -1.
  * @var points
  **/
  public $points = 0;
// etc
}
edit: and on a side note, which is not really relevant to this discussion.. "Why are you assuming -5 to be 5?" would be my question to you.

Re: oop question

Posted: Wed May 20, 2009 10:16 am
by Christopher
onion2k wrote:What I'm failing to understand is why, if as you say yourself you never use public class variables, and you use a naming scheme to make this stuff obvious, you wouldn't enforce it in the code just to make sure. There's no difference really between using a naming scheme and using directives, apart from the directives actually make sure people don't ignore it. Which is good.
I think that is the part of this discussion that is baffling the people on the side of controlling scope. There is really no conceptual difference between using local variables and specifying scoping rules for properties. They are simply ways to control access access to data from outside the current scope. The fact that properties allow a three-way switch rather than local variables two-way switch is only due to the fact that functions cannot inherit but classes can.

That's why statements like this seem so odd:
Jenk wrote:Because, back to what was posted earlier, there's no point changing anything until it needs changing. I'm not going to restrict something on the off chance someone mis-uses it, simply because I don't know if what they are trying to do actually consists of mis-use or is just a different usage to what I am attempting. In fact I'd rather they did misuse it, and learn from their mistake.
Because Jenk currently restricts access every time he implements a function, yet I doubt he declares all local variables global. So it is simply being inconsistent. This is very odd, given that a major thrust of programming language design and OOP itself has been to decrease they ways in which code can be misused.

And this "there's no point changing anything until it needs changing" makes the erroneous assumption that the natural state of properties is public and not protected. I agree with the words, but I think you only change visibility from protected to public or private if there is a reason it needs changing.

It is only the historical quirk that the PHP Group originally implemented objects as arrays (which do not have scope control) that we are even having this conversation. They took a short-cut which they have since fixed in PHP5. All OO languages provide those three obvious scoping rules simply because they cover the main options.

Re: oop question

Posted: Wed May 20, 2009 10:24 am
by Jenk
arborint wrote:
onion2k wrote:What I'm failing to understand is why, if as you say yourself you never use public class variables, and you use a naming scheme to make this stuff obvious, you wouldn't enforce it in the code just to make sure. There's no difference really between using a naming scheme and using directives, apart from the directives actually make sure people don't ignore it. Which is good.
I think that is the part of this discussion that is baffling the people on the side of controlling scope. There is really no conceptual difference between using local variables and specifying scoping rules for properties. They are simply ways to control access access to data from outside the current scope. The fact that properties allow a three-way switch rather than local variables two-way switch is only due to the fact that functions cannot inherit but classes can.

That's why statements like this seem so odd:
Jenk wrote:Because, back to what was posted earlier, there's no point changing anything until it needs changing. I'm not going to restrict something on the off chance someone mis-uses it, simply because I don't know if what they are trying to do actually consists of mis-use or is just a different usage to what I am attempting. In fact I'd rather they did misuse it, and learn from their mistake.
Because Jenk currently restricts access every time he implements a function, yet I doubt he declares all local variables global. So it is simply being inconsistent. This is very odd, given that a major thrust of programming language design and OOP itself has been to decrease they ways in which code can be misused.

And this "there's no point changing anything until it needs changing" makes the erroneous assumption that the natural state of properties is public and not protected. I agree with the words, but I think you only change visibility to public or private if there is a reason it needs changing.

It is only the historical quirk that the PHP Group originally implemented objects as arrays (which do not have scope control) that we are even having this conversation. They took a short-cut which they have since fixed in PHP5. All OO languages provide those three obvious scoping rules simply because they cover the main options.
You really are clutching at straws now. I've already answered the question for local variables vs member variables.

A member variable is utterly different to a local variable in every given way except one: it is a container for a value.

A member variable is a container for stateful data. I.e. it is relevant to keep a reference to this value for the duration of the objects instance.

A local variable is discarded after function exit, i.e. it is temporary. The only place I ever use local variables is something like an iterator.

Code: Select all

public function addToAll($add)
{
    $newNumbers = array();
    foreach ($this->numbers as $number)
    {
      $newNumbers[] = $number += $add;
    }
    $this->numbers = $newNumbers;
    // $add, $number and $newNumbers references are no longer needed. Discarded.
}

Re: oop question

Posted: Wed May 20, 2009 10:34 am
by onion2k
Jenk wrote:edit: and on a side note, which is not really relevant to this discussion.. "Why are you assuming -5 to be 5?" would be my question to you.
Fair point. The method should really reject the input argument and return a failure rather than abs() it and use it anyway. That's just my hastily thought out example though, it's not really relevant to the discussion. If you're directly accessing the member variable you still wouldn't get that failure.

Re: oop question

Posted: Wed May 20, 2009 10:36 am
by Jenk
onion2k wrote:
Jenk wrote:edit: and on a side note, which is not really relevant to this discussion.. "Why are you assuming -5 to be 5?" would be my question to you.
Fair point. The method should really reject the input argument and return a failure rather than abs() it and use it anyway. That's just my hastily thought out example though, it's not really relevant to the discussion. If you're directly accessing the member variable you still wouldn't get that failure.
You would get a failure if directly accessing with an unexpected value were to be problematic which - unless we have crystal balls to peer into - we cannot tell if that failure will even happen until it does anyway.

Re: oop question

Posted: Wed May 20, 2009 10:59 am
by Christopher
Jenk wrote:You really are clutching at straws now. I've already answered the question for local variables vs member variables.

A member variable is utterly different to a local variable in every given way except one: it is a container for a value.

A member variable is a container for stateful data. I.e. it is relevant to keep a reference to this value for the duration of the objects instance.

A local variable is discarded after function exit, i.e. it is temporary. The only place I ever use local variables is something like an iterator
They are only utterly different to you. Class properties are in a different scope, just like local variables. The fact that in PHP4 objects were just arrays is simply a quirk you got used to. Concepts like "stateful" and "temporary" are subjective. Properties hold values for the life of the object, which can be considered temporary.

Re: oop question

Posted: Wed May 20, 2009 11:34 am
by Jenk
and local variables hold values for the life of the function, ergo, it's gone when you return.. how do you propose you change their value during the life of the function? fork and cross your fingers?

"temporary" is anything but subjective, because that's exactly what they are.. temporary variables for the life of the function.

Re: oop question

Posted: Wed May 20, 2009 12:08 pm
by alex.barylski
Jenk...pardon me for asking but are you not the Smalltalk/Funcitonal programming adovcate here at DN?

If this is the case, and smalltalk is what I believe it to be, do you not feel keeping all member data (if I understand this argument correctly) to be breaking the most important rule in OOP -- encapsulation (second maybe only to polymorphism)?

I'm not a huge fan of trivial getter/setter methods as they seem rather moot -- but they encapsulate the internal naming conventions I use for variables and might even provide some additional funcitonality, like enforcing a 'const-ness' similar to const modifiers in languages like C/C++

If funcitonal programming is a paradigm that enforces lack of state and you like that idea, how does exposing an property in a OOP paradigm help any? I can only see that further allowing state to change, at least with a getter/setter you can avoid changing of state.

Consider the database example so commonly refered to:

I would such an object like:

Code: Select all

 
$obj = new MyPDO();
$obj->connect('localhost', 'user', 'pass');
 
It sounds as though what you are all disscussing is the ability to set the connection object after instantiation/connection, so something like:

Code: Select all

$obj->_db = null; // Kill connection
$obj->_db = $SomePDOResource;
Personally I would rather just re-instantiate the PDO object with different parameters and use a new object if I really needed to change the connection.

My objects tend to be extremely simple, 4-5 methods at most, each method less than 25 lines and maybe 2 or 3 private data members, so the overhead in instantiating a object is minimal -- at least I have not yet encountered problems.

The exception to this, are objects which are perhaps more analogous to C/C++ style structures and not really objects but data containers, such as row data gateway, config objects and registry are good examples.

In these objects I allow direct access to the properties, again because they are more about data containers than polymorphic objects -- although they typically derive from abstract classes, in which they inherit all the protected and public methods of course (I never protect a member variable -- it's either public or private).

With the two examples I gave above, one being a data container in the form of an object (registry, config, RDG, etc) and the other being a database object that essentially wraps a resource...what am I missing???

Is it strongly believed that allowing a user to set the resource $_db under a DB object to be good practice? Not destroying the old object first might result in memory leaks, or so it would under many languages, like C/C++ so it's generally accepted you never allow direct access to those member data, instead relying on the ctor/dtor to create and destroy the object and it's resources effectively.

So while I might allow access to a property such as 'first_name' I do not think I would want users to access a variable called 'ref_counter' -- which if they changed could screw up GC or something similar.

That to me, has always been the point behind encapsulation, keeping the implementation separate from interface and visa-versa.

I suppose it's fare to say that member data, can be both publically accessible (in the case of data contrainer objects) and completely sealed off from the rest of the world, such as a external resource, reference counter, etc.

Cheers,
Alex

Re: oop question

Posted: Wed May 20, 2009 12:22 pm
by McGruff
arborint wrote:There is really no conceptual difference between using local variables and specifying scoping rules for properties.
There's a huge difference fundamental to the understanding of OOP. A class doesn't need to be divided up against itself. A strict boundary between "inside" and "outside" should be upheld (eg no direct property access: a gentleman doesn't do that sort of thing) but inside anything goes. The idea that objects need an internal scope is quite odd. Why have things been allowed to get so complicated? If something feels exposed that's probably a code smell indicating a discrete responsibility which needs to be split off into a new class. Private is actually an enabler of bad design because it helps to support bloated inheritance hierarchies. It's evil.

Re: oop question

Posted: Wed May 20, 2009 12:34 pm
by Christopher
Jenk wrote:and local variables hold values for the life of the function, ergo, it's gone when you return.. how do you propose you change their value during the life of the function? fork and cross your fingers?

"temporary" is anything but subjective, because that's exactly what they are.. temporary variables for the life of the function.
But an object only holds its values for the life of the object. From the point of view of application state the property is temporary. "Temporary" is subjective. And it also has little to do with this discussion of scope and visibility. It does not matter how long you provide visibility for...

Re: oop question

Posted: Wed May 20, 2009 12:47 pm
by Christopher
McGruff wrote:There's a huge difference fundamental to the understanding of OOP. A class doesn't need to be divided up against itself. A strict boundary between "inside" and "outside" should be upheld (eg no direct property access: a gentleman doesn't do that sort of thing) but inside anything goes. The idea that objects need an internal scope is quite odd.
No one that I know of is talking about dividing things up in any way but inside and outside. Public/protected/private only control visiblity for inside/outside a class. And the fact that you and Jenk probably more strongly oppose direct access of properties makes this conversation all the more odd to the rest of us... Non-PHP OOPiphiles though that PHP's "var" for properties was horrible and now you guys are defending it?
McGruff wrote:Why have things been allowed to get so complicated? If something feels exposed that's probably a code smell indicating a discrete responsibility which needs to be split off into a new class. Private is actually an enabler of bad design because it helps to support bloated inheritance hierarchies. It's evil.
Whether private is "an enabler of bad design" is purely subjective. It is ridiculous to say that typing that keyword instantly bloats an inheritance hierarchy.

I don't think most people in this discussion would disagree with you and Jenk that public and private should not be used that often. They are a design decision that should be done with full awareness. But they are not some made up concepts -- they are simply the possible options. Protected is what most properties should be declared. As I have said, the fact that var/public was the default in PHP4 is a quirk. I would also note that using protected/private/public not only "documents" how the property should be used, but it allows the compiler to give programmers useful information about properly using those properties.

Re: oop question

Posted: Wed May 20, 2009 1:37 pm
by McGruff
arborint wrote:No one that I know of is talking about dividing things up in any way but inside and outside. Public/protected/private only control visiblity for inside/outside a class.
That's exactly what private does ie it creates a bizarre internal scope in a class hierarchy. Protected is unnecessary (except possibly as a label) but private is plain evil. As well as promoting bad design it prevents other people from extending your code - and even then it doesn't actually stop them, just makes it twice as hard. That breaks the open closed principle.
Non-PHP OOPiphiles though that PHP's "var" for properties was horrible and now you guys are defending it?
I certainly would. It's easier to type. I'll be very cross indeed if we are ever forced to use ppp out of some anal-retentive desire to stop people doing things they never had any intention of doing in the first place. Honestly, how many times did you try to call a notionally-private method in php4? I bet you never did. Labelling is of course important but that's all.

I used to live in a small village where hardly anybody bothered to lock their doors. I don't think I ever had a key cut even. Just wasn't a problem. Some did, of course, and nothing could ever persuade them otherwise.

Re: oop question

Posted: Wed May 20, 2009 1:53 pm
by Christopher
McGruff wrote:That's exactly what private does ie it creates a bizarre internal scope in a class hierarchy. Protected is unnecessary (except possibly as a label) but private is plain evil. As well as promoting bad design it prevents other people from extending your code - and even then it doesn't actually stop them, just makes it twice as hard. That breaks the open closed principle.
Again, using private does not instantly "creates a bizarre internal scope in a class hierarchy". That's just silly. If you don't like it or don't want to use it -- that's fine. But private simply implements one of the possible visibility options. I am sure that you have written classes where you wanted inheritors to use a method rather than access the property directly. Private just enforces it when you want to do that -- which is not that often -- and maybe never for you.

And both you and Jenk say protected is unnecessary, yet in the same breath say that is how you expect people to use the properties in your classes. And everyone here agrees that protected is how most properties should be used.
McGruff wrote:I certainly would. It's easier to type. I'll be very cross indeed if we are ever forced to use ppp out of some anal-retentive desire to stop people doing things they never had any intention of doing in the first place. Honestly, how many times did you try to call a notionally-private method in php4? I bet you never did. Labelling is of course important but that's all.

I used to live in a small village where hardly anybody bothered to lock their doors. I don't think I ever had a key cut even. Just wasn't a problem. Some did, of course, and nothing could persuade them otherwise.
Again, this is quite silly. Equating programming language constructs to a small village where everyone just trusts each other! (and yes I did have errors due to improperly setting properties in PHP4) As I said to Jenk, you must also be opposed to using constants and you must keep all variables in the global scope because you just trust other programmers and don't want any restrictions on their access to your variables. Likewise I assume you are opposed to the evil of Type Hinting because it is another restriction that tests would catch and you would not want to prevent others from passing the wrong type of variable anyway. Interfaces too ... pure evil. I am really not seeing where you guys are going with this?

Re: oop question

Posted: Wed May 20, 2009 5:13 pm
by Jenk
PCSpectra wrote:Jenk...pardon me for asking but are you not the Smalltalk/Funcitonal programming adovcate here at DN?
I am a Smalltalk programmer, but I'm not quite sure what you mean by functional? If you mean procedural - then no, anything but. Smalltalk is 100% OO, even more OO than Java. No such thing as a primitive type, and there are next to no keywords/reserved words. As a matter of fact there are, I believe, only self (equivalent of this) nil (null) true, false, ^ (return) and thisContext. But even they are not restricted, as you can change their value very easily:

Code: Select all

true become: false
but not recommended, of course.

Whilst in Smalltalk there is no means to access a member variable directly, it is impossible to restrict them. The methods #instanceVariableAt:, #instanceVariableNamed: (and partnering putters) means no variable is safe :p If they were 'private' you would never be able to debug, and you'd be in some serious head scratching territory when something goes wrong. :)