• Mr.'; Drop Database -- (unregistered) in reply to Abscissa
    Abscissa:
    But with modern languages that support accessors, that practice has (for the most part) become rendered an ugly and unnecessary kludge, since you can now add extra processing while maintaining variable-access syntax
    You will do better in debates if you address the points that people actually use, rather than the ones you wish they'd use. At least skim their arguments so you know what their point of view is. The prevailing point of view in this thread is that, in C#, it's not worth breaking binary compatibility just to avoid typing "{ get; set; }" a bunch of times. If you disagree with that, that's fine, but don't act like the argument doesn't exist.
  • j-kidd (unregistered) in reply to Mr.'; Drop Database --
    Mr.'; Drop Database --:
    Abscissa:
    But with modern languages that support accessors, that practice has (for the most part) become rendered an ugly and unnecessary kludge, since you can now add extra processing while maintaining variable-access syntax
    You will do better in debates if you address the points that people actually use, rather than the ones you wish they'd use. At least skim their arguments so you know what their point of view is. The prevailing point of view in this thread is that, in C#, it's not worth breaking binary compatibility just to avoid typing "{ get; set; }" a bunch of times. If you disagree with that, that's fine, but don't act like the argument doesn't exist.
    That means C# is not a modern language that supports accessors. It just pretends to be one.
  • Shabbyrobe (unregistered)

    On the topic of getters and setters in PHP, they're mostly pointless and they're a waste of resources especially without an opcode cache. On my setup, I made two crappy classes, one with five private fields encapsulated by five getter/setter pairs proxying the field (which looked almost exactly like java code, funnily enough) and another with five public fields, and called memory_get_usage() at the end after creating an instance. The script with the getter/setters used 59708 bytes of memory and the script with the public fields used 49244 bytes.

    In the context of a class library of any significant size, such as a web site framework, these useless getters and setters can add up to a HUGE black hole for memory. I have been developing a framework for my employer in PHP (their choice, not mine. i wouldn't use it for this if i had the choice but having said that, PHP is not imposing any insurmountable restrictions on us) and when I refactored the class library to use public fields instead of getters/setters, the whole shebang ended up using 25% less memory per request at least, and when I replaced all calls to /(require|include)(_once)?/i with calls to a class loader which only includes files if the class is actually instantiated or extended, it was another 25% saving again. We went from 4 to 6.5 meg of memory per request to 1.5 to 3.2, and we have about 350 classes in our library and growing. Why interpret classes on every request if you're not actually using them?

    I do something with __get() and __set() (and __isset() and __unset()) that the language should (but doesn't for backward compatibility's sake) - I put them in a class from which EVERY other class I write extends, and make them throw a damn exception if the field doesn't exist. I hate it how you can have this situation:

    class Test {
    	public $field = "LA DI DA";
    	public $field2 = "ZZZZ"; // i'll explain this one later
    }
    $t = new Test;
    $t->feild = "DE DE DUM";
    var_dump($t);
    // output
    object(Test)#1 (2) {
      ["field"]=>
      string(8) "LA DI DA"
      ["feild"]=>
      string(9) "DE DE DUM"
    }
    

    YUCK!

    <?php
    abstract class Object {
    	public function __set($key, $value) {
    		throw new Exception(sprintf('Oh my god your life is so much less shit... the property %s doesn't exist, something tried to use it, and now you know exactly where.', $key));
    	}
    }
    
    class Test extends Object {
    	public $field = "LA DI DA";
    }
    $t = new Test;
    $t->feilddafsdf = "DE DE DUM"; // KABOOM!!!!!!!!
    

    Ahh, that's better.

    So we can have it both ways - crappy old code gets to benefit from PHP5's improved object support, and our nice new code can fail as it should. That's not a bad thing.

    But the __get(), __set() and __call() 'magic' methods really shine for handling interface changes. With an interpreted language it's a bit harder to find all usages of a field or method even with the reasonably good support for code sensitivity provided by Eclipse PDT or Netbeans. Say we want to rename 'field' from the prior example to 'fieldWithBetterName', because 'field' was inappropriate, or no longer described the use accurately, or was just plain wrong. And say we wanted to change field2 to lazy load its value from the database because it isn't known initially...

    ClassLoader::load("Library.CrapDbLayer");
    ClassLoader::load("Library.DebugUtils");
    ClassLoader::load("Library.Object");
    
    class Test extends Object {
    	public $fieldWithBetterName = "LA DI DA";
    	private $_field2;	
    
    	public function getField2() {
    		if ($this->_field2 == null) {
    			$this->_field2 = CrapDbLayer::getSomething($this->fieldWithBetterName);
    		}
    		return $this->_field2;
    	}
    	
    	public function __get($name) {
    		static $refactor = array('field' => 'fieldWithBetterName');
    		if (isset($refactor[$name])) {
    			Logger::log("use of deprecated property... blah blah blah\n".DebugUtils::printBacktrace());
    			return $this->{$refactor[$name]};
    		}
    		else return parent::__get($name);
    	}
    }
    $t = new Test;
    echo $t->field;
    

    And you can go backwards with __call(). This example is much more brittle, but it's not hard to clean up:

    class Test extends Object {
    	public $field2;
    
    	public function __call($name, $args) {
    		if (strpos($name, 'get')===0) {
    			$field = lcfirst($name); // cheating, i know. php 5.3 or greater. not hard to do without it though.
    			return $this->$field;
    		}
    		parent::__call($name, $args);
    	}
    }
    

    Getter and setter methods in PHP are good if the setter has to do something else, or if the getter has to lazy load something, or ensure something has been created, or whatever, but they're unnecessary and wasteful if they do nothing other than proxy the field.

    PHP gets a lot of crap - especially around here - for being a toy language. I think it has a similar reputation to VB.NET. There are a lot of crappy crappy crappy developers writing the lowest imaginable quality code for them because the barrier to entry is so low, but if you've got no choice but to use the technology, you've your wits about you, you care about how your code looks and works, and you learn a few really simple techniques like the ones I hackily mentioned above, there's no reason for them to function as the toys they're perceived to be. VB.NET is very nearly functionally equivalent to C#. It's certainly trivial to port C# to VB.NET (not so much so the other way around depending on how much the Microsoft.VisualBasic namespace has been abused).

    PHP has a LOT of faults, but if you're a halfway decent developer, there's no way your PHP code will look or act anything like all of the shit that informs the stereotype.

  • Dag (unregistered) in reply to Misha

    A watch doesn't allow you to break whenever a field changes. And in fact with .net the generated debug code doesn't support breakpoints based on memory locations changing, which is all that happens when a field is set.

    BUT... as with all things programming, there are no dogmatic answers. Encapsulation is not equally important in your tiny desktop app (where you're recreating Notepad for some inexplicable reason) as it is in your library code. If all the code is in one assembly and app-specific a purist may argue that you don't need the members to be public at all. I'd be more pragmatic and say it doesn't matter in such a case. If you've used fields and the need arises to change what happens, or even to get that breakpoint possibility, just change it to a property and rebuild.

    Obviously whenever you cannot be 100% sure that you can easily rebuild any and all code that might depend on the member, you should use properties and not fields, as the cost is extremely small (an extra "{ get; set; }" in current C#) and the potential benefit is huge.

  • Dag (unregistered) in reply to Shabbyrobe

    Try to repeat your memory-usage test with 100 instances of each type and see what percentage difference you then get. As you know, methods (recalling that properties are pairs of methods following certain conventions that allow using the same syntax as that of reading and writing fields) are loaded into memory once for ALL instances, while each instance necessarily has it's own storage that the methods operate on, such as the field backing a property.

    Personally I doubt I would ever encounter a situation in which the total memory consumed by all instances of a type increasing by 10K would make me even consider dropping the accessors in favor of public fields.

    In order not to be a hypocrite I shall admit that I sometimes use public fields, but only for things like playing around, for code that isn't supposed to live long, and where I know I can rebuild all the code using the member whenever I'd like to, hence making it easy to turn a field into a property should the need arise.

  • Mr.'; Drop Database -- (unregistered) in reply to Shabbyrobe
    Shabbyrobe:
    ClassLoader::load("Library.CrapDbLayer");
    ClassLoader::load("Library.DebugUtils");
    ClassLoader::load("Library.Object");
    You can tidy this even further with spl_autoload_register (it's a builtin function introduced in 5.1.2).
  • Ze (unregistered) in reply to csrster
    csrster:
    The real WTF is that some people think that public setters and getters are a form of encapsulation. They're not. They're a way of exposing the contents of an object through its API, which breaks encapsulation. Sometimes it's necessary, but extensive use of public accessors and modifiers is very often a sign of bad design.
    That is the real WTF.

    People who make a bunch of private variables and then expose them all by get and set methods and think they are writing good code is the real WTF. The whole point of object orientation is encapsulation.

    Think about your design first and keep rethinking it all the time and you will eventually learn how to properly encapsulate your data and where get and setters are appropriate.

    Personally I've always been of the opinion that you make data private/protected , write the methods you need and add get and setters as needed oh and just because you've got a get or a set method doesn't mean you need the other one for that variable.

    BTW all those folks bitching about C++ , the upcoming C++0x has accessors/properties from memory.

  • fgb (unregistered) in reply to Mr.'; Drop Database --
    Mr.'; Drop Database --:
    Abscissa:
    But with modern languages that support accessors, that practice has (for the most part) become rendered an ugly and unnecessary kludge, since you can now add extra processing while maintaining variable-access syntax
    You will do better in debates if you address the points that people actually use, rather than the ones you wish they'd use. At least skim their arguments so you know what their point of view is. The prevailing point of view in this thread is that, in C#, it's not worth breaking binary compatibility just to avoid typing "{ get; set; }" a bunch of times. If you disagree with that, that's fine, but don't act like the argument doesn't exist.

    A prevailing point of view is 3 people? It's not like you've addressed every point here.

  • Shabbyrobe (unregistered) in reply to Dag
    Try to repeat your memory-usage test with 100 instances of each type and see what percentage difference you then get.

    It's more about interpretation overhead than execution. I had reservations the overhead would increase drastically based on the number of instances created, and the quick test I ran seems to bear this out: the public field one uses 95k with 100 instances in memory and the getter/setter one uses 110k with 100 instances in memory.

    Here's the code for the field one. You can guess what the getter/setter one looks like ;)

    <?php
    class Test {
    	public $field = "LA DI DA";
    	public $field2;
    	public $field3;
    	public $field4;
    	public $field5;
    }
    $instances = array();
    for ($i = 0; $i < 100; $i++) {
    	$t = new Test;
    	$t->field2 = time();
    	$instances[] = $t;
    }
    var_dump(memory_get_usage());
    

    This is for just one class too. So without the instances in memory, we're looking at a 10k difference and with them we're looking at 15k, which also includes 100 timestamps.

    Personally I doubt I would ever encounter a situation in which the total memory consumed by all instances of a type increasing by 10K would make me even consider dropping the accessors in favor of public fields.

    but the whole point of my previous ramble was to demonstrate that getters/setters in php are not only a waste of resources, but they're also completely unnecessary because the language provides all the tools you need to transition between a public field and a getter/setter seamlessly and efficiently when you decide that the getter/setter needs to do more than simply proxy a field.

    So it's basically a moot point... you can have it both ways with public fields and the __get()/__set() magic methods, so why not favour performance? if you've got a large enough class library with dozens to hundreds of fields, there is no disputing that the memory saving is significant when we're talking about 2-3k less per field per request compared with getter/setters.

    PHP is also markedly slower when pushing another method on to the stack, so all of those unnecessary gets and sets are a waste of CPU cycles as well.

    <?php
    class Test
    {
    	public $n;
    	public $z;
    	public function doStuff() {
    		++$this->n;
    		++$this->z;
    	}
    }
    class Test2
    {
    	public $n;
    	public $z;
    	public function doStuff() {
    		++$this->n;
    		$this->doOtherStuff();
    	}
    	public function doOtherStuff() {
    		++$this->z;
    	}
    }
    $count = 100000;
    $s = microtime(true);
    for ($i=0; $i<$count; $i++) {
    	$t = new Test;
    	$t->doStuff();
    }
    var_dump(microtime(true) - $s);
    
    $s = microtime(true);
    for ($i=0; $i<$count; $i++) {
    	$t = new Test2;
    	$t->doStuff();
    }
    var_dump(microtime(true) - $s);
    
    // output:
    // float(0.40908789634705)
    // float(0.6473970413208)
    
    You can tidy this even further with spl_autoload_register (it's a builtin function introduced in 5.1.2).

    Of course! How do you think ClassLoader knows when to load ;) ?

    (require|include)(_once)? all read the file and interpret the type immediately. If you register a class loader with spl_autoload_register, then register all your includes with the class loader, they all only get interpreted on demand.

  • Mr.'; Drop Database -- (unregistered) in reply to Shabbyrobe
    Shabbyrobe:
    Of course! How do you think ClassLoader knows when to load ;) ?
    If you use it properly, you don't need to call ClassLoader::load at all. Just register your autoloader and let PHP call it for you.
  • Iain Collins (unregistered) in reply to Michael
    Michael:
    Does this mean if I provide a DLL with a class that has a public field and later change that public field to a property that the DLL will no longer work with applications that were compiled using the old version?
    Well, I just checked that and it's true. The old executable won't work with the new class library. That's the most convincing reason I've seen yet. In C# at least, you really can't freely convert between properties and public fields if you want classes to be usable by external consumers. That's another vote for python in my book, and it's good to know when writing C# code.
    That's interesting (and disappointing - not the behavior I expected), thanks for posting.
  • coolguy (unregistered) in reply to Jon

    he he... FatCatException ..

  • vane (unregistered) in reply to dkf

    That comment is not a troll. It isn't an argument against making public fields private with public accessors. It is an argument against having every field of every class you make private and those fields having public accessors. The original poster says this limits encapsulation and it does! I (and probably the OP) would argue that such classes should "do more", while hiding more from other classes.

  • (cs) in reply to Michael
    Michael:
    by Don't get it:
    You're both right. It is extra code, which takes up time and space and can make tings less clear. But those get/sets can be life savers if you ever need to instrument the code to count accesses or you need to scale or audit the data before returning it.
    Why can't you make them properties later, when you find out there's a need to count accesses or whatever? What advantage is there to writing them as properties ahead of time?

    This actually came up as a response in an interview for a candiate recently. They were completely unaware that such a change is a breaking change. If you have other code that is expecting a field and you change to a property then everything is broken unless you recompile all of the client code. Even worse in languages/platforms that provide Reflection (such as .NET) where all of a suden the item will no longer be found.

Leave a comment on “Try Doing That with a Field”

Log In or post as a guest

Replying to comment #250826:

« Return to Article