![](/i/fill.gif) |
![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> wrote:
> You still get subclasses. And of course there's always the hack of declaring
> a subclass.
A subclass can't access the private members of the base class.
> Or just using compiler-specific hackage to access the variables.
That has been made rather difficult in practice. If you are *intentionally*
trying to break your program, then that's your choice, of course. However,
in normal usage it's useful if the compiler checks that you don't make
mistakes.
> or the infamous "#define private public".
Whether your program will link after that can depend on the compiler.
It's certainly not standard-conforming. And again, you are hacking on
purpose, trying to bypass the compiler checks, rather than using those
checks to catch your mistakes.
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
nemesis <nam### [at] gmail com> wrote:
> Warp escreveu:
> > nemesis <nam### [at] gmail com> wrote:
> >> I'm sorry, but that simply doesn't follow.
> >
> > 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.
> Now I (think I) understand the root of our disagreement. I'm thinking
> about functional programming here with only functions accessible per
> interface, you're thinking about what variable can be accessed and
> whatnot in a severely mutable setting. It all becomes really hard when
> you allow state to dominate. So hard that even very experienced
> programmers can face dificulty handling it all, thus having to invent
> all sorts of levels of accessibility rather than just rely on lexical scope.
Not all member functions have to be public either. It's extremely common
for a class to have private member functions which are part of its internal
implementation and not even intended to be part of the public interface.
I would say that being able to define private member functions is equally
important as being able to define private member variables.
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp escreveu:
> nemesis <nam### [at] gmail com> wrote:
>> It's not because it's accessible that it is going to be used.
>
> Yeah, sure. If you are the *only* person making the entire program, then
> perhaps that might be the case.
Like I said, if the dumbass wants to use things not in the interface,
it's his risk.
> So in your opinion the concept of "interface" is a verbal agreement about
> what should and shouldn't be used from a module? *That* is what sounds like
> bureaucracy to me.
Not bureaucracy at all. Just a list of names of functions a module
provides.
>> For people who know it better, the lack of such measure does not mean
>> irrestrict access to things, it simply means less stupid typing to make
>> the compiler happy. Modularity is conserved.
>
> In Utopia, maybe. In the read world, not so.
Indeed. In real enterprise world we got people who don't enjoy nor know
how to program, programming. Or, should I say?, fill up a few forms and
allow an IDE to generate the code. It will spill shit all over, true.
> And I don't consider having to write "private:" once to be significantly
> more typing.
Indeed, Delphi and C++ are yet more zippy at that, not so much for those
poor Java souls... you also forgot the data type declarations.
> If I had to document what you should and should not access
> in the module, *that* would be significantly more typing.
This coming from a guy whose favorite language needs for one to provide
the source and the header file.
> And the kind of
> text which most people will not read anyways.
It's usually the first thing one sees when opening a module. (export
foo bar boz frob etc)
> Also, if I make a module for others to use, how can I guarantee that
> I can change the implementation later without breaking code others have
> written?
Don't change the interface. Of course, if the implementation is changed
in such a buggy way as to totally alter the behaviour, same interface
doesn't mean jack.
>> It's all about scope. If it's public, it should be used. If it's not,
>> you shouldn't.
>
> And what's wrong with the compiler telling you if you try to use it
> regardless? I really can't understand that.
Nothing wrong except quite a few more tiresome and bureaucratic measures
before actually writing anything.
> The compiler is not limiting anything that you aren't *already* limiting
> by your verbal agreement. The only thing the compiler is doing is checking
> that the agreement is not broken. Why that is a bad thing is beyond my
> comprehension.
I was not saying that is bad. I was just reacting to this: "Your
definition of object-oriented programming may vary, but in my view
data hiding, ie. modularity, is an integral part of OO programming."
Modularity is still there regardless of dumb programmers ripping their
contracts and no middleman to prevent them doing so. But I'm thinking
here on a typical Scheme module of old, before true modules, and where
all you had was a list of functions and lexical scoping, not a C plain
text file with lots of variables and variable-dependent functions lying
all around.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
>> Like, in unsafe languages, where a stray pointer can change private
>> variables without going thru the class methods? :-)
>
> No. The reasoning behind data hiding in modular thinking is completely
> independent of the language used. It has to do with program design.
OK. I guess you look it as "if you bypass the documentation and access
members not documented, I have to support your brokenness forever." I look
at it as "if you're coding from the implementation instead of the
documentation, you get what you deserve" combined with "don't make me debug
my code when the bug is in your code."
> If you expose the internal structure of a module to the outside, then
> there's a big chance that outside will start making *assumptions* about
> this internal structure.
Sure. Most of these languages (a) document what's public and what isn't, and
(b) have a language-wide naming convention for it. That is, after all, what
C++'s 'private' tag is - a naming convention.
> If this happens, then you can't change the internal implementation of
> this module without breaking existing code. For example, if you wanted
> to change the color components to floats, or you would want to pack the
> color components into one single integral value, you will most probably
> break existing code (especially probable in the latter case, as the
> amount and names of the member variables will change drastically).
>
> If you can design the absolutely perfect module which will never change
> its contents and will suffice for years to come, then by all means make
> all members public. Us mortals will try smarter techniques.
>
>> C# and Java both have reflection that let you get to private members from
>> outside.
>
> Thus it's one reason why the design of these languages is badly broken.
I think it's more a trade-off than you make it out to be.
>> C++ not only lets you return pointers to private members
>
> Only if the class itself explicitly does so. You can't get to the private
> members *from the outside*.
That's why I said it wasn't much of a breakage in my view.
> (Well, at least not without some serious hacking.)
Running off the end of an array is "serious hacking"? I wouldn't think so.
> I don't understand what you are saying. If a class in C++ does not expose
> a member array, then you can't get to that member array from the outside,
int * p = (int *) 0x123456;
*p = 27;
Find the bug in your code that's setting that member variable to 27.
How about
// Your code...
class xyz {
public: int[10] x;
private int y = 0;
}
// My code
xyz pdq;
pdq.x[10] = 27;
> You might be able to control your *own* code from not misusing public
> variables (and you might never make mistakes), but it's more difficult to
> control someone else.
Sure. See above examples.
> If you need to tell someone else "don't access member variables whose
> name start with an underscore", that's just plain stupid. You should be
> able to tell that by making the *compiler* enforce it.
I agree, except for the fact that you're using C++ as an example. :) C++ has
it's own different lack-of-modularity problems. If the compiler actually
*enforces* that the member variables you declare private can only be changed
by your own methods, that's great.
"don't access member variables whose name starts with an underscore" is the
kind of rule that's enforced all through a codebase or a programming
language. The little extra warning the compiler is going to give you is
generally not of much benefit if someone's going to violate that rule
anyway, IME. In other words, if they really need to violate the privacy of
your class, they're going to do it in C++ almost as easily as they do it in
something like Python or LISP. The compiler doesn't enforce the
encapsulation in C++ - it just gives warnings when you use a variable name
that's private. There's no enforcement at runtime, and plenty of back doors
at compile time. Contrast with, say, C#, where you don't even know what the
private variables are named, and you couldn't access them if you did,
because the runtime enforces that - there, the only backdoor is the
reflection libraries that specifically are bypassing the privacy checking
system. Using reflection (or explicitly assigning to _private members) isn't
any more common or more prone to abuse than ((int*)0x12345)=27; is,
particularly because the user has to explicitly know they're violating
encapsulation when they write the code.
Granted, if you don't *document* in a universal kind of way what's public
and what isn't, you're leaving yourself open to abuse.
But there are a lot of people who don't want to write a ton of boilerplate
code for a function that could be automated, so they're willing to say "if
you use introspection to read and write my structure over the wire, be
aware it may change in other versions." It's better to say "this will break
with future versions" than to say "I'm going to write 5000 lines of
boilerplate code to allow clients to send my values over the internet or
into databases."
There are also a whole bunch of assumptions in your classes that someone is
going to rely on that you're not going to be able to prevent. SimCity
assumed memory you called free() on would still be valid until the next
malloc(), which is obviously a bad assumption yet still has to be supported
by the infrastructure if you expect to run simcity on later versions of the
OS. If you store your object outside of memory or interact with any other
objects, you're also going to have random dependencies created - someone is
going to have to change database schemas to store your objects in a
database, or change buffer sizes if you switch from JSON serializiation to
XML serialization without otherwise changing your interface. There will be
people who assume your class only invokes their getter method once, if
that's how you first code it, and if you change to invoking it twice, they
may very well fail out (because they're pulling the next row from a database
for each invocation, say). Or, in short, you can't protect against bad
programmers, and anyone half-decent isn't going to be frobbing private
variables to start with, IME.
--
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) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Rule #5: Best documentation is the code. ;)
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp escreveu:
> Not all member functions have to be public either. It's extremely common
> for a class to have private member functions which are part of its internal
> implementation and not even intended to be part of the public interface.
Exactly. Lexical scoping takes care of that. For languages which allow
conveniently-definable lambdas, that is.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp escreveu:
> And again, you are hacking on
> purpose, trying to bypass the compiler checks, rather than using those
> checks to catch your mistakes.
How this is any different from someone breaking a contract on purpose is
beyond me.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
> 1) I write "private:" once in my class definition.
>
> 2) I write extensive documentation about the subject and hope people will
> read it and obey it. Many people won't.
You missed this one:
3) You name your private variables with the naming convention used by
every other package ever implemented in that language, including
the ones that define the runtime, and which every programmer knows
bypassing means future incompatibility.
> And what's wrong with the compiler telling you if you try to use it
> regardless? I really can't understand that.
You already know you're using a private variable, if you're bypassing either
global naming conventions or using reflection or something.
If the compiler actually *prevents* it, then you're locking yourself out of
a whole bunch of metaprogramming techniques that templates aren't adequate
to handle.
--
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) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
> Darren New <dne### [at] san rr com> wrote:
>> Certainly if should-be-private members are exposed as public but don't
>> document to the user which are private, that's a problem.
>
> I thought you were old enough to know some basic facts of life:
>
> Rule #1: People *don't* read documentation.
> Rule #2: Read rule #1.
> Rule #3: Even if people read documentation, they do not have photographic
> memory and they forget.
> Rule #4: Humans are imperfect and make mistakes.
Sure. "Don't read documentation" or "forget documentation" is as bad as
"don't document it". But if it's a naming convention used throughout the
language, people don't do it.
How many people name their own function to add a list of numbers as
__builtin_addlist()
in C or C++? Why not? Because everyone who is even a little knowlegable
knows that two underscore names are reserved for the compiler.
> Why is it a bad thing to make the compiler check interface breaches is
> beyond my comprehension.
First, the whole "dynamic languages" bit at the start should indicate not
everyone has a compiler for these languages. Secondly, it eliminates a whole
raft of useful mechanisms. Where's the C++ library to which I pass a class
and it generates a SOAP interface parser for that class?
--
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) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
> Darren New <dne### [at] san rr com> wrote:
>> You still get subclasses. And of course there's always the hack of declaring
>> a subclass.
>
> A subclass can't access the private members of the base class.
Yeah, "protected" slipped my mind. It's still not hard to do if you're trying.
>> Or just using compiler-specific hackage to access the variables.
>
> That has been made rather difficult in practice.
Err, has it? I can't say something like
int * p = (int*) ((void*)(&yourInstance) + 32);
if I want access to whatever integer is 32 past the start of your class?
> If you are *intentionally*
> trying to break your program, then that's your choice, of course. However,
> in normal usage it's useful if the compiler checks that you don't make
> mistakes.
While I agree, I fail to see why using reflection as intended isn't "normal
usage" and not "a mistake". It's not something you accidentally do. You know
very well you're bypassing encapsulation. Not the least of which is that you
need to give the name of the variable you want to access as a string.
> Whether your program will link after that can depend on the compiler.
> It's certainly not standard-conforming. And again, you are hacking on
> purpose, trying to bypass the compiler checks, rather than using those
> checks to catch your mistakes.
Right. Since you said reflection violates encapsulation hard enough to make
a program not "OO", I'm trying to figure out allowing type casts and
assignment of arbitrary memory addresses to pointers doesn't.
Now, if the statement is "the compiler should be able to warn of external
access to private variables, with the ability of the caller to easily
indicate they know what they're doing," I'm 100% with you.
If the statement is "the compiler should error on external access to private
variables, with no way to get around it," I'm 95% with you, with the caveat
that "that's a pain in the ass way to write generic code that isn't type
specific, because you have to write code generators instead of using the
compiler you already have."
If the statement is "the compiler should error out on external access to
private variables, but there should be a non-portable hacky and error-prone
way to bypass it anyway, so you can't rely in your debugging efforts on what
your code actually says," I'll just have to disagree with you there. :-)
--
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) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |