|
|
Warp wrote:
> Darren New <dne### [at] sanrrcom> wrote:
>> 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.
>
> I still prefer option #1. It's not like it would exclude option #3, so
> you get the best of both worlds: Clarity in naming conventions, *and* the
> compiler checking the integrity of the interface.
I disagree. Now you've got a naming convention that isn't enforced that
would mean something to people trying to read your code. Duplicate work,
with uglier source code, and insufficient reliability to depend on. I think
we've all learned that faux-Hungarian notation is a bad idea.
Unless the compiler also enforces that (say) privately scoped variables
start with an underline, at which point, why? What prefixes are you going to
have the compiler enforce, and what benefit does it bring, and why not just
have the prefix indicate the type information (like trailing $ means string
in basic)?
>> 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.
>
> And if you don't prevent it, you are locking yourself out of ever trying
> to improve your module (without breaking tons of existing code).
Not really. The beauty of the reflection libraries are that they allow the
person using them to *adjust* what they do when you change your code, all
without having to change *their* code. Does using
write(handle, &thestructure, sizeof(thestructure))
prevent you from ever adding anything to thestructure? No. Why? Because
you're getting metadata from the compiler (via sizeof) rather than
hardcoding a 137 as the size or some such.
Of course, that's hardcoded at compile-time, and the results it writes out
can't be read into an instance of the new version of the structure, which is
exactly why people started building more complex reflection libraries,
hibernation libraries, and so on.
If you have something like your function parse library, and I want to take
an instance of that and send it to a process on a different machine, how do
I do that? I can't, without violating the encapsulation, because you didn't
provide for that. But if my income this week depends on me getting to your
private variables, C++ isn't going to be able to stop me.
(I may be wrong, but it doesn't look like you provide accessors for anything
in the instance, so I can't even look at it after the fact and see what
function it's representing? It looks like I can't have a function that takes
an instance of FunctionParser and pulls out enough information that I can
make a second FunctionParser that does the same thing, other than via
AddFunction (second overload)?)
But with reflection, I can write code that does this, *and* it will *still
work* even after you change your class, even if you rewrite it completely.
Hacking past "private" is a whole different ball of wax than reflection.
Hacking around "private" can be a mistake (bad pointer) or intentional
(#define private public), but reflection is always intentional *and* it's
easy to write it to self-adjust.
--
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
|
|