|Think about Loose Coupling|
Re: Re: Re: Re: Re: This is why I use Perlby tilly (Archbishop)
|on Nov 08, 2003 at 23:28 UTC||Need Help??|
To me this is not about the ability or capability of a given language, but about the principles of encapsulation, OO programming and the best practice for OO programming. You don't do things that's doable, if they are not the best practice.
I strongly suspect that you misunderstood the point of what I was trying to say. Probably because I didn't describe it in enough detail for you to clearly visualize what I described. So here it is in detail.
In Ruby it is customary that if you want to write get/set methods for an attribute named, say, bar, you name the get method bar, and the set method bar=. The reason is that Ruby has a nice piece of syntactic sugar, foo.bar = baz is translated into foo.bar=(baz). Therefore people can use your get/set methods in a simple way. Now lets take a simple piece of working Ruby to show this in practice:
And you see that you have normal get/set methods under the hood, in which we don't do much. They are, in fact, equivalent to the ones that you wrote above.
Now let me write the same class in a different way:
This is exactly the same as what I already had, except that I did less writing and the necessary bar and bar= methods will be implemented natively and hence run a bit faster.
Therefore in Ruby if you have decided to write loads of public get/set methods, there is absolutely no reason to write them yourself. Just declare a bunch of public (yes, Ruby allows you to differentiate between public, private, and protected) ones with attr_accessor instead. If one of those accessors needs to do something more complex later (like add validation), that is easily enough changed later, transparently to existing code.
The decision about whether to have public get/set methods is an entirely tangential question.
In Perl you can do something similar, but the case for doing it is far weaker than it is in Ruby. If you have created your objects like most people do, as anonymous hashes, then you can move the implementation elsewhere and replace the anonymous hashes with anonymous tied hashes. You now get the ability in your FETCH, STORE, DELETE etc methods to hide specific fields, sanity check others, etc. All transparently to existing code.
One way that you could do it is take what I did at Class::FlyweightWrapper and modify it by having the wrapping objects be references to tied anonymous hashes (with an arbitrary tying class) rather than anonymous scalars. This is doable, but takes a fair amount of work, and as I said, is clearly a suboptimal approach. I might consider it as a retroactive fix for a bad situation, but I wouldn't plan on doing things that way.
In Java if someone has decided to allow the properties of an object be directly exposed, I don't believe that you can later replace that with get/set methods without having to visit existing code that used the old API. Therefore the possibility that you might some day, maybe, want to change your implementation and do something sophisticated in your get/set methods means that you must now hide properties and write get/set methods.
Therefore while the principles of encapsulation, OO programming, etc do not change between languages, best practices may. In particular what is best practice in Java (writing lots of simple get/set methods) is not best in Ruby because the capabilities of the language give you a better option. In Perl if you get it wrong, you theoretically can fix things afterwards, but probably don't want to because the ways of doing it are problematic.