![](/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:
> 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) |
|
![](/i/fill.gif) |
Warp wrote:
> 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.
Fair enough. I thought we'd already talked to death the advantages of unsafe
languages (primarily performance and control).
> Especially if the impact of
> many of these negative things is exaggerated,
I think you underestimate how much of a problem some problems are for
average programmers because you've become expert. I still occasionally get
questions from people who have been programming for decades who ask
"How do I debug something when it stops crashing after I add a printf()?"
You yourself have posted C++ code with a quiz-like "what's wrong with this
class". Clearly it takes a fair amount of expertise to write correct C++
code, doesn't it?
I can write C code that doesn't have bugs due to the unsafeness, but it
takes me much longer because I have to think a lot harder about the
boundaries. It's also something that took years of experience to learn.
I also figured it wouldn't be taken to be "bashing C++" if I pointed out the
equivalent flaws in the whole list of other languages we were talking about,
which is what led me to believe you might be a bit oversensitive or
oversensitized.
> 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. ;) )
There's nothing wrong IMO with a good bash so labeled. I don't think
anyone's going to read a page labeled "I hate Java" and expect a balanced
presentation, any more than they're going to go to apple.com to see the pros
vs cons of apples vs windows, say. I even think something like the C++ FQA
is a valuable service, bashing as it is. I wish there were pages like that
for every language and tool.
I don't think it's a bash of any one language to say "no language strictly
enforces modularity, they're all broken in various ways, and here they are:
...." I'm hoping it's not considered bashing Y to say "I like X better than
Y because ..." It's not like I started talking about the flaws I think are
in the design of C++ that haven't anything to do with violating modularity,
or that I argued you can't violate modularity in the other languages.
--
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:
> With this I mean that with the memcpy() you are not accessing the private
> members any more than you are with "a = b;".
I would disagree for the following reason:
Altho {a = b;} *might* do the same thing as memcpy(), the author of the
class has the ability to make it do something different, or to declare
operator= to be private, preventing it altogether.
memcpy() can not be "defended against" in that sense.
"Can I change the values of private variables without invoking a class
method or friend function?" "Yes." I'd say that's breaking modularity.
I think at this point we each understand what the other is saying, and now
we're just having an argument about whether to call it "really" unmodular or
only "kinda" unmodular. :-)
> 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.
Note, too, that even in this case, if you change your pixel example to be
HSV instead of RGB, the memcpy() approach still works for moving pixels
around. :-)
> 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.
Sure. I'm just arguing that the ability to use memcpy() *is* non-modular.
The fact that it breaks or is non-portable in some cases would not seem to
counter that fact. It would just seem to say "it's a bad way of doing
things." :-) Which we both agree with.
> 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.
Agreed. Not that it's difficult to figure out. I can think of at least 3
easy ways to figure out where individual variables are: 1) use a debugger,
2) look at the generated asm code, 3) stick a friend function into the
header that returns the offset of the private instance. None of those are
particularly portable, except the last, assuming that adding a friend
function declaration doesn't rearrange the actual structure members.
I agree it's a concern in CLOS that someone will read your source code and
access the internals of your class by learning the names of private
variables and then you'll have to support it. I also contend it's about the
same level of concern that someone will look at your header file, see it's
POD, and write code that uses memcpy() to move POD-structs around (perhaps
to different address spaces or into files or something), and you'll wind up
having to support that. Neither is really common enough to worry about, and
both are trivial to avoid if you can change the module you're talking about
or avoid the need to do that altogether in the caller.
> 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.
Sure. And my comparison would be that "Anything you can call CopyFile() on,
you can open and read and write, possibly messing up the program that uses
the file, or possibly for the purpose of bypassing DRM."
--
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:
> I understand that "bashing" can also be used to describe overly negative
> critique of something
Or, to just phrase it a different way, I've been actively and consciously
attempting not to say bad things about C++ and to ensure whenever I point
out a limitation I also point out the equivalent limitation in other
languages. Yet you continue to fall back on "you're bashing C++ to annoy
me", which is kind of discouraging.
--
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:
> I agree it's a concern in CLOS that someone will read your source code
Or, to phrase it a bit differently, I'll agree that using memset() or
memcpy() to get to the entire instance opaquely *feels* qualitatively
different than the sorts of access CLOS or Python allows.
On the other hand, it seems kind of similar to the sorts of things
reflection allows.
Even in Python, I think there's two kinds of accesses:
x = myinstance._myprivatevar
vs
"iterate over all public and private variables of this instance
and do XYZ with them."
They feel qualitatively different, with the latter feeling more like
reflection and the former feeling more like bad news, even though they
both stem from precisely the same language rules.
As an example you might be able to relate to, to see what I'm talking about,
consider http://www.boost.org/doc/libs/1_38_0/libs/serialization/doc/index.html
Look at the "class gps_position" example. It has a pair of routines named
"serialize" each of which lists the exact same variables in the routine as
are in the class. With a reflection library, adding this sort of
serialization would be done by having a mix-in multi-inheritance routine,
and you wouldn't need to code that sort of body at all. Of course, there
would likely be routines like "serialize everything" and "serialize all
public members", as well as routines like "serialize everything but X and Y,
and when you load back in from the archive, invoke fix_up() on the loaded
instance to fix X and Y." So lots of uses of this sort of thing are done
from within the class, just taking advantage of the fact that you *already*
listed the names and types of the instance variables, so why do it again?
Yeah, you can use it to get to the insides of classes from outsides, but you
kind of want that for your IDE and your debugger. :-) It's a lot of power,
and IME not a whole lot of misuse.
--
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:
> Or, to just phrase it a different way, I've been actively and consciously
> attempting not to say bad things about C++ and to ensure whenever I point
> out a limitation I also point out the equivalent limitation in other
> languages. Yet you continue to fall back on "you're bashing C++ to annoy
> me", which is kind of discouraging.
I'll try to be less paranoid next time.
--
- 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:
> I'll try to be less paranoid next time.
Thank you. I appreciate it. In return, feel free to say something early on
if it sounds like I'm not making the effort. :-)
--
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) |