![](/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) |
Warp wrote:
> But an outside code could do something along the lines of:
>
> OuterClass::_InnerClass obj; // Assuming the compiler doesn't restrict this
>
> obj.someFunction();
That's correct. And no, the compiler doesn't restrict it. I don't know I've
even heard of a source code tool that warns you about it, altho that would
seem fairly easy to write, methinks.
Just FYI, the syntax for that would be
obj = OuterClass._InnerClass()
obj.someFunction()
OuterClass._InnerClass returns the class itself, since the class is just
assigned as the value of the variable. Invoking that value with () does the
equivalent of C++'s "new". Then you assign whatever the constructor returned
to obj. Depending on the existence of different functions inside the
_InnerClass class, you get things like overridden "new" or overridden
constructors.
And, technically, a constructor doesn't *have* to return an instance of the
class you invoked, if you override "new" in the class and have it return
something of a different class. So it's even uglier. :-) Just calling
obj = OuterClass()
could actually wind up assigning an OuterClass._InnerClass instance to obj.
Handy for factory functions, tho.
> The first line clearly breaks the privacy contract, but with the second
> line it's not so obvious anymore.
Correct.
On the other hand, it's the same result as if you did something like
obj = OuterClass::factory_method(...)
and factory_method returns an instance of _InnerClass. So it's not really
something you could enforce there at the compiler level. (As in, it would
be hard to enforce at the obj.someFunction() call, but easier at the
OuterClass._InnerClass access.)
I.e., I'm not sure I'd describe the second line as breaking the privacy
contract. It's just using a value obtained by breaking the privacy contract.
But that's just a matter of wording, really.
> It's calling a public member of _InnerClass,
> but it's intended to be "public" only for OuterClass
Not necessarily. If OuterClass returns an instance of _InnerClass (like, if
OuterClass is a collection and _InnerClass is an iterator over the
collection) it might make sense.
> (because _InnerClass is
> part of the private implementation of OuterClass), not for anything else.
If OuterClass never returns instances of _InnerClass, yes, that would be a
difficult violation of modularity to track down. It's certainly not the best
way of doing things if you're worried about that sort of thing.
--
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) |
Darren New wrote:
> It's certainly not
> the best way of doing things if you're worried about that sort of thing.
Um, "it" there means "Python's way of handling private variables", not
"inner classes". As in, naming conventions aren't the best way of handling
private members if you're worried about someone violating the privacy.
--
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:
> And it's getting really tiresome and old that you act all innocent after
> a tirade of C++ bashing,
Can you do me a favor, for the sake of future conversations?
Can you tell me what I said that you took to be "a tirade of C++ bashing"?
As far as I can see, I've been trying to be factual and honest. You started
out using derogatory terms like "it's a kludge", and "that's BS", and
referring to people as "self-taught hackers" and "use a fancy term instead
of admitting their mistake" and "In Utopia, maybe" and the usual insulting
hyperbole.
Where did I say anything derogatory about C++? I would like to know what I
said about C++ that you took to be saying C++ is *bad*. Can you actually
quote what I wrote that you took to be "C++ bashing", let alone a "tirade"?
As far as I can see, the conversation (once it got to be about modularity
instead of minimalism) went something like
You: "Modularity is good. Breaking modularity is bad."
Me: "Yes. But everyone breaks modularity in different ways.
CLOS breaks it by doing A
C# and Java breaks it by doing B
Python breaks it by doing C
C++ breaks it by doing D
I prefer B over D."
You: "D doesn't count. C++ doesn't break modularity."
Me: "Wild pointers."
You: "Doesn't count - not standard."
Me: "Memset"
You: "Doesn't count - non portable."
Me: "But it still happens."
You: "You're so mean, always bashing C++."
So, in all honestly, I'd really like to know where in the process I said
something that "bashed" C++, rather than simply comparing its behavior with
other languages and explaining (in detail) why I preferred the other mechanisms.
--
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:
> You can't access the private variable by address. Not according to the
> standard.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf
Section 3.9 paragraph 2, page 60 sheet 74.
#define N sizeof(T)
char buf[N];
T obj ; // obj initialized to its original value
std::memcpy(buf, &obj, N); // between these two calls to std::memcpy,
// obj might be modified
std::memcpy(&obj, buf, N); // at this point, each subobject of obj of scalar
type
// holds its original value
Yet I'm sure at this point that there will be some reason this doesn't count
as violating modularity. Will it be that it's only a draft of the standard?
Will it be that it's only true of POD types? Will it be because it only says
it works for reading and writing all the private variables at once?
--
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) |
Darren New <dne### [at] san rr com> wrote:
> Warp wrote:
> > You can't access the private variable by address. Not according to the
> > standard.
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf
> Section 3.9 paragraph 2, page 60 sheet 74.
> #define N sizeof(T)
> char buf[N];
> T obj ; // obj initialized to its original value
> std::memcpy(buf, &obj, N); // between these two calls to std::memcpy,
> // obj might be modified
> std::memcpy(&obj, buf, N); // at this point, each subobject of obj of scalar
> type
> // holds its original value
> Yet I'm sure at this point that there will be some reason this doesn't count
> as violating modularity. Will it be that it's only a draft of the standard?
> Will it be that it's only true of POD types? Will it be because it only says
> it works for reading and writing all the private variables at once?
By the same logic this would also "break modularity":
T obj;
T obj2 = obj;
All the data in obj is copied to obj2. This includes all the private data.
However, the memcpy() version *is* breaking modularity because, as the
text says, it's guaranteed to work only if the object contains scalar
types. If you assume it does, you are breaking modularity.
--
- 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) |
Darren New <dne### [at] san rr com> wrote:
> Can you tell me what I said that you took to be "a tirade of C++ bashing"?
A combination of concepts gave me the impression that you were
denigrating the way C++ does thing, while praising how other languages
do it better.
Maybe you didn't use the word "unsafe" in a derogatory manner, but it
was easy to get the impression. When you said basically that it's not true
that C++ enforces modularity, and proceeded to "demonstrate" that by
trying to give examples of how you can circumvent C++'s semantics by
using low-level pointer casting and arithmetic, it gave the impression
that you were denigrating C++ for trying to do something and failing
miserably. This impression was emphasized by you at the same time telling
how you prefer how other languages do it "right" by having explicit support
for breaking the module interface boundaries, while in C++ you have to
resort to non-standard hacks to do the same. Also your arguments why
someone would even want to break the interface boundaries was not completely
convincing to me. (Your only argument seemed to be "reflection", and my
only experience on it is with Objective-C, where it's done without really
accessing private members from the outside, at least as far as I have had
to deal with it.) When you wrote that C++ is the only unsafe OO language
you know of, it sounded like you were bragging how *all* other OO languages
are better than C++, which gives the impression that you are telling that
C++ is the worst possible OO language in existence.
I apologize if I overreacted.
--
- 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 wrote:
> By the same logic this would also "break modularity":
>
> T obj;
> T obj2 = obj;
Not really. operator= is declared in T.
> All the data in obj is copied to obj2. This includes all the private data.
Only if you say that's how you want it to work.
> However, the memcpy() version *is* breaking modularity because, as the
> text says, it's guaranteed to work only if the object contains scalar
> types. If you assume it does, you are breaking modularity.
You don't have to assume it does. You can read the header file and see it
does. :-)
In any case, yes, you're breaking modularity. That's what we're saying, yes?
Accessing private variables without the permission of the class breaks
modularity? Accessing private variables by address in a
standards-conforming way breaks modularity. Given that you're agreeing with
me, I'm not sure what the "however" in your sentence is supposed to imply.
--
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:
>> Can you tell me what I said that you took to be "a tirade of C++ bashing"?
>
> A combination of concepts gave me the impression that you were
> denigrating the way C++ does thing, while praising how other languages
> do it better.
OK. As I said, I simply said I prefer how the other languages break
modularity instead, and then I listed the reasons. "Bashing" to me implies
denegrating it either by lying about its capabilities or saying it's bad for
no reason or using abusive language or something like that, yes?
And yes, I was saying I prefer how other languages do it to how C++ does it,
and I listed the reasons why. We all know why C++ does things the way it
does, and the benefits that provides to the programmer. That doesn't make it
"C++ bashing." If anything, the bashing was of Java in the original post.
> Maybe you didn't use the word "unsafe" in a derogatory manner, but it
> was easy to get the impression.
I think you're oversensitive about that. I don't like unsafe languages for
the reasons I've stated, but I don't know how saying that is "derogatory". I
said "C is unsafe", I didn't say "C is a fucked up steaming hack pile of
garbage whose inventors should be shot for being so stupid." *That* is
derogatory.
> When you said basically that it's not true
> that C++ enforces modularity, and proceeded to "demonstrate" that by
> trying to give examples of how you can circumvent C++'s semantics by
> using low-level pointer casting and arithmetic, it gave the impression
> that you were denigrating C++ for trying to do something and failing
> miserably.
OK. That wasn't the impression I was trying to convey. I was simply trying
to point out that no unsafe language is truly modular, and the easier it is
to find the unsafe operations, the easier it is to debug accidental breakage
of modularity.
> This impression was emphasized by you at the same time telling
> how you prefer how other languages do it "right" by having explicit support
> for breaking the module interface boundaries, while in C++ you have to
> resort to non-standard hacks to do the same.
You have to resort to non-standard hacks to *intentionally* break
modularity, is what I said. And that there's two types of modularity involved.
> Also your arguments why
> someone would even want to break the interface boundaries was not completely
> convincing to me. (Your only argument seemed to be "reflection", and my
> only experience on it is with Objective-C, where it's done without really
> accessing private members from the outside, at least as far as I have had
> to deal with it.)
It doesn't happen really often, which is why I thought *you* were
overreacting by calling CLOS a kludge OO system simply because you can break
modularity by reading the source of the module. :-)
> When you wrote that C++ is the only unsafe OO language
> you know of, it sounded like you were bragging how *all* other OO languages
> are better than C++, which gives the impression that you are telling that
> C++ is the worst possible OO language in existence.
I said that because you challenged me to say which I'm talking about. By
then, you were already convinced I had to be bashing C++ and I was trying to
hide it after the fact. :-)
> I apologize if I overreacted.
Apology accepted. I believe you did. I admit I've bashed C++ in the past in
some ways, so it's not unreasonable, but I've been trying not to do that for
quite some time now. It's primarily you teaching me about the power of it in
conversations like this that has made me appreciate for what it is.
It's actually not that bad a language if it's the sort of language you need.
I disagree with the design principles, and sometimes I explain why I
disagree with them, but that's an opinion that everyone can feel free to
decide for themselves. It's kind of funky how much power it can manage to
build onto itself using what it comes with.
I'll try to be even *more* careful how I talk about things if you'll do me
the favor that, when you get annoyed, you re-read without assuming I'm
bashing and see if it still sounds like I'm "bashing."
--
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) |
Darren New <dne### [at] san rr com> wrote:
> In any case, yes, you're breaking modularity. That's what we're saying, yes?
> Accessing private variables without the permission of the class breaks
> modularity? Accessing private variables by address in a
> standards-conforming way breaks modularity. Given that you're agreeing with
> me, I'm not sure what the "however" in your sentence is supposed to imply.
The breaking of modularity in this case has little to do with accessing
private members, and more to do with bypassing the normal copy constructor
or assignment operator semantics through reinterpret-casting pointers.
"a = b;" and "memcpy(&a, &b, sizeof(a));" might in fact produce almost,
if not exactly identical machine code by the compiler, if the class in
question only has scalar types as members (and doesn't define an assignment
operator the compiler cannot see at this point). Thus at machine code
level the two expressions might in fact be completely identical.
With this I mean that with the memcpy() you are not accessing the private
members any more than you are with "a = b;". They are both copying the
state of the entire object to another instance. You could say that with
memcpy() you still don't know *what* you are copying (what type of members,
how they are padded inside the class, etc), only that you are copying
everything verbatim.
The difference, and what makes the memcpy() version non-modular, is that
the memcpy() version bypasses the normal class assignment semantics and
instead goes to the "raw hardware level". If the class would need a more
complex copying semantics than a bit-by-bit copy, then the copy is broken.
I understand your argument to be that memcpy() could be used in this
way to *access* the private members of the object. However, it can't,
not in a portable way anyways, because you still can't know the internal
structure the compiler has generated for the class, and you can't point
to individual private elements.
Perhaps this could be compared to calling the CopyFile() function of
the Windows API: Even though it copies the entire contents of a file to
another file, I'm still not *accessing* the contents of the file with
that function in my program. I'm just telling the system to copy it.
--
- 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) |
Darren New <dne### [at] san rr com> wrote:
> OK. As I said, I simply said I prefer how the other languages break
> modularity instead, and then I listed the reasons. "Bashing" to me implies
> denegrating it either by lying about its capabilities or saying it's bad for
> no reason or using abusive language or something like that, yes?
I understand that "bashing" can also be used to describe overly negative
critique of something in a way that, while not telling any lies per se,
makes it sound a lot worse than it really is. Especially if the impact of
many of these negative things is exaggerated, and especifally if all this
is done on purpose.
For example, in my "I hate Java" page I'm outright bashing Java because
I'm pointing everything that I consider negative about it, without pointing
out anything positive to compensate (although Java does have its positive
things as well). Someone who didn't know anything about Java could get a
rather biased impression of the language by reading that page alone. (Guess
twice if I care. ;) )
--
- 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) |