Re: Hypothetical: All code in classes but main()

From: Mark A. Gibbs (x_gibbsmark_at_rogers.com_x)
Date: 04/11/04


Date: Sun, 11 Apr 2004 17:10:13 GMT


Steven T. Hatton wrote:

> Mark A. Gibbs wrote:
>
>>Your second argument, if I understood it, makes no sense. "Another
>>problem is the fact that functions which were external to a class now
>>gain access to member data and potentially become bound to it. This is
>>the argument Stroustrup gives for having helper functions at namespace
>>scope." So does that support your argument or not?
>
>
> Yes it supports the point I was making.

What point? And supports it how? It still makes no sense to me.

I mean, this is how I look at it. If I have a class Foo and a function
bar(), there is no coupling unless there needs to be, and if there needs
to be a relationship, there needs to be a relationship.

>>If a function requires access to member data, then by all means make it
>>a member function. But static functions can't access member data, now
>>can they?
>
>
> Of course they can.

I did not say class static functions, I said static functions, which is
equivalent to globabl functions. I was being very careful not to do this
in order to not muddy the waters, but this one slipped by.

Globabl functions cannot access member data. So there is no imperative
to make them members. It is completely optional.

>>something different, I suppose, but for all practical purposes it is
>>safe to assume that the only functional difference between a global
>>function and a class static function is that that the class static
>>function has access to private and protected class static data and
>>functions.
>
>
> A static function has access to all member data. Am I missing something
> here? I only have a couple months of real C++ experience, so I may have
> misunderstood something, but I'm almost certain a static member function
> can access all member data of instances of the class.

class Foo
{
public:
    static void foo();
    static int foo_and_bar_can_see_me;
    int foo_cannot_see_me1;
protected:
    static int foo_can_see_me1;
    int foo_cannot_see_me2;
private:
    static int foo_can_see_me2;
    int foo_cannot_see_me3;
};

void bar();

Given an instance of Foo f in foo or bar:

void foo()
{
    foo_and_bar_can_see_me = 1; // ok
    foo_can_see_me1 = 1; // ok
    foo_can_see_me2 = ; // ok

    Foo f;
    f.foo_cannot_see_me1 = 1; // ok
    f.foo_cannot_see_me2 = 1; // ok
    f.foo_cannot_see_me3 = 1; // ok
}

void bar()
{
    foo_and_bar_can_see_me = 1; // ok
    // foo_can_see_me1 = 1; // bad
    // foo_can_see_me2 = ; // bad

    Foo f;
    f.foo_cannot_see_me1 = 1; // ok
    // f.foo_cannot_see_me2 = 1; // bad
    // f.foo_cannot_see_me3 = 1; // bad
}

While you are technically right, that a class static function can access
all data members, if it needs to access private and protected instance
members, why is it a class static function?

Actually, that brings up another area that you're way out in left field
on. Public data members. I was actually shaking my head in disbelief at
your proposed "associated" extension. I have never heard any recommend
the use of public data members in good OO design. It violates
encapsulation. I have heard some Java wags claim that for performance
reasons the cost of the accessor methods can be too much, but even that
has been debunked as nonsense. Just declare your accessor methods final
and most compilers will optimize them away. In C++ you don't even need
to rely on the compiler's whims and fancies, just make the accessor
functions inline.

There are no benefits to public data members except for backwards
compatability with old C code (and that is not an issue in this discussion).

> If you have a reasonably good IDE its very easy to type:
> java.[get a listing of available packages and classes]

Oh my lord. Your justification for a restrictive design constraint to be
applied to an entire body of work is that it makes it easier to make
flashy IDE's?

But I'll tell you what, I'll play along.

Why is it not possible for a C++ ide to detect a function sin() in a
namespace math in a namespace top?

I type "top" then a "::" and the IDE looks for a class or namespace
called top. It finds the namespace named top and pops up a charming
little list box of all namespaces, classes and functions in namespace
top. Then I click on the "math" namespace, and the box refreshes, now
with a list of all the namespaces, classes and functions in namespace
top::math. I could scroll down, but I'm too lazy, so I type "s". the
field is narrowed considerably. There's sec(), sin(), sqrt() and more. I
could click, but I paid a lot for this snazzy IDE, so I type the "i".
Now the field is narrowed down to sin(), sinh() and a couple others. So
I click on the "sin". Now I see a list of all the overloads of "sin".

Now, none of my IDE's do it, but I've never been impressed by IDE's, so
my compilers often have none to speak of (or I don't use them often, as
in the case of CodeWarrior). I suppose I could get a better editor. So
I'm not an authority on the subject, but there's probably an IDE out
there right now that does it for C++. If not, there's no practical
reason why there can't be, once someone is willing to put in the work.

> select
>
> java.Math.[get a listing of available members with their type displayed]

java.lang.Math perhaps?

