should i learn c?

J

James Kanze

Sun's guidelines for Java suggest that you declare the
variables at the top of the block, even though the language
doesn't require it.

The only justification I can think of is that, like C++, Java's
syntax (like that of C++) doesn't really effectively distinguish
between a definition and an expression statement. Which makes
recognizing the definitions in a block of code somewhat
problematic. The obvious solution is to use some arbitrary
formatting element to make them identifiable---I use internal
spacing in a definition for this, for example. In Java, it's
probably not as bad defining everything at the top, since on one
hand, the only things you can define all have reasonable default
initializations which can be used if you don't know what else to
use, and the language itself requires "definite assignment": the
compiler is required to do a minimum of flow analysis in order
to verify that the variable is initialized before use. But it
still seems like a case of two wrongs trying to make a right.
Java also doesn't support inline. It helps me to think of
"setting up stack frames," rather than "declaring variables,"
even when I realize that the function I'm writing will
probably be inlined automatically, and therefore not require
its own stack frame at all.
I agree with your implied point that one probably shouldn't be
defining variables before one is ready to initialize them.
However, if you find yourself declaring variables in the
middle of a block, it may be worthwhile to factor that portion
of the block into a separate function, anyway.

Yes. Still, I can see cases where you might have a (very)
little code before defining a variable. Something like:

void*
operator new( std::size_t n )
{
n += myOverhead ;
void* result = malloc( n ) ;
// ...
}

But on the whole, if you find a lot of declarations showing up
other than at the top of the function, you're probably doing too
much in the function.
 
S

SG

Jeff said:
SG said:
In Java the compiler warns
about uninitialized object references. Good point.
[...] As far
as the C++ compiler is concerned  such objects (excluding built-in
types) are initialized already and there's no need to warn about any
kind of usage because the C++ compiler can't tell whether a default
constructed object is "logically initialized" (as it might not be the
case in two stage initializations, see std::ifstream, default-
constructor + ifstream::eek:pen).

How is that any different from Java?  Java doesn't have any way of
knowing whether objects have been "logically" initialized, either.

Right. The difference is that in Java you are limited to object
references. Such an object reference can be uninitialized so the
compiler can warn about read access to these references. In C++ you
could ...

(1) create the object on the stack at which point it is considered
initialized by the compiler. This would be a case for late
definition.
(2) use an uninitialized pointer instead. The compiler can warn about
read access of uninitialized pointers. This is similar to the Java
version with references. It's okay to define these pointers early.
(3) use a default constructed smart pointer. Such a thing is also
considered initialized by the compiler which suggests late
definition of smart pointers.

Compare smart pointers to native pointers the native pointers have a
slight advantage over smart pointers in that the compiler can warn
about the use of uninitialized pointers.


Cheers!
SG
 
A

Alf P. Steinbach

* Jeff Schwab:
What word do you feel I misinterpreted? Could you please point out the
original use, and where you believe I used it to mean something different?

Oh sorry, the quoting disappeared.

Original use:

* (e-mail address removed):
I find it useful to be able to define variables


Jeff assuming a non-sensical meaning:

* Jeff Schwab:
That's not possible in C++, because the definition of a variable is
the only place you can initialize it. Beyond that, you're talking
about assignment


In essence you're assuming the other guy doesn't even know English, and that
therefore it's just a big cosmic coincidence that the other guy's sentence
appears to be sensible: you're assuming the least sensible meanings of words.


Cheers & hth.,

- Alf
 
S

SG

Jeff said:
Why is this more a case for late definition in C++ than in Java?  IOW, I

My example was an object of class std::ifstream. Consider you'd like
to create it on the stack (because you don't need it to outlive the
scope) but decide to call ifstream::eek:pen at a later time. Then you
can make the mistake of using it without it being fully ("logically")
initialized (i.e. opened).

In Java the only thing you CAN do is defining built-in types or
references. And these references can be uninitialized. My point is:
Instead of

MyObject mob = new MyObject(); // default-init
mob.fullinit();

you would rather write

MyOBject mob;
mob = new MyObject("full init");

if you whish to delay initialization. Here the Java compiler gives an
ERROR (Sun's compiler rejects the code) if there's any read access to
"mob" prior the assignment. So, if you stick with initializing
references only with fully usable objects (i.e. opened streams) early
function scope definitions of object references pose no danger.
You're really relying on the compiler at that point, though.  If the
compiler doesn't warn, you'll get some awfully nasty bugs.

Sure.


Cheers!
SG
 
A

Alf P. Steinbach

* Jeff Schwab:
Here's what you snipped: "I know it's a subtle point, but there are
meaningful differences."



"Initialization" has special meaning in the context of C++, as you know.

I'm sorry, that's a misunderstanding (on your part).

The word "initialization" has many different meanings in the context of C++
prgoramming, including but not limited to the general language-independent
"ensuring first meaningful value/state" as well as more specialized C++ specific
meanings such as static initialization, dynamic initialization, constructor
call and call to init member function (e.g. in iostreams).

It seems that the particular special meaning (out of the many special meanings)
you're alluding to is the one of a successfully completed C++ constructor call.

That meaning can reasonably be assumed in a context discussing C++ constructor
calls.

But it cannot reasonably be assumed in a context where that meaning becomes
non-sensible and another and quite sensible meaning is strongly implied.

The upshot is that you assumed a completely unreasonable meaning, and it doesn't
matter whether it was the one I guessed above or some other silly one, which
just a few seconds reflection could have told you was completely unreasonable.

And not just in that article but also e.g. when "arresting" James on his use of
"global variable". :)

