Page 2 of 3
Re: private constants
Posted: Wed Jan 07, 2009 12:41 am
by Jenk
On the note of this being so dangerous that it must/should be private.. what's to stop them just changing it to public?
If someone wants to shoot themselves in the foot, be my guest. They'll probably try any way even if I do make the member private.
Chris: The point of the StreamWrapper wasn't just to wrap a Stream, but to restrict access to said stream. I.e. to control what goes in/out of it. Ergo, the stream cannot be accessed outside of the StreamWrapper interface. The class/object/scenario in question occured in Smalltalk, and was used to access Serial Ports on the machine. The constructor accepted a String for the label of the device (Linux box, so eg 'ttyS1').
I'll try to paraphrase as best I can in PHP.. but essentially it came to needing to mock a stream, to be able to test the wrapper did its job..
Code: Select all
public function testWritesFoobarToStream () {
$streamWrapper = new StreamWrapper('ttyS1');
$streamWrapper->writeToStream("a string");
// how to assert the StreamWrapper wrote 'a string' if we cannot access the member ?
}
The solution was to create an accessor/mutator for the stream (getStream()/setStream()).
Re: private constants
Posted: Wed Jan 07, 2009 10:10 pm
by josh
Jenk wrote:On the note of this being so dangerous that it must/should be private.. what's to stop them just changing it to public?
What's stopping them from screwing up the code in other ways? Its not about danger its about intent, its the fact that *something* visible breaks. If the code still ran they might not realize that change was "bad", If they want to make the change anyways then they change the visibility and they face the side effects
but essentially it came to needing to mock a stream, to be able to test the wrapper did its job..
The solution was to create an accessor/mutator for the stream (getStream()/setStream()).
If you don't need those on your public interface why would you be writing tests for them? If something doesn't affect outward behavior, and it isn't tested by a method that is public that is calling it, then its essentially just dead code and should be removed.
Re: private constants
Posted: Thu Jan 08, 2009 4:45 am
by Jenk
So how would you test that it does write to the stream, if you haven't got access to the stream, or to be more 'correct' the holding property of that stream? The desired behaviour of that object is that it writes to a stream. This is the fundamental behaviour, and the entire reason for that objects existence.
Are you telling me you wouldn't test it?
There is no problem with having accessors or methods that are only used by testing; within reason. Lazy loading and initialisers/setters can, and are used for this very purpose.
How do you think languages that don't have visibility restraints survived all these years? In php4, how did your code survive without "private"?
Re: private constants
Posted: Thu Jan 08, 2009 5:13 am
by VladSun
Jenk wrote:Is it really worth making anything private, be it a constant, a method, or property? The best, yet still not convincing argument, is that it is not part of the class/objects interface, and thus should not be used by anything outside of that object, but why is it there in the first place, if it is not to be accessed? Why must you completely restrict access? How can you be so certain that you won't want to override, or allow access in the future? (To prevent unnecessary discussion on this point, you can't. No, really, you can't.)

Example:
Final classes - read only or/and inner state properties.
Re: private constants
Posted: Thu Jan 08, 2009 6:32 am
by Jenk
"final" is more frustrating that private. If I want to override a class, it's because I have reason to override a class. If a class is "final" I cannot do this, so end up duplicating the class behaviour. In PHP this is not the case, I'll just un-final the class I need to override, but then it adds maintenance and technical debt to anything and everything I do in the future. If a new version of that software is released, I'll need to remember to un-final that class.
I absolutely detest "final" it is the most pretentious and headache inducing idiom in programming and whomever decided it would be a good idea needs to be shot.
Re: private constants
Posted: Thu Jan 08, 2009 7:00 am
by VladSun
In my practice, I'm trying to follow the concept that inheritance should be used just in a one level and everything else should be done by using composite objects.
I think it's more "program by interface, not by implementation" like.
So, I see "final" as an "injection-of-a-good-practice". It also applies to using private modifiers.
Re: private constants
Posted: Thu Jan 08, 2009 7:09 am
by Jenk
I see it as injection of prevention. The developer that used final/private/some other means of restriction has somehow decided that I will never want to use his or her code differently. Maybe they have a crystal ball that could tell me next weeks lottery numbers, too?
Composite object is not the most elegant solution for some use cases. If all I'm wanting to do is override a small piece of object behaviour. Let's take the hypothetical situation of a collection and me wanting to extend it to be a sorted collection, but I can't because collection is final.. a composite object on collection would be over the top.
Re: private constants
Posted: Thu Jan 08, 2009 7:18 am
by josh
If you didnt have private / public the framework creator would have to maintain a seperate list of things that were supposed to be called publicly and things that are inner implementation, "protected / public" just expresses that directly in code. Im not saying you have to use them for good practice and you raise interesting points, but after all they are optional... you really must hate them with a passion