>>You could replace "static Math class in Java" with "Math namespace in
>>C++" in your statement, and it would still be valid. The *only* reason
>>there is a static Math class in Java (as opposed to a Math namespace) is
>>that Java does not support free functions.
>
>
> One might argue that the real difference is that in Java you have another
> level of encapsulation. I find 'free' functions to be of questionable
> value. Some people seem to think of them as global functions.

There is no other level of encapsulation, encapsulation happens (as it
does in Java) at the class level. If you expose the guts of your class,
that is hardly the fault of an external function.

An external function that uses a class is just another client of that
class. It sees the same interface as anyone else. If that interface
changes, well you broke your program anyway, that's not the function's
fault.

>>Given that C++ has the option, what are the advantages here?
>
>
> Perhaps. There is the advantage of predictability. That is, since there
> are fewer options, it's easier to determine how something is structured.
> It also enforces certain structural rules that programmers might otherwise
> violate.

I thought the structure was quite clear. All the math functions are in
the Math namespace.

What you're telling me is that you think having all the math functions
in the Math class is more structured than having all the math functions
in the Math namespace. But they're the same thing.

The only possible plausible argument in your favour is that having a
Math class means that all the math functions must be declared in a
*single translation unit* (or a single header file, in practice). Yeah,
I suppose there's some merit to that - you know exactly where to look
for a function. But that comes at a price.

The price is that I now have to include ALL the math functions in a
source file, even if I just want sqrt(). Also, if I have 1000+ math
functions (which is not inconceivable, what with overloads and all), and
I want to change or add just one, ALL files that use ANY math functions
will now need to be rechecked by the compiler. So much for predefined
headers.

Plus the obvious maintennance headaches trying to maintain one HUGE
header file instead of a dozen smaller ones.

You have not decreased coupling, you have increased it.

>>>>Both can run just as fast (if you inline the former; the latter is
>>>>intrinsically inlined), so it's not a speed issue. Namespace Math::max
>>>>provides (essentially) the same amount of collision protection and
>>>>encapsulation as class Math::max, so it's not a maintennance issue.
>>>
>>>
>>>Other than the fact that people tend to be sloppy with namespaces.
>>
>>People can be just as sloppy with anything in C++, and it's usually the
>>same people. Is there any emperical evidence that people tend to
>>sloppiness when namespaces are introduced?
>
>
> The STL.

Ok, that's not even a complete sentence. The STL what? Sucks? R0x0rs?
Tastes like candy? What makes the STL empirical evidence that namespaces
cause sloppyness? And once again, sloppy in what way? What is sloppy?

>>Yes, but there are many ways of doing this in C++. You could use a
>>"Math" class, or you could use a "Math" namespace, or you could prefix
>>global functions with "Math_".
>
>
> And (some) C++ programmers believe the last is a viable option.

Your point? Some Java programmers believe that public data members are a
viable option. I wouldn't hire from either group.

>>Each of these methods groups certain
>>operations together, and each tell me different things about that
>>grouping. The class tells me that "Math"'s are things, ie, objects -
>>it's not called object-oriented programming for giggles - just like
>>class Student, class smart_ptr_policy or class ifstream. The namespace
>>tells me that these functions are conceptually grouped in some way, but
>>otherwise gives me no further indications of how - which is fine, all I
>>really need to understand is that they are all "Math" functions.
>
>
> But when you have disorganized your collection of operators as described
> above, it is more difficult to work with. As far as OO goes, if you really
> understand what Java is doing, you would understand that it is very much OO
> to do things that way. But even if you only look at the surface, there is
> nothing non-OO about using utilities classes. It's just another way of
> using tools effectively.

How have I disorganized anything? From what I can read it's perfectly
well organized. The only difference between your organization and mine is:

// mine
namespace Math {
    // organization
}

// yours
class Math {
public:
    static // organization
};

I understand perfectly well what Java is doing. And why. And while I
could argue over whether it may or may not be "the" OO way to do things
(because OO is not exactly written in stone, you know, there are many
interpretations of the OO gospel), I will point out instead that OO is
hardly the last word in software design theory. Just search for object
oriented critiques, and alternatives.

As for utilities classes not being "non-OO", that's quite open to
debate, but I am not going to debate it. Instead I am going to take you
up on your final statement. "It's just another way of using tools
effectively."

The problem with that is that you're not using the tools effectively. In
fact, you're not using the tools at all. Namespace-scope functions are
tools, too. They are designed to solve a specific problem: operations
that are not associated with class data. You're tossing the screwdriver
aside and using the hammer to drive screws.

In Java, all you have is the hammer, so what can you do but use it
everywhere. In C++ (WHICH IS NOT AN "OO" LANGUAGE - it supports multiple
paradigms), you have a whole array of tools. Why stick to the hammer?

>>Of course I understand that, it was my argument after all. But a class
>>describes a (surprise, surprise) class of objects.
>
>
> So if there is only one instance of a class, does that mean OO has been
> missused? I find that argument against the use of the Math class to be
> silly. Ever wonder why the German cognate for the English /dish/ means
> table? There is a lesson there.

