 |
 |
|
 |
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> Darren New <dne### [at] san rr com> 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. In the second case, it's obvious from inspection. If you have
>> x._y
>> in your code, you're doing something wrong. :-)
>
> Btw (not flaming here), what would be the naming convention for nested
> classes? Take, for example, this kind of situation, in C++ code:
Python is kind of funky in this respect. Nested classes (or functions, or
etc) don't have access to the private variables of the classes they're
nested in. They can only get locals, globals, or built-ins. A lambda
expression can, but that's not a separate class as such, but just an unnamed
function.
Depending on which naming convention you're talking about, class beta nested
inside class alpha would be alpha.beta (if it's a public class), or
alpha._beta if it's a private class.
In python, classes are values just like strings and lists and such. You can
even instantiate classes without using the normal syntax, just by invoking
the appropriate constructor for type "class". The syntax
class abc:
...
just invokes that constructor and assigns the result to the variable abc
(which creates the variable in that namespace if it doesn't already exist).
So if you nest alpha within beta like this
class beta:
static_one = 1
static_two = 2
def beta_add(self,x,y):
return x + y
class alpha:
root = 27
def alpha_add(self,x,y):
return x + y + root
then you get beta.static_one and beta.static_two and beta.beta_add and
beta.alpha. You also get beta.alpha.root and beta.alpha.alpha_add.
Alpha can't access beta.static_one without using a dot. Beta can access
alpha (as in "new alpha" sort of thing) without a dot, because alpha is a
static variable of class beta.
But the namespaces that routines in alpha can access don't include the
namespace that beta uses, and vice versa.
Hence, to get to alpha from outside of beta there, you need to say beta.alpha.
If you want alpha to be private to beta, so beta is (say) your linked-list
class and alpha is a single link, you use "class _alpha:" instead, which
indicates that beta._alpha is meant to be private to beta.
If you want alpha to be public, you name it "class alpha:" and others refer
to it as beta.alpha.
Does that answer it? I probably gave way more details than you were actually
asking about. :-)
The same naming convention holds for what you'd call "member variables" in
C++, member functions, static variables/functions, nested classes, etc.
Everything gets assigned to a variable. If you want gamma to implement the
same foobar function as delta does, you can just write
gamma.foobar = delta.foobar
and they're both the same function afterwards.
--
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] san rr com> wrote:
> Does that answer it? I probably gave way more details than you were actually
> asking about. :-)
I actually didn't understand your answer. There might have been some
miscommunication.
Let me restate:
There's a class named 'OuterClass', which has a public interface for
everything else to use, and a private part which is used only by 'OuterClass'
itself, and should be accessed by anything else.
This private part declares another class named 'InnerClass'. This class
in question is part of the private implementation of 'OuterClass', and thus
should not be used in any way from the outside. However, 'OuterClass' itself
can, naturally, use it as usual.
However, 'InnerClass' itself also has a public and a private part: The
public part defines the interface for 'OuterClass' to use. The private
part is for the internal implementation of 'InnerClass' itself, and shouldn't
be accessed by 'OuterClass'.
The question is: If we are using a naming convention to denote public
and private data, how do you name 'InnerClass' and its private members?
Since 'InnerClass' is part of the private implementation of 'OuterClass'
and thus should be used from the outside, I assume that the convention is
to call it '_InnerClass' (or whatever). The underscore denotes "don't
use this class from outside 'OuterClass', because it's private".
How how do you name the members of this '_InnerClass'? All of its
members, even those in the public interface, are part of the private
implementation of 'OuterClass' and thus shouldn't be used from outside,
so do you put underscores in all the members, even public ones?
What about the private members of '_InnerClass'? How do you differentiate
them from the private members of 'OuterClass'?
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> The question is: If we are using a naming convention to denote public
> and private data, how do you name 'InnerClass' and its private members?
Got it.
OuterClass
OuterClass._private_static_of_OC
OuterClass.public_static_of_OC
OuterClass._InnerClass
OuterClass._InnerClass.used_by_outerclass
OuterClass._InnerClass._Used_only_by_innerclass
Does that clarify?
OuterClass could invoke
x = _InnerClass.used_by_outerclass
The trick is you shouldn't write "._" as part of a reference. :-)
> How how do you name the members of this '_InnerClass'? All of its
> members, even those in the public interface, are part of the private
> implementation of 'OuterClass' and thus shouldn't be used from outside,
> so do you put underscores in all the members, even public ones?
Oh, no. InnerClass isn't really "part" of outer class. It's just a class
that happens to be created while creating InnerClass and assigned to a
static variable of InnerClass.
Python doesn't have declarations, even of classes and functions and methods.
It has statements that have lumps of code in them and creates an instance of
a function object or an instance of a class object, and then assigns it to
the name you gave the statement. So there's no real relationship between
InnerClass and OuterClass, any more than you have a relationship between a
sphere object and the texture on the sphere. There's a relationship there,
but it's not a relationship having to do with types, but rather with
pointers to instance objects. Kind of like javascript in that respect.
> What about the private members of '_InnerClass'? How do you differentiate
> them from the private members of 'OuterClass'?
The private members of _InnerClass have _ on the front. _InnerClass can't
access OuterClass's private or public variables without going through the
class or instance dot-notation.
InnerClass and OuterClass are two 100% separate and independent classes. You
could get *exactly* the same result by declaring it this way:
class InnerClass:
.....
class OuterClass:
...
_InnerClass = InnerClass
...
(Except of course now InnerClass has a global name also)
A nested class definition says "Create a new instance of type 'class' and
assign it to this name in my namespace." But that doesn't give the nested
class any access that any other class could have, and vice versa. It's just
a different name for a class. InnerClass doesn't have anything that points
to the parent class, so there's no way to get to anything in the parent
class directly from InnerClass. If the parent class has a global name like
"OuterClass", then you can refer to that, of course, but there's nothing
that tells InnerClass it's "part of" outerclass.
--
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] san rr com> wrote:
> Warp wrote:
> > The question is: If we are using a naming convention to denote public
> > and private data, how do you name 'InnerClass' and its private members?
> Got it.
> OuterClass
> OuterClass._private_static_of_OC
> OuterClass.public_static_of_OC
> OuterClass._InnerClass
> OuterClass._InnerClass.used_by_outerclass
> OuterClass._InnerClass._Used_only_by_innerclass
> Does that clarify?
> OuterClass could invoke
> x = _InnerClass.used_by_outerclass
> The trick is you shouldn't write "._" as part of a reference. :-)
But an outside code could do something along the lines of:
OuterClass::_InnerClass obj; // Assuming the compiler doesn't restrict this
obj.someFunction();
The first line clearly breaks the privacy contract, but with the second
line it's not so obvious anymore. It's calling a public member of _InnerClass,
but it's intended to be "public" only for OuterClass (because _InnerClass is
part of the private implementation of OuterClass), not for anything else.
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|
 |