Page 2 of 2

Posted: Tue Jul 18, 2006 4:13 pm
by Christopher
Roja wrote:
Jenk wrote:_ANY_ property in a class is to be set via a setter, and 'get' through a getter imo.
A quite delicious response was written by someone else to that very concept.
A fundamental precept of OO systems is that an object should not expose any of its implementation details. This way, you can change the implementation without changing the code that uses the object. It follows then that in OO systems you should avoid getter and setter functions since they mostly provide access to implementation details.
If only it were that simple. That article -- which is at once good, contested, and a little out of date-- is making a point about the improper use of getters/setters, mainly in Java. It certainly makes some good points about how to design and use classes. And I think the current consensus is to use getters/setters less often. His previously provocative article was about using composition rather than inheritance -- also often heard advice today.

But his major point is about Tell, don't ask which is a broad design topic that can be a little subtle if you are not well versed in OOD -- I certainly don't understand it very well. I guess that my problem with "Is Evil" statements is that they usually lack an clear alternative of what to do. That is probably because the poor choice should actually be replaced with several different good choices depending on the circumstance.

I would note that he starts his article with this:
Allen Holub wrote:This column and last month's article are about design. Design, by nature, is a series of trade-offs. Every choice has a good and bad side, and you make your choice in the context of overall criteria defined by necessity. Good and bad are not absolutes, however. A good decision in one context might be bad in another.

If you don't understand both sides of an issue, you cannot make an intelligent choice; in fact, if you don't understand all the ramifications of your actions, you're not designing at all. You're stumbling in the dark. It's not an accident that every chapter in the Gang of Four's Design Patterns book includes a "Consequences" section that describes when and why using a pattern is inappropriate.

Posted: Tue Jul 18, 2006 4:58 pm
by Roja
arborint wrote:If only it were that simple.
I don't see it being that complicated. Jenk's position is "use set/get always", and his is "try to avoid using them". From my viewpoint, it is that simple. :)
arborint wrote:That article -- which is at once good, contested, and a little out of date-- is making a point about the improper use of getters/setters, mainly in Java. It certainly makes some good points about how to design and use classes. And I think the current consensus is to use getters/setters less often. His previously provocative article was about using composition rather than inheritance -- also often heard advice today.
I'm missing how it is "mainly in Java", or "out of date". Its extremely applicable to Jenks point, and to this thread, making it neither mainly a Java issue, or out of date.
arborint wrote:But his major point is about Tell, don't ask which is a broad design topic that can be a little subtle if you are not well versed in OOD -- I certainly don't understand it very well.
Very odd. I didn't have that take at all, and I'm not sure what you mean by it.
arborint wrote:I guess that my problem with "Is Evil" statements is that they usually lack an clear alternative of what to do. That is probably because the poor choice should actually be replaced with several different good choices depending on the circumstance.
Thats exactly right. He's not saying you should NEVER use getters/setters, just that they can be a bad code smell, indicating that the design wasn't sufficiently object oriented.

I think his point is dead on. The default should be to avoid using get/set, for the reasons he mentions. There are definitely exceptions to the rule, but if you have get/sets everywhere, you probably are missing some opportunities.

Posted: Tue Jul 18, 2006 5:39 pm
by Christopher
Roja wrote:I'm missing how it is "mainly in Java", or "out of date". Its extremely applicable to Jenks point, and to this thread, making it neither mainly a Java issue, or out of date.
His article is mainly addressing the getter/setter epidemic in Java -- I don't see the same thing happening in PHP.
Roja wrote:Very odd. I didn't have that take at all, and I'm not sure what you mean by it.
His emphasis, not mine, which I think is his whole thesis is really about "Tell, don't ask":

Don't ask for the information you need to do the work; ask the object that has the information to do the work for you.
Roja wrote:I think his point is dead on. The default should be to avoid using get/set, for the reasons he mentions. There are definitely exceptions to the rule, but if you have get/sets everywhere, you probably are missing some opportunities.
As I said, my problem with "Is Evil" statements ,like "avoid" statements, is that there is no positive action given for what to do. There is a big difference to me between "Avoid using get/set" and "Follow Tell, don't ask and only use get/set where appropriate" There are many places where accessors are appropriate and some thing like Value Objects that are all accessors.

Posted: Tue Jul 18, 2006 5:55 pm
by Roja
arborint wrote:
Roja wrote:I'm missing how it is "mainly in Java", or "out of date". Its extremely applicable to Jenks point, and to this thread, making it neither mainly a Java issue, or out of date.
His article is mainly addressing the getter/setter epidemic in Java -- I don't see the same thing happening in PHP.
You don't see that happening in Jenk's comment "_ANY_ property in a class is to be set via a setter, and 'get' through a getter imo. "?

Thats what I was replying to, not to the overall, academic theory of PHP in the realworld (which I would argue is by an overwhelming majority in procedural code, not OOP).
arborint wrote:
Roja wrote:Very odd. I didn't have that take at all, and I'm not sure what you mean by it.
His emphasis, not mine, which I think is his whole thesis is really about "Tell, don't ask":

Don't ask for the information you need to do the work; ask the object that has the information to do the work for you.
Ah, you've changed his phrasing, and thats what confused me. Now I get your drift (on that point).
arborint wrote:As I said, my problem with "Is Evil" statements ,like "avoid" statements, is that there is no positive action given for what to do. There is a big difference to me between "Avoid using get/set" and "Follow Tell, don't ask and only use get/set where appropriate" There are many places where accessors are appropriate and some thing like Value Objects that are all accessors.
I don't see a big difference between the two. Avoiding using get & set is a good thing, in the manner he specifies. He doesn't say never use them, or any other absolute that would need a positive action given for what to do instead. He gives you a justification for avoiding them, and an explanation of what you can do to prevent needing them - better design choices, and a different paradigm for handling objects that is closer to encapsulation.

Just because you don't agree with that design choice in ALL places doesn't make it a non-ideal comment to make in general. I also note that you haven't argued against the fact that a get/set is inappropriate in general because it is directly accessing implementation details. You are just arguing that making that statement as general as he is isn't reasonable enough - and since I'm contrasting it against Jenk's absolute statement, I'd say its incredibly balanced in comparison.

Posted: Tue Jul 18, 2006 6:08 pm
by Benjamin
The only use I have really seen for getters and setters is if you need execute code on the data everytime it is set or retrieved. Simple examples would include logging, removing html, validation, etc.

Posted: Tue Jul 18, 2006 6:15 pm
by Luke
What is the difference between these?

Code: Select all

$instance->setVar('bla');

Code: Select all

$instance->Var = 'bla'
Seems to me they do the same thing. The first allows for Var to be private, but so what, it can be changed outside with the setter... what's the difference??

Posted: Tue Jul 18, 2006 6:19 pm
by Benjamin
With

Code: Select all

$instance->setVar('bla');
You can execute code on it in the class...

Code: Select all

function setVar($var) {
  // check length
  // check content
  // log the transaction..
  // remove html
  $this->var = $var;
}
I'm sure you already know that though.

Posted: Tue Jul 18, 2006 6:19 pm
by Weirdan
Seems to me they do the same thing. The first allows for Var to be private, but so what, it can be changed outside with the setter... what's the difference??
It's the ability to pre-process the value before you assign it to the internal object member. It's the ability to change internal data representation without changing object's clients. That's the difference (astions mentioned it as well).

Posted: Tue Jul 18, 2006 6:20 pm
by Chris Corbyn
IMO setters come in more useful than getters. You see these publically available classes that say "to turn on persistent connect do:

Code: Select all

$obj->PersistentConnect = TRUE;
"

Now, good. I'm sure it works but what if I typo:

Code: Select all

$obj->persistentConnect = TRUE;
Easily done. At least with a setter you'd see right way that you mis-typed it.

Posted: Tue Jul 18, 2006 6:21 pm
by Luke
OK... makes sense.

Posted: Tue Jul 18, 2006 6:34 pm
by John Cartwright
The Ninja Space Goat wrote:What is the difference between these?

Code: Select all

$instance->setVar('bla');

Code: Select all

$instance->Var = 'bla'
Seems to me they do the same thing. The first allows for Var to be private, but so what, it can be changed outside with the setter... what's the difference??
There are several reasons someone may want to use an accessor or setter, one being it will allow you to control values set to the variable. Lets say we want to make sure the variable being set is a string only:

Code: Select all