I am not an OO expert, so I really can't speak on that authoritatively.
Personally, I don't think singletons violate OO design. But we're back
again to insisting that you can create a "Math" (although we're now
insisting there can be only one (from the Matrix to Highlander)). And
once more I say, there is no Math. But prove me wrong, make one.

And no, I've never wondered why any german thinker for english crockery
would mean table, and for what. And I'm sure there is a lesson there,
there are lessons everywhere. The questions should, is it a good lesson?
And, is it relevant?

>>The ONLY valid
>>reasons I can think of for having a non-instantiable (static) class is
>>when that body of operations MUST NOT be extended, and/or they all make
>>use of some kind of private data/algorithms that MUST NOT be visible to
>>the rest of the program.
>
>
> I tend to believe the onus falls in the other direction as far as the
> visibility of data. But that's just what the standard texts on OO say.

Wha?

What onus? What other direction? I mean, if the body of operations CAN
be extended, and if they do not make use of any private data or
functions (that cannot be contained within the function of course), why
do the "standard texts on OO" say that they must be in a class instead
of a namespace?

>>As I mentioned before, Java has no choice but to do max() with static
>>class members. You have a choice in C++.
>
>
> One might argue that you have the illusion of choice in C++. How many
> main() functions can exist in a C++ program? How do you specify the
> namespace for that function? That sounds like a restraction, not a liberty
> to me.

There is no illusion. You can have as many main() functions as you want.
You specify namespaces for main() functions the same way as for any
other function. You can only have one *entry point*, but that's true for
Java too (in the least illogical case). The only "restriction" here is
that the main() function in the global namespace is the entry point.

Java's restriction is no less restricting: the entry point must be a
static function called main in your startup class. You can have static
functions called main in other classes if you want. You can have free
main functions in other namespaces if you want. What's the problem?

>>But to me at least, you are making a statement when you create a class
>>vs. a namespace. A class describes a "thing", an object. A namespace
>>describes a group. To me, mathematical operations can be grouped. But a
>>"Math" doesn't have a "cosh()" capability.
>
>
> I could be argued that /a/ math does have a cosine. But I would tend to
> argue that for practical purposes, there is only one (singleton) math.
> Math /is/ actually instantiated implicitly in Java.

It could also be argued that the world is a flat plate resting on the
back of an infinitely high pile of turtles, and that there are fairies
whose job it is to catch us when we fall off one side and put us on the
other and to alter all of our memories and measurements to keep the
truth from us. That doesn't make it right.

If you really understood object oriented terminology, you'd be laughing
at the idea of instantiating math. What's next, inheriting from Humour?
Extending Peace? Overriding Truth?

> Yup, you understood the intent. There are some advantages to the functional
> operator approach to mathematical symbolism.

Unless, of course, you're doing math.

>>I understand that it was hypothetical, so was my proposed "morse coding
>>standard".
>
>
> Can you provide an example of a successfull general purpose programming
> language that used such an approach?

After you provide me with a coherent and compelling argument in favour
of ditching non-class functions.

> I'm not sure of all the cause and effect, but, yes, Java pretty much forces
> the creation of Math. There, of course, are a few alternatives, such as
> making a class for each operator, or for some subset of operators. I'll
> grant that Java lacks a lot of the available finesse in C++. But that
> feature of C++ comes at a cost.

Yes, more complicated compilers and a shortage of IDE's that are smart
enough to automatically guess the function you intend to use from part
of the qualified name.

Frankly, I don't care how hard my compiler vendor has to work to make me
a working compiler. I mean, props to the dudes at Edison, but I don't
see how that's relevant to my design process. So Java lacks a lot of the
finesse of C++, that doesn't explain to me why you would choose to dumb
down C++ now to make it more like Java.

And of course, it doesn't answer the cardinal question. If Java is the
model that C++ should follow, why does Java keep evolving to look more
like C++?

mark



Relevant Pages

  • Re: Hypothetical: All code in classes but main()
    ... the argument Stroustrup gives for having helper functions at namespace ... If a function requires access to member data, then by all means make it ... > There are advantages to having the static Math class in Java. ...
    (comp.lang.cpp)
  • Re: Hypothetical: All code in classes but main()
    ... > gain access to member data and potentially become bound to it. ... >> There are advantages to having the static Math class in Java. ... >> Other than the fact that people tend to be sloppy with namespaces. ...
    (comp.lang.cpp)
  • Re: Hypothetical: All code in classes but main()
    ... > all data members, if it needs to access private and protected instance ... > the use of public data members in good OO design. ... > namespace math in a namespace top? ...
    (comp.lang.cpp)
  • Re: Hypothetical: All code in classes but main()
    ... > One reason for having a static member function is to implement a singleton ... Public data members. ... >>the use of public data members in good OO design. ... >>in the Math namespace. ...
    (comp.lang.cpp)
  • Re: Static member and namespace - a puzzle.
    ... > namespace I have a class with a static const double member. ... > member is not an int so I cannot initialise it within the class, ... > tried putting the initialisation in the header file immediately after ...
    (comp.lang.cpp)