Initialization and assignment are frequently confused. I consider it
important to make this distinction, particularly in the context of
determining whether variables should be defined before (as SG calls it)
"logical initialization." In particular, define-then-assign implies
that the value cannot be const.

I mainly agree, except that to combat confusion more clear terminology could
Really Help. ;-)


Cheers & hth.,

- Alf
 
A

Alf P. Steinbach

* Jeff Schwab:
What's a "constructor call?" You can't call a constructor. The closest
you can get is placement new.

I'm sorry.

I was using the C++ standard's terminology (namely, "constructor call") to avoid
any confusion, seeing as how today you're having problems grokking even very
simple words.

But if I instead had used some term that was not standard in the sense of being
used in the international C++ standard, even then you should ideally not have
had a problem with it.

I'm not sure what you're after here... Assignment is not the same thing
as initialization, and errno isn't a global variable.

And ideally you shouldn't have had any problem grokking this, either (for the
record, your statement before the comma is vague and misleading, considering the
earlier context of you misinterpreting someone's use of the word
"initialization", and the statement after the comma is incorrect).

Well I certainly agree with that, but you seem to have been trying to
say otherwise: That technical terms should not have precise meanings,
but should be accepted in a kind of blurry, vernacular sense.

Nope. I'm just trying, unsuccessfully so far, to

1. guide your attention to the fact that a word can have many meanings, and to

2. enlighten you about the social convention that a sensible meaning should be
assumed instead of a non-sensical and completely unreasonable one.

You also seem to have gotten kind of angry about it
Nope.


, and I'm not sure why.

Understandable, since you're wondering about the cause of a non-existent thing.


Cheers & hth.,

- Alf
 
C

coal

That's not possible in C++, because the definition of a variable is the
only place you can initialize it.  Beyond that, you're talking about
assignment, not initialization.  I know it's a subtle point, but there
are meaningful differences.

By the way, your message is a little garbled:  Lines have been broken to
fit in 72 columns, then broken again to fit in 68.  The result is a lot
of orphaned words.

Sorry. I forget about the lengths sometimes.
All of the functions defined in the class body are implicitly inline.
There is no need to declare them as such.

I was under the impression that inline was needed if the output file
was included in multiple TUs and then those TUs linked together.

Why define an empty constructor and empty, non-virtual destructor?
Aren't these identical to the defaults?  (There may be a good reason, I
just don't see it.)

I added those a while ago and don't see much reason to removing
them.

Brian Wood
Ebenezer Enterprises
www.webEbenezer.net
 
C

coal

That looks better.  This is a good example of the kind of refactoring I
mentioned up-thread.  The code tells you what needs to happen, once you
learn to read it.  This particular kind of refactoring is what Agile
proponents call "DRYing" your code, where DRY stands for "Don't Repeat
Yourself."

After writing my first reply to your comments, I reread your
post and thought about things a little more. Then I replied
again hoping I would beat anyone else who would also reply and
point out the idea before I did.

I've done a little work comparing the two approaches now. I also
wrote a boolReceive function and generated code that sends and
receives 481 bools using both approaches and compared the .o
files. They were both 1436 bytes without optimization, both
1340 bytes with -O3, both 780 bytes when the -O3 versions
are stripped and using cmp the stripped versions are equal.
I'm not going to bother with any run-time tests at this point.
Thank you for the ideas.

Now I would like to do the same thing for the string classes
we support: std::string and flex_string<char>. (We support
one other string class also.) Making this work for
std::string doesn't seem difficult, but flex_string with
it's multiple template parameters seems like it might be
more difficult.
A typedef for that unsigned char also would have made the intent clearer
to me.  It took me a few seconds to figure out why you were implicitly
converting a bool to an unsigned char, and whether that was intentional.
  For example, something like one of the following, with case and
underscore conventions adjusted for consistency with your library:

     typedef unsigned char byte;
     typedef unsigned char bool_representation;

I was happy to post that implementation in case someone would say,
"Why don't you do it this way?" I wasn't sure if bools are guaranteed
to be one byte -- on gcc 4.3.2 they are one byte, though. I'm not
going to use the typedefs for now. Maybe later.


Brian Wood
Ebenezer Enterprises
www.webEbenezer.net
 
C

coal

You mean because of testing?

No. Now I think it may not be too difficult. It's been a long
winter here and I'm tired. It's supposed to be in the 40s here
over the weekend and that seems really great.
I was happy to post that implementation in case someone would say,
"Why don't you do it this way?"  I wasn't sure if bools are guaranteed
to be one byte

They aren't.  Section 5.3.3 Sizeof, p. 1, says:

"sizeof(char), sizeof(signed char) and sizeof(unsigned char) are 1; the
result of sizeof applied to any other fundamental type (3.9.1) is
implementation-defined. [Note: in particular, sizeof(bool) and
sizeof(wchar_t) are implementation-defined.69) ]"

Thanks. That's what I thought from reading some threads about bools,
but wasn't 100% sure.


Brian Wood
Ebenezer Enterprises
www.webEbenezer.net
 
J

James Kanze

SG wrote:

[...]
You're really relying on the compiler at that point, though. If the
compiler doesn't warn, you'll get some awfully nasty bugs.

If he's thinking of Java, Java requires a compile time error if
there is a path through which a variable gets accessed before
having been initialized. (See §16 of the Java specification, or
Google Definite Assignment Java.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,161
Messages
2,570,892
Members
47,431
Latest member
ElyseG3173

Latest Threads

Top