function setVar($value)
{
   if (!is_string($value))
   {
       //error
   }
   
    //set var
}
edit | *note to self*, don't start writting post then go grab snack

Posted: Tue Jul 18, 2006 6:36 pm
by Chris Corbyn
Jcart wrote:Lets say we want to make sure the variable being set is a string only:
I almost always typecast my inputs in setters.

Code: Select all

public function setRows($rows)
{
    $this->rows = (array) $rows;
}

Posted: Tue Jul 18, 2006 6:43 pm
by John Cartwright
d11wtq wrote:
Jcart wrote:Lets say we want to make sure the variable being set is a string only:
I almost always typecast my inputs in setters.

Code: Select all

public function setRows($rows)
{
    $this->rows = (array) $rows;
}
Comes back to the same idea that we want to control the variable, atleast forcing it to be a certain format. If I'm dealing with input, yes I also find it best to simply cast it to the proper format, although on system internals I prefer to spit some kind of error out, because inputting malformed data could lead to an error somewhere down the line.. perhaps.

Posted: Tue Jul 18, 2006 7:01 pm
by Jenk
I was about to post what has already been posted :)

It's the control over the property that made me decide to always use setters/getters. The getters can be used in places where the property is private/protected because I don't want the 'outside' to be able to influence it, yet will still require the data from it..

e.g. in one of my File classes:

Code: Select all

class jmt_File implements jmt_iFile
{
	private $size;
	private $path;
	private $type;
	private $name;
	
	public function __construct ($file, $path)
	{
		if (!file_exists($fullpath = realpath($path . '/' . $file))) {
			throw new FileNotFoundException ('File path given does not exist.');
			return;
		} 
		
		$this->path = $fullpath;
		$this->name = $file;
		
		$this->readProperties();
	}
	
	private function readProperties ()
	{
		if (function_exists('mime_content_type')) {
			$this->type = mime_content_type($this->path);
		} else {
			$this->type = 'application/octet-stream';
		}
		
		$this->size = filesize($this->path);
	}
		
	public function getSize ()
	{
		return $this->size;
	}
	
	public function getType ()
	{
		return $this->type;
	}
	
	public function getName ()
	{
		return $this->name;
	}
	
	public function getPath ()
	{
		return $this->path;
	}
}
The properties $size, $type etc. are needed elsewhere in my application, but I don't want the application defining them - that's left to the class/object to do so.

The readProperties() method should probably be protected incase I want to overload it with a child class in later life though.

Posted: Tue Jul 18, 2006 7:06 pm
by Christopher
Roja wrote:You don't see that happening in Jenk's comment "_ANY_ property in a class is to be set via a setter, and 'get' through a getter imo. "?

Thats what I was replying to, not to the overall, academic theory of PHP in the realworld (which I would argue is by an overwhelming majority in procedural code, not OOP).
I don't agree with Jenks' statement -- but rather than counter general yes with a general no, I think instead the issues about accessors should be discussed. As I said ... I don't think the answer is that easy.
Roja wrote:
Don't ask for the information you need to do the work; ask the object that has the information to do the work for you.
Ah, you've changed his phrasing, and thats what confused me. Now I get your drift (on that point).
My point of mentioning that is that the article you linked to (and its predecessor) where part of a large number of articles starting around five years ago that started to question some of the premises on which Java/J2EE was built. There are language reasons in part as to why Java took the route it did and then changed. That's why I say it is more a Java issue than a PHP one. PHP OO programmers are not being raised in that world but this one. That article also follow on from many older articles.
Roja wrote:Just because you don't agree with that design choice in ALL places doesn't make it a non-ideal comment to make in general. I also note that you haven't argued against the fact that a get/set is inappropriate in general because it is directly accessing implementation details. You are just arguing that making that statement as general as he is isn't reasonable enough - and since I'm contrasting it against Jenk's absolute statement, I'd say its incredibly balanced in comparison.
Balanced in their extremity. For me the main point is that there is no "in general" when it comes to accessors. For me it is like saying you should "in general use" conditionals and avoid loops. There are places where accessors are entirely the appropriate choice and places where they are not as good a choice. But you need to understand some of the current thinking about OO design to know where to draw the line. And I would note that ten years ago that dividing line was in a different spot than today, and that in ten years it might be in a different one.