3 ms·
> There are other ways to encapsulate besides private member functions. Could you elaborate a bit here? I've searched for solutions in this area before without
by Xenograph 6y ago
> There are other ways to encapsulate besides private member functions.
Could you elaborate a bit here? I've searched for solutions in this area before without much success. I'd be interested to hear more.
- wa1987 6y agoMaybe he's referring to closures.
- humanrebar 6y agoFor instance, yes. And some languages and idioms also allow objects to be provided without exposing their types at all. Declared but undefined types, for instance . And all languages would support opaque IDs as alternatives to references that expose irrelevant or harmful APIs.
- mumblemumble 6y agoI'm obviously not who you're asking, but I'm going to cheekily show up with my own thoughts on the subject, anyway: I'm coming to the opinion that, if you need private member functions to retain encapsulation, that's a strong sign that your design was never properly encapsulated in the first place. The motivation for making something private is to prevent people from breaking your object by messing with things they shouldn't. Generally speaking, only real way for it to be possible break an object is if its internal state is complicated enough to allow that to happen in the first place. Which is itself a failure of encapsulation. Somewhat more concretely: If you've got to private fields A and B, where any change to A must be accompanied by some corresponding change to B, and the logic for enforcing that rule needs to be enforced at several places within your class, then, at the level of abstraction your object is operating at, A and B represent a single logical entity, and should never have been represented as individual fields in the first place. They should have been encapsulated into their own object. Even more concretely: Don't do this: class Thing { val counter = 0; fun foo() { val x = counter; counter++; ... } fun bar() { val x = counter; counter++; ... } } And don't do this: class Thing { val counter = 0; fun foo() { val x = counter_next(); ... } fun bar() { val x = counter_next(); ... } private fun counter_next() { val x = counter; counter++; return counter; } Do this: class Counter { int state = 0; fun next() { val x = state; state++; return x; } } class Thing { val counter = Counter(); fun foo() { val x = counter.next(); } } Very abstractly: Composing objects is the core idea behind OOP. In general, the more object-oriented design is the one that favors object composition over other language constructs whenever possible. Also, this is all arguably a separate issue from using privates simply to avoid cluttering your public interface when factoring code. If you're working in a language that doesn't really have good nested functions, private methods are your next best choice.
- Xenograph 6y agoThanks for the detailed explanation, but I realize that I was misreading the whole time and so you answered a question that I actually didn't mean to ask. Apologies. Instead of 'private member functions' my mind read 'member functions'. For instance, I'd love to be able to create functions that operate on a Vector3 interface type in Typescript, but don't have the clunky syntax of > AddVec3(AddVec3(v1, ScaleVec3(v2, DotVec3(v4, v5))), v4). Classes in Typescript solve this just fine, so that I can do > v1.add(v2.scale(v4.dot(v5))).add(v4) But then I lose the benefits of structural typing. I still have yet to find a nice solution here.