|
![](/i/fill.gif) |
Warp wrote:
> Darren New <dne### [at] san rr com> wrote:
>> 1) They're enforced 100%. Nobody outside the class is capable of writing to
>> or reading from a private variable. This provides maximum isolation at the
>> expense of not having available at runtime lots of stuff the compiler knows
>> at compile time that you might want to know (e.g., reflection type stuff).
>
> If you need to know the private members of the class from the outside,
> then that class has been badly designed.
>
> With a well-designed class you don't *need* to know, nor care.
Not all uses of reflection come from outside the class, and not all uses of
reflection violate modularity. For example, the ability to instantiate an
instance of a class whose name you have in a string is technically
"reflection". That doesn't break modularity.
>> 2) They're enforced 100%, but people outside the class can read but not
>> write them. This is a little more fragile to change
>
> It breaks modularity badly. The whole idea of data hiding is that the
> private part should be completely opaque to the outside. The second it
> isn't, outside code will start making assumptions, and you can't change
> the implementation of the class anymore.
Right. That's what I meant by "it's more fragile to change."
> Some people argue that accessors to all private members, especially if
> they are automatically generated, is almost as bad as having all the
> members public.
It seems semantically identical to me. :-) Of course, if you can override
the private accessors, you might be able to keep some sorts of compatibility.
> It exposes the internal implementation, and thus outside
> code will start making assumptions about it, making it harder to change
> the implementation later.
>
> Some accessors may be justifiable, but you should not go overboard.
Agreed. I'm not advocating that people access private members without
knowing what they're doing and why. I'm not advocating they access private
members when they can change the module to reveal what they need revealed.
>> 3) They're enforced, but there are explicit mechanisms to bypass them, such
>> as reflection. This is my personal preference, because it's easy to find the
>> places in the code that might be breaking your invariants or might rely on
>> your internal implementation, while providing the power of metadata. This is
>> the C# and Java model.
>
> If you don't have access to the code which is making assumptions about
> your class' internal structure, you can't change your class without breaking
> that existing code.
It depends what assumptions are being made by the code you don't have. It's
also the case that it's not uncommon for things like reflection to be used
internally to the class or the module to replace what would otherwise be
fragile boilerplate code.
If the code that violates modularity adjusts automatically when you change
the class being violated, it's in practice capable of handling far more
kinds of changes than one might expect.
> Sure, this situation might not be extremely common, but it can happen.
> And it's something which might have been avoided with a good interface
> design and a completely opaque private implementation.
Agreed. The problem comes when you're stuck with a bad interface design and
an opaque implementation. :-) Surely, you don't imagine that reading the
source code of a class implementation and then using internal functions to
get the values of private variables is a normal way of programming LISP objects?
>> 4) They're enforced by the compiler but not by the runtime. This removes
>> *both* the ability to debug your module in isolation *and* the ability to do
>> metaprogramming that eliminates boilerplate by using the information the
>> compiler has already calculated.
>
> Why would you want runtime checks if access rights could be fully checked
> at compile time?
I wouldn't. I don't know any languages that fully check access rights at
compile time that don't provide well-defined standard mechanisms for
bypassing them at need.
>> 5) They're not enforced by the compiler or the runtime, but there are
>> conventions and/or standards that make it obvious to everyone when you're
>> breaking the data encapsulation, and the runtime ensures that you can only
>> do this "on purpose". That is, the unenforced conventions (or enforced but
>> bypassable mechanisms) ensure that the only way of breaking encapsulation is
>> on purpose. This is almost as good as #3, except it may be harder to track
>> down who is violating your invariants.
>
> Again, if you must keep "reverse compatibility", for a lack of a better
> term (in other words, you as a library developer must maintain compatibility
> with existing code which uses your library, and you don't have access to
> this existing code nor can change it), it can be a problem if the existing
> code can make assumptions about your library and does so.
Agreed. But I don't know of any language that doesn't let you get into that
situation. It's just a question of how easy or hard it is, and how obvious
it is that it's happening.
>>> I think that your problem is that you have some kind of holy war against
>>> C++, and every single discussion about programming is always somehow turned
>>> to bashing C++.
>
>> Nope. Someone brought up C++ by talking about the compiler enforcing
>> "private:". I was just pointing out that the compiler only enforces it in
>> some ways, and not in the ways that I thought was also important for modularity.
>
> You immediately assumed that it must be talking about C++, of course,
> and immediately jumped at the opportunity of bashing it.
Well, the first thing I objected to is the idea that a language is kludgey
if you can access private variables whose names only appear in the source
code of the class implementation.
My first mention of C++ (in the same paragraph where I meantioned another
half-dozen OO languages) was that it's trivial to bypass the modularity of
it, meaning that you can read and write private members of a class by using
well-defined if non-portable operations. I then asked you if you didn't
think that meant modularity was lacking in C++.
Actually, you mentioned "private:" first, and I admit I assumed you were
talking about C++, since the only other languages I know that use that
syntax are ones you'd already said are kludgey.
I think we're just off on the wrong foot here, perhaps. You said "data
hiding is an integral part of OO" and criticized CLOS for not having it. Yet
the only way to unhide the private data in CLOS is to read the source code
for the implementation of the class. Hence, it seems you were saying that
any mechanism that allows the access of private members, even with complete
access to the source, is a bad thing (assuming you think kludges are bad).
Yet I can get access to the private members of *every* language that has the
"private:" syntax. C++ is the only language I know that use that syntax that
doesn't have a standard way of accessing private variables. All C++ has is
non-portable (but standard) ways of accessing private variables. So I talked
about C++.
> In a discussion about the modular programming paradigm and data hiding you
> succeeded in creating an lengthy thread about how you can trash memory in C++.
> It's not exactly like you avoided the subject.
No, I didn't avoid it. There was an implication that C++ had better
modularity and data hiding than languages with reflection implemented
standardly. I'm pointing out that it doesn't. You can dump an instance into
an array of characters and rebuild whatever you need, if you accept you'll
have a non-portable knowledge of how the class is laid out.
>> OK. I'm just trying to communicate here. That's why I'm asking the question.
>> It seemed to me that you preferred a language with unsafe behavior and
>> compiler-enforced checks to one with safe behavior and no compiler-enforced
>> checks.
>
> That "you preferred a language with unsafe behavior" is 100% your own
> invention. I have nowhere said that.
Are you missing the "it seemed to me" bit there? Do you not understand what
that phrase means? It means "Hey, we seem to have a miscommunication going
on. This is what I received. Is it what you meant?" That doesn't mean I'm
"twisting" your words. It means I'm asking you to clarify.
> What I have said is that I prefer enforced modularity over non-enforced
> one (which IMO is not modularity at all). That "unsafe" bit is all your
> own twisting.
I prefer enforced modularity over non-enforced modularity myself. I know of
virtually no language that supports enforced modularity. They all have
specific trap doors just to get around the modularity restrictions. (Except
perhaps Ada and Eiffel, neither of which is a really a language I use enough
to be sure of.)
>> I've never heard you call C++ a kludge OO language. I assumed you were
>> excluding C++ from that criticism when you said a language that allows
>> access to private members is a kludge OO.
>
> At least you admit you are making assumptions.
Yeah. Sure. That's a basic part of communication. That's why my comments are
full of things like "it seems to me..." and "are you saying that..."
They're indicators that I'm making assumptions that need to be validated. It
doesn't mean I'm saying you said that. It means it sounds to me like you're
implying that, and I'm asking if I'm interpreting you correctly.
--
Darren New, San Diego CA, USA (PST)
My fortune cookie said, "You will soon be
unable to read this, even at arm's length."
Post a reply to this message
|
![](/i/fill.gif) |