1

I have heard a prominent language designer remark that no language today enforces real object privacy, and we are still unsure whether it is possible in practice to design a language that does.

Without trying to read this particular person's mind, this piqued my interest. There are, I think, two distinct concepts at work here:

  • Languages with class-level privacy almost always provide ways to work-around it - for example with introspection. Are these workarounds necessary, in that their absence would make certain problems much harder to solve in the language, and if so, doesn't that indicate that the privacy paradigm is flawed? In other words, do people (ab)use these mechanisms when they are provided, and why?

  • Class-level privacy is not object-level privacy (an object has access to private state of other objects if they are of the same class), and we don't know how to do the latter. But why would we want to?

  • you said class-level privacy is not object-level privacy, but you didn't explain what you think "class-level privacy" is, just that we don't know how to do it. I think you'll need to explain a little better what you think it is and why we can't do it, because "class-level" instead of "object-level" tends to be a distinction people use to refer to type-statics where a given type has a single member across process scope, which can most definitely be private...so, what are you getting at here? Also you gave one example of working around privacy, but not all languages support it. – Jimmy Hoffa Oct 4 '14 at 5:35
  • 1
    also "object-level privacy" is not a paradigm, I think you're referring to a particular language feature, and likely one that is only relevant in OO languages I'm guessing. Again, you really need to explain what you're referring to here with more detail, right now you're vaguely referring to things without enough detail for us to know what you mean. If you're not certain what it is you're referring to that's fine, but perhaps you should describe it rather than using terms that might be ill fitting to the feature you're referring to as the terms may just be confusing the point. – Jimmy Hoffa Oct 4 '14 at 5:38
  • I have edited the question. This is indeed only relevant to OO languages. You make the example of singletons (I know OO does not have to mean class-based, but my vocabulary fails me if I try to step outside of that); however making objects one-of-a-kind has lots of implications besides privacy. I imagine you could design a language where private state is private to the instance and not the class. – dgirardi Oct 4 '14 at 6:12
  • It's not difficult to use - it's difficult to implement. And I'd say that the reason why we want it is because that's what any sane observer would expect: one Person should not automatically get access to another Person's password merely because they are both Persons. – Kilian Foth Oct 4 '14 at 7:55
  • @KilianFoth: note that information hiding isn't a security feature, as it's generally easy to circumvent within a program. Your example is better handled by capabilities. – outis Oct 4 '14 at 12:35
2
  • Languages with class-level privacy almost always provide ways to work-around it - for example with introspection. Are these workarounds necessary, in that their absence would make certain problems much harder to solve in the language

Reflection and introspection are particularly useful in white-box testing, so as to ensure code coverage and implementation requirements. For this, access relaxation in reflection is necessary. Language-level tools (depending on the runtime) may also make use of reflection (imagine a native debugger which needs to access private fields).

Some would argue that if a class is properly designed, white-box testing (hence, access relaxation) of the private interface isn't necessary. Since an object's interactions with other objects is defined by its public interface (or, in the case of relatives, its public & protected interfaces), the private interface is immaterial. If the class is so complex as to require testing the private interface to ensure stability, the argument goes, then the class likely has too many responsibilities and should be refactored into multiple classes.

In some cases, casting in C++ can be used to access private fields, but this isn't an intended use.

Inheritance can be used to relax access restrictions, but this isn't a workaround so much as an intersection of access and inheritance rules, and is suggested by the LSP.

and if so, doesn't that indicate that the privacy paradigm is flawed?

Note that white-box tests and debuggers aren't a part of the software's normal execution, so circumventing access rules doesn't (in these cases) negate their purposes.

In other words, do people (ab)use these mechanisms when they are provided, and why?

I'd consider this to be a separate question from the earlier one. People definitely abuse reflection and inheritance to improperly relax access. I'd say typically when it happens it's because there's a design flaw in the program (not the language), but that's more opinion than not.

Casting to circumvent private access is abuse.

Increasing access using inheritance is often (always?) abuse. Sometimes it's another kind of design flaw: naming collision, in this case arising when you override a private base method with an unrelated public method that happens to have the same name & signature.

  • Class-level privacy is not object-level privacy (an object has access to private state of other objects if they are of the same class), and we don't know how to do the latter.

On the contrary, in Ruby, no instance variable is accessible to another instance, even of the same class; the same goes for private methods. The Ruby term is "instance-private", rather than "object-level private". The same is true of Eiffel and functional-OOP style (where objects are functions that take a message). Smalltalk has instance-private fields, but no true private methods. Scala supports instance-private members.

In general, accessing instance fields outside of an instance isn't syntactically possible in languages that purely use a messaging model rather than a method-call/member-access/slots model, so the former have instance-private fields, though the feature isn't necessarily exclusive to them.

See also "Why are private fields private to the type, not the instance?".

But why would we want to?

The same secondary reason as for all forms of information hiding: anything that can overwrite state is a potential bug source; limiting an object's surface as much as possible helps cut down on the number and locations of potential bugs.

0
  • Class-level privacy is not object-level privacy (an object has access to private state of other objects if they are of the same class), and we don't know how to do the latter. But why would we want to?

Object-level privacy makes some kinds of encapsulation difficult / impossible to achieve. For example, consider an object that represents a log file format:

class i_write_things
{
    std::ostream* writer;
public:
    bool equal(i_write_things const& other) { return this->writer == other.writer; }
    void write_to(std::string const& message) { /* ... */ }
};

If object-level privacy was in use, the equal implementation wouldn't be able to see writer in the other instance of i_write_things. As such, you would need to create a getter for this property in order to implement equal, which is worse encapsulation: it exposes that the internal implementation of i_write_things uses an ostream.

  • Even with object-level privacy, one could implement equal by having a method usesWriter(ostream *writer) and then equal(i_write_things const &other) { return other.usesWriter(this->writer);}. – supercat Jul 25 '15 at 21:47
  • @supercat: That still exposes that an ostream is in use to clients which is the undesirable encapsulation loss here. – Billy ONeal Jul 25 '15 at 22:33
  • @supercat That's not any better protection. Pirate-object: usesWriter(i_write_things const &other) { DoEvilThings(other); return false;}. That's unless you cannot mock that function. – Deduplicator Jul 25 '15 at 22:34
  • @Deduplicator: You're right; I oversimplified. Doing things properly requires a "trustworthy" class which is instantiated with data from one class object and can do specific actions in relation to another; in systems that support value types, such a thing can be pretty efficient and versatile. For example, if .NET included a suitably designed helper class for the purpose and had IReadableList<T> or a variant thereof support it, it would be possible for any implementation of that type to allow its contents to be quickly copied into an array in such a fashion that... – supercat Jul 26 '15 at 1:02
  • ...the data source could have the data split into multiple backing sections without exposing that fact (or the arrays themselves), and the destination could know that the helper class would never expose the array to the data source, but the helper class would still be able to use bulk-copy operations to move data in cases where the data source could accommodate that. – supercat Jul 26 '15 at 1:05
0

If class Foo accepts references to objects of its type from outside code and uses private members thereof, then outside code will need to use references of type Foo or one of its subtypes. If Foo didn't need to use private members of its own type, but it implemented an interface which included all the members it did need to use, then it would be possible for outside code to use that interface type instead of Foo, allowing such code to work with other implementations of that interface.

It would be possible for Foo's methods to accept parameters of the interface type even if the language didn't enforce object-level privacy, but it wouldn't be able to access any of the private members of the objects identified by those interface references. Nonetheless, the ability of Foo's methods to make use of private members of passed-in references may serve to discourage the use of more general types as message parameters.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.