Re: private constants
Posted: Thu Jan 08, 2009 7:48 am
by Jenk
No more of a passion than to not use them, and post on a public forum my opinion about them

Re: private constants
Posted: Thu Jan 08, 2009 5:53 pm
by alex.barylski
Jenk: If I understand correctly your primary issue with private is when it comes to testing TDD/BDD?
What is the alternative for you then? Keeping everything public seems to me would cause potential headaches for a client developer.
I personally think (as of now -- maybe you can change that) that a explicit separation of implementation from interface is applicable of every level of software development, including classes.
Private functions for me, are helper methods. Basically giving a block of code that is used exclusively by a class or a method a clear name, nothing more really.
That being said, if the code was kept inline in the public functions, the public function would suffer and possibly introduce duplication (DRY) not ot mention make the method more complicated/verbose (KISS).
If the function is called independently of pre-requsites than a failure is very likely. How do you give access to this function without that error from ever occuring? Do you document it? That seems counter-produictive.
Also, while I can see the issue being a PITA with TDD, isn't this a non-issue with BDD when mocking the object and just intercepting method calls?
If you are suggesting designing an interface in such a way that all methods are public, can you offer a real world of example of before (using privates) and after (using strictly public). Unfortunately that requires implementation code to, so if you don't have an example ready, don't worry about it, I'm just curious.
Maybe someone could find a class with a few methods, 3 or 4 privates and see how Jenk might refactor so that only public interfaces were available???
Cheers,
Alex
Re: private constants
Posted: Thu Jan 08, 2009 6:52 pm
by Jenk
The differences between any example I could give you would simply be that one will have the keyword private, the other will not.
My point is exactly this - nothing is safe, nothing should be 'made' safe, and everything should be visible. It is far safer if everything is visible, than it is with "hidden" features. Private/Protected/Final are just obscurities.
My distaste for restriction is not solely BDD/TDD, BDD/TDD simply highlights this issues which is what BDD/TDD are good for, and is what is their primary purpose.
No, it's the very fact that you, as the creating developer, have decided something for me. You have decided I should not have access to that member, you have decided I should not see it. If you use final, you have also decided I should not override, nor extend the behaviour. It is almost patronising. If the behaviour is there, I trust that it is warranted. If it is 'dangerous' then why the hell is it there in the first place?
Also on your last point, an interface is non-restrictive. So you've designed an interface, you may have even documented it already. Why are you not allowed to add more methods/members? Is there some magical barrier? If documentation is the reason, use PHPDoc and presto: automatic documentation.
There has never been a time when I've thought "whew, thank god that was private/final/whatever" but countless times I've moaned "oh for God's sake, why is that private/final/whatever?"
Re: private constants
Posted: Thu Jan 08, 2009 7:17 pm
by alex.barylski
My point is exactly this - nothing is safe, nothing should be 'made' safe, and everything should be visible. It is far safer if everything is visible, than it is with "hidden" features. Private/Protected/Final are just obscurities.
I guess I see access control as slightly different. More of a language construct to help enforce best practices, rather than hinder client developers. When I make something private it's because I know it's only ever useful in a certain context, which is typically setup via a purblic call.
My distaste for restriction is not solely BDD/TDD, BDD/TDD simply highlights this issues which is what BDD/TDD are good for, and is what is their primary purpose.
I hear ya. If I can appreciate anything TDD it's the fact that it forces your code to remain simple and dependency free.
No, it's the very fact that you, as the creating developer, have decided something for me.
I think that is inherent in all levels of software. I make executive decisions constantly, whether it be an interface, database design, implementation, etc. When I know a method called out of context will result in failure or weird results, that is generallyan indication for me to keep it private.
You have decided I should not have access to that member, you have decided I should not see it. If you use final, you have also decided I should not override, nor extend the behaviour. It is almost patronising. If the behaviour is there, I trust that it is warranted. If it is 'dangerous' then why the hell is it there in the first place?
Not nessecarily dangerous...but possibly pointless in the public context so why make it available?
Also on your last point, an interface is non-restrictive. So you've designed an interface, you may have even documented it already. Why are you not allowed to add more methods/members?
An interface (or rather an object) IMHO is best implemented following OCP. Certainly you should be able to add methods to a class, through extension, not from core hacking. If I have made a method private, it's likely because it's a helper method to simplify a public method(s) and reduce duplication (or eliminate it outright). It's not intended to be called in it's own context.
There has never been a time when I've thought "whew, thank god that was private/final/whatever" but countless times I've moaned "oh for God's sake, why is that private/final/whatever?"
Obviously it was open source? Why not change it as required? Although I can see that being a serious PITA and easily avoided if the developer only used private/protected as the exception rather than the rule. Like most programming constructs, etc...if it's abused it becomes counter-productive.
Cheers,
Alex
Re: private constants
Posted: Thu Jan 08, 2009 11:20 pm
by Chris Corbyn
Jenk wrote:On the note of this being so dangerous that it must/should be private.. what's to stop them just changing it to public?
If someone wants to shoot themselves in the foot, be my guest. They'll probably try any way even if I do make the member private.
Chris: The point of the StreamWrapper wasn't just to wrap a Stream, but to restrict access to said stream. I.e. to control what goes in/out of it. Ergo, the stream cannot be accessed outside of the StreamWrapper interface. The class/object/scenario in question occured in Smalltalk, and was used to access Serial Ports on the machine. The constructor accepted a String for the label of the device (Linux box, so eg 'ttyS1').
I'll try to paraphrase as best I can in PHP.. but essentially it came to needing to mock a stream, to be able to test the wrapper did its job..
Code: Select all
public function testWritesFoobarToStream () {
$streamWrapper = new StreamWrapper('ttyS1');
$streamWrapper->writeToStream("a string");
// how to assert the StreamWrapper wrote 'a string' if we cannot access the member ?
}
The solution was to create an accessor/mutator for the stream (getStream()/setStream()).
I still don't get it. How would I be supposed to know what the "private" stream was called inside the class? What I DO know however is how to read ttyS1 I don't need to inspect the implementation of StreamWrapper to know that it *should* write to ttyS1. All I'd have to test is that ttyS1 was written to, and not that some hidden property of StreamWrapper is written to.
Perhaps it's even possible to register a mock tty stream and use that? Either way, I still don't see what accessing private data has to do with it
Effectively your example translates to something like this:
Code: Select all
$wrapper = new StreamWrapper("/path/on/filesystem");
$wrapper->writeToStream("foo");
$this->assertEqual("foo", file_get_contents("/path/on/filesystem"));
//Not
$this->assertSomethingWith($wrapper->_internalValue);
Re: private constants
Posted: Fri Jan 09, 2009 3:27 am
by Jenk
It would be a logically named item, and would need to be accessible (and documented etc. etc.) In that particular example, we didn't access the property directly, we injected a mock via setStream(). The subtle yet significant difference was that we are not constructing a class that writes to a port, we are constructing a class/object that writes to a Stream on that port. We know what the interface of the Stream was/is, so in actual fact it did not matter what label we fed the object (for testing purposes) in the end. Which also removed the dependency on having a physical ttyS1. Bonus.

Re: private constants
Posted: Sun Jan 18, 2009 6:28 pm
by Chris Corbyn
I'd also just like to point out that "private" has different behaviour public and protected when it comes to scope and naming conflicts too. By changing everything to public/protected it's not as clear-cut as saying it should "just work", they have different semantics and influence behaviour:
Code: Select all
<?php
class PublicSuperclass {
public $_prop = 42;
public function getProp() {
return $this->_prop;
}
}
class PublicSubclass extends PublicSuperclass {
public $_prop = 7;
}
$public = new PublicSubclass();
printf("Public _prop is %d\n", $public->getProp());
class ProtectedSuperclass {
protected $_prop = 42;
public function getProp() {
return $this->_prop;
}
}
class ProtectedSubclass extends ProtectedSuperclass {
protected $_prop = 7;
}
$protected = new ProtectedSubclass();
printf("Protected _prop is %d\n", $protected->getProp());
class PrivateSuperclass {
private $_prop = 42;
public function getProp() {
return $this->_prop;
}
}
class PrivateSubclass extends PrivateSuperclass {
private $_prop = 7;
}
$private = new PrivateSubclass();
printf("Private _prop is %d\n", $private->getProp());
Output:
Public _prop is 7
Protected _prop is 7
Private _prop is 42