|
|
|
|
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp wrote:
> I started by defending data hiding principle in the object-oriented/modular
> programming paradigm, and stressed that this principle is completely
> independent of the language used.
We did kind of get into a bit of a flurry of messages there, didn't we?
Let's see. I think we started out with a comment that minimalist languages
with powerful syntax (e.g., LISP) can implement things like OO without
having it built in, by using closures for example. Then the subject of CLOS
came up (which AFAIK doesn't use closures), with an indication that it's
possible to access the private members with sufficient work.
You said
"""
I think that the typical impossibility or difficulty in data hiding in
languages which do not have specific support for modularity is a sign that
the "OOP" is, after all, just a kludge.
"""
and later talked about how reflection makes it impossible to hide private
variables and implying that clear and unambiguous naming conventions that
everyone who codes in the language understands aren't sufficient.
I have agreed with that. I think what we're disagreeing with is the degree
to which the language implementation needs to enforce that modularity
strictly, but if it does, that's better than a language that disallows it
without enforcing it, because you can look at your code and see what it's doing.
I prefer being able to break the modularity with reflection, because it
gives you lots of power you otherwise need to write a bunch of boilerplate
to handle.
Lacking that, I prefer to have the modularity enforced, so I can reason
logically about a piece of code and determine that it will work correctly
even if there are bugs in other parts of code. I've had too many occasions
where I spend days looking for bugs in my code only to find that someone
else had scribbled over memory. Or even, in one case, had printed up "now
invoking Darren's code"[1] and then crashing out while prepping the
arguments to my module.
Lacking that, you have glorified assembly language. :-) The machine
represented to your code matches the machine it's running on. There are
times when that's good, but my work lately has not been one of those times.
> Your argument against this technique seems to be "since you can't completely
> guard against it in C++, it's as good as not having data hiding at all". As
> if C++ had anything to do with this issue.
There were examples given as "private". I don't know who started it, maybe
not you. I was simply pointing out that it's as easy for someone to violate
your encapsulation in C++ as in LISP because the compiler doesn't enforce
encapsulation. You can't completely guard against it in C++, and you can't
completely guard against it in CLOS (the LISP OO system under consideration)
or Python. I don't see that big a difference, really.
>> Um, no, really, you can't. How do you prevent me from corrupting your
>> private variables with a wild pointer?
>
> If you write standard-conforming C++, you won't have a wild pointer
> (unless you have a bug, of course).
No. If *everyone* writes standard-conforming C++, you won't have a wild
pointer. In safe languages, it doesn't matter what you write, *I* can count
on my library behaving as I wrote it. And, unfortunately, the C++ compiler
may try to enforce "private", but it doesn't try to enforce
standard-conforming C++.
If you call "accessing someone else's private variables on purpose" a bug,
then you can't have standard-conforming Python that violates encapsulation
without a bug, either.
--
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
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp wrote:
> Nicolas Alvarez <nic### [at] gmailcom> wrote:
>> Instead of using private:, you could just add an underscore to internal
>> variables.
>
> But why would I want to do that? There's no benefit. There are only
> potential disadvantages.
He's saying that putting "private:" before the variables in a class
declaration is equivalent to naming private variables with an underscore. In
the first case, the compiler warns you if you use a private variable by
mistake. In the second case, it's obvious from inspection. If you have
x._y
in your code, you're doing something wrong. :-)
--
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
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp escreveu:
> Nicolas Alvarez <nic### [at] gmailcom> wrote:
>> Warp wrote:
>>> Why not? Having the compiler check for breaking of agreements (eg.
>>> "don't
>>> access these variables") is much better than oral agreements. The compiler
>>> is much better at catching mistakes than you are.
>
>> It's an underscore or something else clearly visible in the offending
>> (= private-data-using-) code, not an oral agreement.
>
> Ok, "written agreement" then, if you want to nitpick. Not much difference.
> Still not enforced nor sanity-checked by anyone or anything.
Here is where Larry Wall's quote really applies. ;)
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp wrote:
> Darren New <dne### [at] sanrrcom> wrote:
>> I disagree. Now you've got a naming convention that isn't enforced that
>> would mean something to people trying to read your code.
>
> You mean the naming convention *is* enforced by languages which do not
> explicitly support private data?
Not exactly.
In Python (and, AFAIK, LISP), getting to private functions, for example,
requires you to explicitly name the module and private function, and say
"pull them into my space."
However, you can get to private members without doing that.
Therefore, the convention is that private members are given names that
indicate they're intended to be private. Private functions don't need that
naming convention, because there's a list out there in the source code that
distinguishes private from public. That list is only enforced by default,
but you can work around it if you care to read the code and see what isn't
exported, or if you grope into the generated code and look what's there.
Even if it were enforced in Python, the metadata is there to be used and
abused. You can go into the data structures that make up the class or the
instance and modify them, because that's exactly how the system works
normally. The compiler works by building those data structures at runtime,
so if the compiler can do it, so can you. That's why the original article
talked about dynamic systems, i.e., systems that you can change at runtime.
For example (and very simplified), in Python, each object has a hashtable
mapping the names of fields to their values. Each member object of each
class and instance is in a hashtable. The hashtable is called "__dict__", so
xyz.__dict__["hello"] is the same as xyz.hello. If you marked "hello" as
private (even if you could), code could still get to it via __dict__. If you
marked __dict__ as private, all kinds of meta stuff would break.
--
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
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Darren New <dne### [at] sanrrcom> wrote:
> He's saying that putting "private:" before the variables in a class
> declaration is equivalent to naming private variables with an underscore. In
> the first case, the compiler warns you if you use a private variable by
> mistake.
Could you give a concrete example of a compiler, of any OO language,
which will only *warn* (rather than give an error message) if you try to
access a member variable specifically marked as private from the outside?
--
- Warp
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
nemesis <nam### [at] gmailcom> wrote:
> > Ok, "written agreement" then, if you want to nitpick. Not much difference.
> > Still not enforced nor sanity-checked by anyone or anything.
> Here is where Larry Wall's quote really applies. ;)
Since when have code sanity checks become a bad thing?
--
- Warp
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp wrote:
> The question here is: Are compiler-enforced private member variables a
> good thing in programming or not?
My argument, again, very specifically, is that there's a bunch of
possibilities, not two:
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).
The benefit is you can debug modules in isolation.
2) They're enforced 100%, but people outside the class can read but not
write them. This is a little more fragile to change, but still capable of
being debugged in isolation, because other parts of the code can't break
your invariants. Eiffel does this, but it's the same syntax (x.y) to
reference the y member of x as it is to invoke the nullary member function y
on x, so you don't need to do more than recompile the client code. (I think
you can also say a variable is completely private, IIRC.)
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.
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.
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.
6) There's no convention, and all you have is documentation saying which
bits are supposed to be private and which aren't. Worst of all possible
worlds. Not very modular at all.
> 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.
I.e., there's two good reasons for modularity: future-proofing your code,
and bug-proofing your code. You only talked about the former.
> I defended data hiding in general, as a programming paradigm (and I made
> that pretty clear). Your very first reply to me was a reference to (and
> attack against) C++.
Err, no it wasn't. I simply said "LISP can use macros to simulate OO just
like C++ uses constructors and destructors to do resource management."
> You certainly didn't wait.
Sure I did. Go back and look what I said about C++ again. Really.
> access rights in C++ and why everything is better in all other languages.
I haven't said better. I said different. I'm talking about the things above,
which have little to do with C++ except it's the only unsafe OO language I
know of.
> I'm honestly getting tired of your C++ tirades. Every single subject
> related to programming must somehow include C++ bashing, regardless of
> the subject. That's getting tiresome.
I'm really not trying to bash C++ here. If pointing out that C++ allows you
to corrupt member variables with a bug is "bashing", then I guess I'm bashing.
>> So you're saying having non-portable ways of bypassing the typing is better
>> than having portable ways of bypassing the typing?
>
> How do you even manage to twist my words to almost the exact opposite of
> what I'm saying?
>
> Where exactly do you see the word "better", or any kind of synonym or
> reference to it? That's completely your twisted invention.
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. I was asking whether that was the case. The right answer would be
"No, that's worse" or "No, that's different but just as bad because..." or
something like that.
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.
AFAIK, using lambdas to implement OO (which you can do in Python or LISP) is
the only mechanism I've seen that doesn't expose private instance variables
outside the class. Everything else provides either reflection or undefined
(or even well-defined) behavior to so do.
--
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
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp wrote:
> I still can't comprehend what's so bad in the compiler doing the check
> that you don't access the private members.
If it's actually enforced (as in an error rather than a warning), it makes
lots of things harder than they need to be, because the running code winds
up with less information than the compiler had. You're throwing away half
the work the compiler did once you generate the code, so you wind up with
lots of boilerplate to enter into code things the compiler already knows.
If it's not enforced (i.e., it's a warning), then I don't see it as an
improvement over a naming convention. People don't accidentally use x._y in
their python code any more than they accidentally name something
__builtin_printf in their C code. In CLOS, you actually have to go read the
source code of the implementation of the class to see what member variables
you can access, so it's not like you don't know you're violating encapsulation.
If it's *really* enforced (as in you actually can't get to private
variables), it lets you do things like prove your program is correct and
lets you do things like know you've got a bug in your module when an
instance variable winds up with the wrong value.
If it's half-enforced, as in the compiler complains and won't compile the
code, but there's ways to get around it anyway (on purpose or by mistake),
then it's IMO the worst of all possible worlds. You'll spend hours or days
trying to debug code that's already right because the client is convinced
the other code they've written is bugfree and it's easier to blame you than
to find the wild pointer in their own code. The whole idea of class
invariants goes out the window.
Incidentally, I see little wrong with breaking encapsulation if you maintain
the invariants. It makes it harder to upgrade in the future without changing
the client, but that's the price you pay for it. If you can automate the
access to where it doesn't hurt to change the client, it seems like a
win-win to me.
--
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
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp wrote:
> You could, of course, take that pointer and start trashing the memory
> it's pointing to, but that would be rather pointless. Certainly not useful.
Sure. And that's how C does its OO design pattern. :-)
--
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
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp wrote:
> Darren New <dne### [at] sanrrcom> wrote:
>> He's saying that putting "private:" before the variables in a class
>> declaration is equivalent to naming private variables with an underscore. In
>> the first case, the compiler warns you if you use a private variable by
>> mistake.
>
> Could you give a concrete example of a compiler, of any OO language,
> which will only *warn* (rather than give an error message) if you try to
> access a member variable specifically marked as private from the outside?
Sure. C# or Java. You get this warning that says "this won't compile." So
you use the reflection libraries instead, and it compiles. The compiler
hasn't stopped you from accessing the private variable. It just stopped you
from trivially accidentally accessing the private variable. (Python doesn't
even prevent you from trivially accessing the private variable, but in
practice it isn't a problem.)
I know what you're asking. I'm asking you to look at it from a slightly
different point of view. Take a more general approach to what it means to
get "a warning" than the usual "the compiler issues warnings and errors, and
nothing else is meaningful."
Another example is, as I've been saying, C++. The compiler warns (and won't
compile) if you access the private variable by name, but not if you
intentionally or accidentally access the private variable by address. Again,
I understand what you're saying, and I'm asking you to also try to
understand what I'm saying, instead of thinking I'm only saying it to annoy
you. This is really how I think about programming - what do I know, and what
might be broken. That's why I dislike unsafe languages with undefined behavior.
--
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
|
|
| |
| |
|
|
|
|
| |
|
|