Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > To bean or not to bean

Reply
Thread Tools

To bean or not to bean

 
 
Sam Holden
Guest
Posts: n/a
 
      09-02-2004
On Wed, 01 Sep 2004 19:30:12 -0400,
Steven T. Hatton <(E-Mail Removed)> wrote:
> Sam Holden wrote:
>
>> On Wed, 01 Sep 2004 03:52:53 -0400,
>> Steven T. Hatton <(E-Mail Removed)> wrote:
>>> Phlip wrote:
>>>
>>>> Steven T. Hatton wrote:
>>>>
>>>>> And you get threadding, unicode, effortless portability, incredibly
>>>>> smooth refactoring, highlevel abstraction with the tools to support it,
>>>>> great,
>>>>
>>>> Threading is good??
>>>
>>> Hu? Even Microsoft eventually figured that out. Yes. Thread support is
>>> crucial for creating any sophisticated application that can be expected
>>> to do more than one thing at a time.

>>
>> Strangely enough I've been using non-threaded applications that
>> do more than one thing at a time and are reasonably sophisticated.
>>
>> Where sophisticated means things like: makes multiple concurrent TCP
>> connections, encodes and decodes audio sending and receiving it over
>> UDP, displays GUI and so on - without a thread in sight (well one
>> thread for the pedants).

>
> OK. Let me be clear as to what I really meant be threading. I really
> intended concurrent programming with resource locking and synchronization.


But you only need resource locking and synchronization because of the
existance of the threads. The code I was thinking about above contains a
fifo queue onto which one "section" of code pushes "events" it has
received via a TCP connection. Another "section" of code pops those
"events" in order to deal with them.

This could use threads - that would be one way to implement it. One
thread would do a blocking read on the network socket and when an event
was received would push it on the queue. Another thread would do a
"blocking pop" (or some equvalient thing) on the queue and deal with the
events. That would require resource locking and synchronization - in
this case the queue is the resource. It would also mean that all the
global data in the program is accessable by both threads. Obviously the
queue needs to be, but due to using threads all the rest of it is too.
Any global data could change state at any time - of course the
programmers will hopefully know which parts of the global state they are
allowed to touch and which need locking and synchronisation. But why
throw away decades of work into systems which can eforce those
restrictions?

In this case my code doesn't use threads, it uses asynchronous events -
when data is available on the socket it gets read and an event pushed on
the queue. To pop from the queue, a callback is provided which is called
when something becomes available and so on. The "main loop" of the
system just multiplexes between the various "sections" according to the
events (button clicks, network sockets changing state, etc).

The disadvantage of this is that on a multiprocessor machine the program
only uses one processor, with threads it could use all of the processors
(well as many as it had threads).

The advantage of this is that no locking is required (which makes things
faster), the programmer doesn't have to worry about "atomic operations"
but can write code knowing that no variable will change value all of a
sudden - no "action at a distance".


> Technically, threading means tracing the same executable image with
> multiple instruction pointers. It's main advantages are the multiple use
> of the same executable image by different 'processes', and the reduced need
> for context switching between processes.
>
>> I even write them occassionaly.
>>
>> Threading throws away decades of work in creating systems with useful
>> protected memory spaces for processes. And lets the average programmer
>> meet all the problems and reinvent (poorly) all the solutions all over
>> again. Rather than using the solution implemented by the (hopefully
>> much more experienced and competent in the domain) OS authors.

>
> What you seem to be suggesting is that threads are used in situations where
> multiple processes would be better. Am I to also understand that all
> concurrency is bad?


Using threads is a *massive* trade off. You are trading off decades of
research and experience into concurrency and system design in order to
get whatever it is threads are giving you (a performance increase?)

The operating system was hopefully designed and implemented by people
who knew what they were doing (which of course may not be the case...)
and who, hopefully, didn't try to reinvent to many of the things like
semaphores.

Threads share memory, the problem is they share all memory (well not
stack and registers, but all "heap" memory if you will). So when you use
threads you have just lost the entire protected memory concept of modern
(and not modern, for that matter) operating systems. You have lost the
resource management handling of the operating system, so you need
to do your own synchronisation.

An obvious alternative is multiple processes and explicitely shared
memory which only contains the data which needs to be shared. That way
the OS can be used to protect the data that doesn't need to be shared,
instead of just trusting no other thread executes buggy code.

Concurrancy doesn't require threads. Threads are one way of achieving
it. How is multiple processes communicating via some form of IPC not
concurrency?

Threads are not all bad, they are the best solution to some problems.
But that set of problems is vanishingly small compared to the
problems threads are usually used to solve...

>
>> Of course there's that vanishingly small percentage of problems that
>> are best solved with threads, but chances are you, me, and the
>> next guy aren't working on one of them.

>
> Please clarify what you mean by 'thread'. I suspect we aren't talking about
> the same thing.


A thread is a concurrently executing entity which has it's own program
counter, registers, stack, and so on but shares main memory with other
threads. That's not a great definition, but hopefully will confirm or
counter your suspicion.

--
Sam Holden
 
Reply With Quote
 
 
 
 
Steven T. Hatton
Guest
Posts: n/a
 
      09-02-2004
Sam Holden wrote:

> On Wed, 01 Sep 2004 19:30:12 -0400,
> Steven T. Hatton <(E-Mail Removed)> wrote:
>> Sam Holden wrote:
>>
>>> On Wed, 01 Sep 2004 03:52:53 -0400,
>>> Steven T. Hatton <(E-Mail Removed)> wrote:
>>>> Phlip wrote:


>> OK. Let me be clear as to what I really meant be threading. I really
>> intended concurrent programming with resource locking and
>> synchronization.

>
> But you only need resource locking and synchronization because of the
> existance of the threads. The code I was thinking about above contains a
> fifo queue onto which one "section" of code pushes "events" it has
> received via a TCP connection. Another "section" of code pops those
> "events" in order to deal with them.


Hey, here's an idea: order these events by some kind of priority. Things
that don't need as much attention could be placed lower on the queue. You
could call it a priority queue. (Yes, I'm yanking your chain.)

> This could use threads - that would be one way to implement it. One
> thread would do a blocking read on the network socket and when an event
> was received would push it on the queue. Another thread would do a
> "blocking pop" (or some equvalient thing) on the queue and deal with the
> events. That would require resource locking and synchronization - in
> this case the queue is the resource.


You could also have a queue of threads. That's what thread pooling does for
you.

> It would also mean that all the
> global data in the program is accessable by both threads.


I tend to use mutable global data about 1% as many times as I use a goto, so
this seems like a non-issue for me. Now, synchronizing shared resource
access /is/ an issue that must be addressed. Java provides the means to
accomplish this, out of the box, in a fairly intuitive way. Some people
think C++ should likewise provide that support. I originally was inclined
to agree. I have now come to the conclusion that it's probably better to
facilitate their use by providing what C++ already does provide, and leave
it to third party providers to produce the thread libraries. And there are
plenty.

> Obviously the
> queue needs to be, but due to using threads all the rest of it is too.
> Any global data could change state at any time - of course the
> programmers will hopefully know which parts of the global state they are
> allowed to touch and which need locking and synchronisation. But why
> throw away decades of work into systems which can eforce those
> restrictions?


If I'm writing a server, an OS, a desktop manager, or similar, I'm pretty
much required to support concurrency. Andy people have attempted all of the
above with Java. The most successful of these has been creating the
server. I don't believe C++'s lack of native support for threading is a
major deficiency. It's nice to have in Java, and the fact that it is
native to the language means that I don't need to study the idiosyncracies
of a particular thread library when I work with a different library. The
downside, of course, is that I can't reasonably implement my own, perhaps
superior, thread support.

> In this case my code doesn't use threads, it uses asynchronous events -
> when data is available on the socket it gets read and an event pushed on
> the queue. To pop from the queue, a callback is provided which is called
> when something becomes available and so on. The "main loop" of the
> system just multiplexes between the various "sections" according to the
> events (button clicks, network sockets changing state, etc).


That's basically polling, if I understand you correctly. It works, Emacs
has been plodding along for decades that way, and there are certainly
advantages to designing your program that way.

> The disadvantage of this is that on a multiprocessor machine the program
> only uses one processor, with threads it could use all of the processors
> (well as many as it had threads).
>
> The advantage of this is that no locking is required (which makes things
> faster), the programmer doesn't have to worry about "atomic operations"
> but can write code knowing that no variable will change value all of a
> sudden - no "action at a distance".


But that is partly due to the fact that your problem domain does not require
you to provide inherently asynchronous services. It may be the case that
threadding is over used by developers. I can't really say. I do know I
was in a situation where the lead engineer was creating his own thread
pooling rather than using that which was provided by the serve we were
developing on. I found that to be a poor choice. But that fact that every
request for service was handled by a different thread was an intuitively
obvious approach to the design.

>> What you seem to be suggesting is that threads are used in situations
>> where multiple processes would be better. Am I to also understand that
>> all concurrency is bad?

>
> Using threads is a *massive* trade off. You are trading off decades of
> research and experience into concurrency and system design in order to
> get whatever it is threads are giving you (a performance increase?)
>
> The operating system was hopefully designed and implemented by people
> who knew what they were doing (which of course may not be the case...)
> and who, hopefully, didn't try to reinvent to many of the things like
> semaphores.


But these are services the OS provides the application programmer. There are
times when it makes sense to use threads, and times when it doesn't.
Sometimes the use of threads is dictated by the development environment.
Application servers tend to naturally favor the use of threadding, and that
is where I have seen them used, and used well, in Java.

> Threads share memory, the problem is they share all memory (well not
> stack and registers, but all "heap" memory if you will).


That isn't correct. There are such a things as thread local resources which
are not shared between threads.


> Concurrancy doesn't require threads. Threads are one way of achieving
> it. How is multiple processes communicating via some form of IPC not
> concurrency?
>
> Threads are not all bad, they are the best solution to some problems.
> But that set of problems is vanishingly small compared to the
> problems threads are usually used to solve...


I can't comment on that because I have not seen them missused.

>> Please clarify what you mean by 'thread'. I suspect we aren't talking
>> about the same thing.

>
> A thread is a concurrently executing entity which has it's own program
> counter, registers, stack, and so on but shares main memory with other
> threads. That's not a great definition, but hopefully will confirm or
> counter your suspicion.


All but the point about 'main memory' are fairly consistent with my
understanding of the term. Threads have some registers of their own, and
some are shared by all threads in a program. The memory shared by threads
is the executable image, and global data. But I don't use global data! The
reuse of the executable image is an advantage even on non SMP systems, as
is the reduced context switching.

--
"[M]y dislike for the preprocessor is well known. Cpp is essential in C
programming, and still important in conventional C++ implementations, but
it is a hack, and so are most of the techniques that rely on it. ...I think
the time has come to be serious about macro-free C++ programming." - B. S.

 
Reply With Quote
 
 
 
 
Steven T. Hatton
Guest
Posts: n/a
 
      09-02-2004
Steven T. Hatton wrote:

> Sam Holden wrote:


>> Threads share memory, the problem is they share all memory (well not
>> stack and registers, but all "heap" memory if you will).

>
> That isn't correct. There are such a things as thread local resources
> which are not shared between threads.


http://doc.trolltech.com/3.3/qthreadstorage.html

The QThreadStorage class provides per-thread data storage.

QThreadStorage is a template class that provides per-thread data storage.

Note that due to compiler limitations, QThreadStorage can only store
pointers.

The setLocalData() function stores a single thread-specific value for the
calling thread. The data can be accessed later using the localData()
functions. QThreadStorage takes ownership of the data (which must be
created on the heap with new) and deletes it when the thread exits (either
normally or via termination).

The hasLocalData() function allows the programmer to determine if data has
previously been set using the setLocalData() function. This is useful for
lazy initializiation.

For example, the following code uses QThreadStorage to store a single cache
for each thread that calls the cacheObject() and removeFromCache()
functions. The cache is automatically deleted when the calling thread exits
(either normally or via termination).

QThreadStorage<QCache<SomeClass> *> caches;

void cacheObject( const QString &key, SomeClass *object )
{
if ( ! caches.hasLocalData() )
caches.setLocalData( new QCache<SomeClass> );

caches.localData()->insert( key, object );
}

void removeFromCache( const QString &key )
{
if ( ! caches.hasLocalData() )
return; // nothing to do

caches.localData()->remove( key );
}

--
"[M]y dislike for the preprocessor is well known. Cpp is essential in C
programming, and still important in conventional C++ implementations, but
it is a hack, and so are most of the techniques that rely on it. ...I think
the time has come to be serious about macro-free C++ programming." - B. S.

 
Reply With Quote
 
Steven T. Hatton
Guest
Posts: n/a
 
      09-02-2004
Chris F Clark wrote:

> That would not have happened if I had written the code inline in all
> the places I might have desired the check.


Why can't you use declarations and definitions to achieve the same thing?
Other than __LINE__ and __FILE__, the use of the CPP seems superfluous. I
do which it were possible to pass strings and or char*s as template
arguments. That would increase their usability as a substitute for
assertions.

> They might have found one
> instance. If they were motivated and had the time, they might have
> done a search for other places, but they might easily have missed some
> place where my coding was slightly different and it wasn't obvious
> that this was an exception for assertion error checking.


What happens when your macro is designed in such a way that expects a
particular kind of behavior on the part of your code, and the modified
macro doesn't understand that?
--
"[M]y dislike for the preprocessor is well known. Cpp is essential in C
programming, and still important in conventional C++ implementations, but
it is a hack, and so are most of the techniques that rely on it. ...I think
the time has come to be serious about macro-free C++ programming." - B. S.

 
Reply With Quote
 
Sam Holden
Guest
Posts: n/a
 
      09-02-2004
On Wed, 01 Sep 2004 21:34:09 -0400,
Steven T. Hatton <(E-Mail Removed)> wrote:
> Steven T. Hatton wrote:
>
>> Sam Holden wrote:

>
>>> Threads share memory, the problem is they share all memory (well not
>>> stack and registers, but all "heap" memory if you will).

>>
>> That isn't correct. There are such a things as thread local resources
>> which are not shared between threads.

>
> http://doc.trolltech.com/3.3/qthreadstorage.html
>
> The QThreadStorage class provides per-thread data storage.


No. It provides virtual per-thread data storage. The actual data is
accessable to all threads - all they need is a pointer to its location
(unless of course a pointer into the stack was used).

It provides a conveniant way of having the correct pointer provided to
the correct thread. But in the presence of buggy code, there is no
guarantee that the data won't be scribbled on by another thread.

In comparison with multiple processes any data which is not in
explicitely shared memory *can not* be scribbled on by another buggy
process (well not without help from a buggy kernel).

Threads are fine and dandy if there are no bugs in the code. Then
again an operating system with no memory protection, that allows any
process to write to any memory location is fine and dandy if there are
no bugs (or malicious intent) in the processes. Threads protect you
from the malicious intent part (all the code is yours), but bugs are
harder to avoid.

Threads cost a lot, and deliver little. Sometimes that little is of such
great importance that the cost is worth it, but often not.

[Snip QT docs]

In a language, such as Java, it would be possible for the virtual machine
to provide such thread local storage, but C++ and current threading
models aren't such a beast.

--
Sam Holden
 
Reply With Quote
 
Steven T. Hatton
Guest
Posts: n/a
 
      09-02-2004
Sam Holden wrote:

> On Wed, 01 Sep 2004 21:34:09 -0400,
> Steven T. Hatton <(E-Mail Removed)> wrote:
>> Steven T. Hatton wrote:
>>
>>> Sam Holden wrote:

>>
>>>> Threads share memory, the problem is they share all memory (well not
>>>> stack and registers, but all "heap" memory if you will).
>>>
>>> That isn't correct. There are such a things as thread local resources
>>> which are not shared between threads.

>>
>> http://doc.trolltech.com/3.3/qthreadstorage.html
>>
>> The QThreadStorage class provides per-thread data storage.

>
> No. It provides virtual per-thread data storage. The actual data is
> accessable to all threads - all they need is a pointer to its location
> (unless of course a pointer into the stack was used).


Actually, they can blow past the stack boundaries in some cases.

> It provides a conveniant way of having the correct pointer provided to
> the correct thread. But in the presence of buggy code, there is no
> guarantee that the data won't be scribbled on by another thread.


I don't claim to be an expert on p-threads, but from reading the
specification you really have to try to access the TLS of another thread.
The only way I can see of doing such a thing is the blow the bounds of an
array, or access a dangling pointer. Neither of these errors are unique to
multi-threading. The only difference between doing this per thread, or per
process, is that accessing out of process memory will get you a big fat
fine from the O/S. If you access a neighboring thread's data, that just
results in corrupted data. There's nothing stopping you from doing that
within a heavyweight process, as long as you don't try to access something
outside of the process's memory space.

> In comparison with multiple processes any data which is not in
> explicitely shared memory *can not* be scribbled on by another buggy
> process (well not without help from a buggy kernel).


Hmmmm. I thought real men don't need protection from themselves. Just ask
Phlip.

> Threads cost a lot, and deliver little. Sometimes that little is of such
> great importance that the cost is worth it, but often not.


It really depends on the context. Servers are natural candidates for the
use of threading.

> [Snip QT docs]
>
> In a language, such as Java, it would be possible for the virtual machine
> to provide such thread local storage,


Recall that this fork started with this exchange:
Phlip wrote:
> Steven T. Hatton wrote:
>
> > And [from Java] you get threadding, unicode, effortless portability,

incredibly smooth
> > refactoring, highlevel abstraction with the tools to support it, great,

>
> Threading is good??

[end excerpt]

> but C++ and current threading models aren't such a beast.


Threads and the Single UNIX(R) Specification, Version 2 (Copyright 1997 The
Open Group)

"Typically, the value associated with a given key for a given thread is a
pointer to memory dynamically allocated for the exclusive use of the given
thread (for example, per-thread stack and stack pointer). The scenario for
establishment and use of thread-specific data can be described as follows.
A module that needs to maintain static data on a per-thread basis creates a
new thread-specific data key as a part of its initialization routine. At
initialization, all threads of the process are assigned null values for the
new key. Then, upon each thread's first invocation of the module (which can
be determined by checking for a null key value), the module dynamically
allocates memory for the exclusive use of the calling thread, and stores a
pointer to the memory as the calling thread's value of the new key. Upon
later invocations of the same module by the same thread, the module can
access the thread's data through the new key (that is, the thread's value
for the key). Other modules can independently create other thread-specific
data keys for other per-thread data for their own use."

You might argue that this is 'on the stack', but that will be true of any
pointers you use to access heap data. As long as your pointers are
properly managed, you should never have a problem. And as I've already
pointed out, that is not unique to threading.

If you are suggesting that the use of threads requires that you know what
you are doing, and that you do it right. I agree. If you are suggesting
it is more difficult to learn than core C++, or at least necessary to learn
something difficult in addition to core C++, yup. I agree again.
--
"[M]y dislike for the preprocessor is well known. Cpp is essential in C
programming, and still important in conventional C++ implementations, but
it is a hack, and so are most of the techniques that rely on it. ...I think
the time has come to be serious about macro-free C++ programming." - B. S.

 
Reply With Quote
 
Richard Herring
Guest
Posts: n/a
 
      09-02-2004
In message <(E-Mail Removed)>, Steven T. Hatton
<(E-Mail Removed)> writes
>Chris F Clark wrote:
>
>> That would not have happened if I had written the code inline in all
>> the places I might have desired the check.

>
>Why can't you use declarations and definitions to achieve the same thing?


I think you're about to answer your own question...

>Other than __LINE__ and __FILE__, the use of the CPP seems superfluous. I
>do which it were possible to pass strings and or char*s as template
>arguments.


That's exactly the point about stringizing and token-pasting that was
raised and answered about 50 posts back in the thread.

>That would increase their usability as a substitute for
>assertions.


But you still wouldn't be able to pass _expressions_, which is what the
use of macros allows. And, thanks to the # operator, you can pass
something which is simultaneously an expression and a string.
>
>> They might have found one
>> instance. If they were motivated and had the time, they might have
>> done a search for other places, but they might easily have missed some
>> place where my coding was slightly different and it wasn't obvious
>> that this was an exception for assertion error checking.

>
>What happens when your macro is designed in such a way that expects a
>particular kind of behavior on the part of your code, and the modified
>macro doesn't understand that?


What happens when any piece of code, macro or not, is designed under a
misapprehension?

--
Richard Herring
 
Reply With Quote
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      09-02-2004
Steven T. Hatton wrote:

> Kai-Uwe Bux wrote:
>
>> Steven T. Hatton wrote:
>>
>>> Yes. You are correct. Information technology is about information.
>>> Good solid easily obtainable information is vital to design, to
>>> implementation, to trouble shooting and to security.

>>
>> a) This is rethoric. The information in "Information technology is about
>> information." is the information, my program deals with. The information
>> in "Good solid easily obtainable information is vital to design, to
>> implementation, to trouble shooting and to security." is information
>> about the structure of my code. The second statement may be true, but it
>> does not follow from the first. You are using one term to reference two
>> different entities.

>
> It's not contradictory, it is simply recursive.


It is neither, the technical term for the way you used the word
"information" in your argument is, I think, "equivocation". But this does
not really matter since the point that you argue for has some merit
regardless of whether the argument was sound: I will just grant you that
"good solid easily obtainable information" about what is going on in my
code is a nice thing to have. And I also agree that C++ allows to write
code where this sort of meta-information is incredibly hard to obtain.

> I am applying the same
> argument a mechanical engineer would use to explain his use of computers
> to
> do his job. The programs and tools a software engineer uses are the
> programming language, the compiler, the IDE, the libraries, etc.


I do not understand this analogy at all. But then again, we are not in
disagreement about the importance of understanding your code and how it
interacts with components beyond your control (like libraries).


>> b) The information about my code is already available. After all, it must
>> be sufficient for the compiler to generate object code. However, I agree
>> that in C++ the information may be scattered around and is not as local
>> as the human mind (or some IDE) would like it to be.

>
> And I believe this is a significant problem that can and should be
> addressed.


There are mitigating strategies that I incorporate in my coding styles. A
problem is, of course, that I have to rely on libraries that might not
follow my coding style. Nonetheless, I feel that a lot can be done without
changing the language.


>> c) I still see that there are trade offs. If you increase what can be
>> known at coding time at the cost of what can be done, then there are
>> trade offs. Since, apparently, I do not face the difficulties you are
>> dealing with, I would rather keep the power of what can be done.

>
> But what power do you lose by being able to import a resource with a using
> declaration, or to bring in -perhaps implicitly- an entire namespace with
> a
> using declaration? That really is what I am suggesting, more than
> anything.


I started to comment on this, and I realized that I was about to write
nonsense. So I realized that I do not understand your proposal. Could you
point me to a post where you have given more details about what these using
directives should do from a users point of view; obviously I missed some
postings of yours. Before I have a firm grasp of the proposed addition, I
cannot estimate what would have to be sacrificed (if anything) to make it
work -- after all this mechanism has to be integrated with the rest of C++.


> WRT exceptions, the fact of the matter is that placing certain
> requirements (restrictions) on their use improves their usability. If
> that behavior can be configured at compile time in such a way that the
> restrictions are not enforced, you have lot virtually nothing. The only
> issue becomes the requirement that you do specify the alternative
> behavior. Most compilers would probably provide a means of modifying the
> option through a commandline switch, so compiling code that doesn't use
> the feature would require no more than adding one command to your
> autoconf.ac, or environment variables.
>
>>> In the case of exceptions, I have solid experience that supports the
>>> opinions I hold. What I suggested simply works better as a default.
>>> And that is what I was referring to when I suggested you hadn't read
>>> everything
>>> I wrote. I explicitly said that the should be configurable through some
>>> mechanism similar to the one currently used to switch out handlers. I'm
>>> not sure how that might be accomplished, but I suspect someone in the
>>> C++ community is capable of finding a means.

>>
>> I will drop exceptions. Obviously talking about them just gives you an
>> opportunity not to address the issue of enforcing policies versus
>> providing mechanisms.

>
> Its your issue, not mine. The only reason I mentioned exceptions is that
> it is the only place where I am advocating placing restrictions on what
> you
> can do by default in C++. There are many restrictions placed on your use
> of code. That's what type checking is all about. If you are suggesting
> that I want to see changes in the way C++ is used in general, yes, that is
> correct.


Do you suggest changes to the standard? I am not concerned with any effort
of yours to change "the way C++ is used in general" (a cultural change),
because it would be up to me to follow the crowd or not. Changes to the
standard are what I am concerned about. If you do not talk about those,
then I apologize for the misunderstanding.


>>> Actually, to a large extent, it's the other way around. I believe the
>>> library management in C++ stinks. If there were a better system - which
>>> I believe is highly doable - I would have far less to complain about
>>> regarding the CPP. The CPP does go against certain principles of
>>> encapsulation that are generally regarded as good in computerscience. A
>>> better library system would go a long way toward addressing that as
>>> well. If people aren't #including 15 megs of source in every file, there
>>> is less (virtually no) opportunity for hidden variables entering the
>>> environment.

>>
>> Maybe, if cpp was even more powerful and more convenient, a superior
>> library management could be implemented using macros.

>
> I actually have a wishlist item in the KDevelop bug database that suggests
> attempting such a thing using #pragma and a strategy of filename, resource
> name consonance.
>


Sounds interesting and cool.


Best

Kai-Uwe Bux
 
Reply With Quote
 
Steven T. Hatton
Guest
Posts: n/a
 
      09-02-2004
Richard Herring wrote:

> In message <(E-Mail Removed)>, Steven T. Hatton


>>That would increase their usability as a substitute for
>>assertions.

>
> But you still wouldn't be able to pass _expressions_, which is what the
> use of macros allows. And, thanks to the # operator, you can pass
> something which is simultaneously an expression and a string.


I don't know what the reason for templates not taking char* constants is, so
I can't really comment on what you might be able to do with them if the
capability to pass them were there.

>>What happens when your macro is designed in such a way that expects a
>>particular kind of behavior on the part of your code, and the modified
>>macro doesn't understand that?

>
> What happens when any piece of code, macro or not, is designed under a
> misapprehension?


Regular code won't do things like

#define twice(x) ((x)+(x))
int n = 1;
int sum;
sum = twice(++n); //undefined

It looks modestly handy to be able to pass an expression and have it
'stringized'. I tried for a long time to do something like that in Java to
no avail. Then I found out how to leverage introspection to accomplish
what I wanted.
--
"[M]y dislike for the preprocessor is well known. Cpp is essential in C
programming, and still important in conventional C++ implementations, but
it is a hack, and so are most of the techniques that rely on it. ...I think
the time has come to be serious about macro-free C++ programming." - B. S.

 
Reply With Quote
 
Steven T. Hatton
Guest
Posts: n/a
 
      09-02-2004
Kai-Uwe Bux wrote:

> Steven T. Hatton wrote:
>


>> It's not contradictory, it is simply recursive.

>
> It is neither, the technical term for the way you used the word
> "information" in your argument is, I think, "equivocation".


What I mean by recursive is that I'm talking about applying the tools
created by information technology to the tool that create these tools.

>
>> I am applying the same
>> argument a mechanical engineer would use to explain his use of computers
>> to
>> do his job. The programs and tools a software engineer uses are the
>> programming language, the compiler, the IDE, the libraries, etc.

>
> I do not understand this analogy at all.


A mechanical engineer uses computers to explore his designs, to access
information, to organize his resources, etc. That's non-recursive in the
sense that a mechanical engineer is not creating IT tools. When I, as a
software engineer, apply information technology to my work it is recursive.
Self-referential, if you will.

> There are mitigating strategies that I incorporate in my coding styles. A
> problem is, of course, that I have to rely on libraries that might not
> follow my coding style. Nonetheless, I feel that a lot can be done without
> changing the language.


I agree. But I still find #inclusion redundant, primitive, inelegant,
potentially confusing, and lots of other bad things.

>> But what power do you lose by being able to import a resource with a
>> using declaration, or to bring in -perhaps implicitly- an entire
>> namespace with a
>> using declaration? That really is what I am suggesting, more than
>> anything.

>
> I started to comment on this, and I realized that I was about to write
> nonsense. So I realized that I do not understand your proposal. Could you
> point me to a post where you have given more details about what these
> using directives should do from a users point of view; obviously I missed
> some postings of yours. Before I have a firm grasp of the proposed
> addition, I cannot estimate what would have to be sacrificed (if anything)
> to make it work -- after all this mechanism has to be integrated with the
> rest of C++.


This is from a previous post. It isn't as concise as I would like, but I
need to work on clarifying in my own mind exactly what I'm suggesting
before I try to formaize it for others. All of what follows might be
replace by the requirement that 'Given a fully qualified identifier in a
source file, the implementation shall locate the declaration, (and
definition if needed), and make it available so that the source file can be
successfully compiled.' How it does this? I don't care!

//-----------------------------------------------------------------------
All of this is correct.**But*I'm*not*sure*that's*the*most*problematic*aspect
of the CPP.**Though*the*CPP*and*its*associated*proprocessor*directives*do
constitute a very simple language (nowhere near the power of sed or awk),
it obscures the concept of translation unit by supporting nested #includes.
When a person is trying to learn C++, the additional complexity can
obfuscate C++ mistakes.**It's*hard*to*determine*if*certain*errors*are*CPP
or C++ related.

IMO, the CPP (#include) is a workaround to compensate for C++'s failure to
specify a mapping between identifiers used within a translation unit and
the declarations and definitions they refer to.

As an example let's consider the source in the examples from
_Accelerated_C++:_Practical_Programming_by_Example _ by Andrew Koenig and
Barbara E. Moo:
*
http://acceleratedcpp.com/

// unix-source/chapter03/avg.cc
#include <iomanip>
#ifndef __GNUC__
#include <ios>
#endif
#include <iostream>
#include <string>

using std::cin;******************using*std::setprecision;
using std::cout;*****************using*std::string;
using std::endl;*****************using*std::streamsize;

I chose to use this as an example because it's done right (with the
exception that the code should have been in a namespace.) All identifiers
from the Standard Library are introduced into the translation unit through
using declarations.**Logically,*the*using*declaration*provides*enough
infomation to deterministically map between an identifier, and the
declaration it represents in the Standad Library.**The*#include*CPP
directives are necessary because ISO/IEC 14882 doesn't require the
implementation to resolve these mappings.**I*believe*-*and*have*suggested
on comp.std.c++ - that it should be the job of the implementation to
resolve these mappings.

Now a tricky thing that comes into play is the relationship between
declaration and definition.**I*have*to*admit*that*falls*into*the*category
of religious faith for me.**Under*most*circumstances,*it*simply*works,*when
it doesn't I play with the environment variables, and linker options until
something good happens.

I believe what is happening is this: When I compile a program with
declarations in the header files I've #included somewhere in the whole
mess, the compiler can do everything that doesn't require allocating memory
without knowing the definitions associated with the declarations.
(by compiler I mean the entire CPP, lexer, parser, compiler and linker
system) When it comes time to use the definition which is contained in a
source file, the source file has to be available to the compiler either
directly, or through access to an object file produced by compiling the
defining source file.

For example, if I try to compile a program with all declarations in header
files which are #included in appropriate places in the source, but neglect
to name one of the defining source files on the command line that initiates
the compilation, the program will "compile" but fail to link.**This*results
in a somewhat obscure message about an undefined reference to something
named in the source.**I*believe*that*providing*the*object*file*resulting
from compiling the defining source, rather than that defining source
itself, will solve this problem.

The counterpart to this in Java is accomplished using the following:

* import statement

* package name

* directory structure in identifier semantics

* classpath

* javap

* commandline switches to specify source locations



Mapping this to C++ seems to go as follows:

* import statement

This is pretty much the same as a combination of a using declaration and and
a #include.**A*Java*import*statement*looks*like*this:

import org.w3c.dom.Document

In C++ that translates into something like:

#include <org/w3c/dom/Document.hh>
using org::w3c::dom:ocument

* package name

This is roughly analogous to the C++ namespace, and is intended to support
the same concept of component that C++ namespaces are intended to support.
In Java there is a direct mapping between file names and package names.
For example if your source files are rooted at /java/source/ (c
\java\source) and you have a package named org.w3c.dom the name of the file
containing the source for org.w3c.dom.Document will
be /java/source/org/w3c/dom/Document.java. Using good organizational
practices, a programmer will have his compiled files placed in another,
congruent, directory structure, e.g., /java/classes/ is the root of the
class file hierarchy, and the class file produced by
comepiling /java/source/org/w3c/dom/Document.java will reside
in /java/classes/org/w3c/dom/Document.class.**This*is*analogous*to*placing
C++ library files in /usr/local/lib/org/w3c/dom
and /usr/local/include/org/w3c/dom.**

* directory structure in identifier semantics

In Java the location of the root of the class file hierarchy is communicated
to the java compiler, and JVM using the $CLASSPATH variable.**In*C++*(g++)
the same is accomplished using various variables such as $INCLUDE_PATH
(IIRC) $LIBRARY_PATH $LD_LIBRARY_PATH and -L -I -l switches on the
compiler.

Once Java know where the root of the class file hierarchy is, it can find
individual class files based on the fully qualified identifier name.**For
example:

import import org.w3c.dom.Document

means go find $CLASSPATH/org/w3c/dom/Document.class

The C++ Standard does not specify any mapping between file names and
identifiers.**In*particular,*it*does*not*specify*a*mapping*between
namespaces and directories.**Nor*does*in*specify*a*mapping*between*class
names and file names.

* classpath

As discussed above the $CLASSPATH is used to locate the roots of directory
hierarchies containing the compiled Java 'object' files.**To*the*compiler,
this functions similarly to the use of $LIBRARY_PATH for g++.**It*also
provides the service that the -I <path/to/include> serves in g++

* javap

The way the include path functionality of C++ is supported in Java is
through the use of the same mechanism that enables javap to provide the
interface for a given Java class.

For example:

Thu Aug 19 09:40:27:> javap org.w3c.dom.Document
Compiled from "Document.java"
interface org.w3c.dom.Document extends org.w3c.dom.Node{
****public*abstract*org.w3c.dom.DOMImplementation*getImplementation();
***...**
****public*abstract*org.w3c.dom.Attr*createAttribute(java.lang.String);
*******throws*org/w3c/dom/DOMException
....
}

What Javap tells me about a Java class is very similar to what I would want
a header file to tell me about a C++ class.

* commandline switches to specify source locations
This was tacked on for completeness.**Basically,*it*means*I*can*tell*javac
what classpath and source path to use when compiling.**If*a*class*isn't
defined in the source files provided, then it must be available in compiled
form in the class path.

One final feature of Java which makes life much easier is the use of .jar
files.**A*C++*analog*would*be*to*create*a*tar*file*containing*object*files
and header associated header files that compilers and linkers could use by
having them specified on the commandline or in an environment variable.


I know there are C++ programmers reading this and thinking it is blasphemous
to even compare Java to C++.**My*response*is*that*Java*was*built*using*C++
as a model.**The*mechanisms*described*above*are,*for*the*most*part,*simply
a means of accomplishing the same thing that the developers of Java had
been doing by hand with C and C++ for years.**There*is*nothing*internal*to
the Java syntax other than the mapping between identifier names and file
names that this mechanism relies on.**This*system*works*well.*The world will
be a better place when there is such a thing as a C++ .car file analogous
to a Java .jar file.**Grant*that*these*will*not*be*binary compatable from
platfor to platform, but in many ways that doesn't matter.
//-----------------------------------------------------------------------
>
>> Its your issue, not mine. The only reason I mentioned exceptions is that
>> it is the only place where I am advocating placing restrictions on what
>> you
>> can do by default in C++. There are many restrictions placed on your use
>> of code. That's what type checking is all about. If you are suggesting
>> that I want to see changes in the way C++ is used in general, yes, that
>> is correct.

>
> Do you suggest changes to the standard? I am not concerned with any effort
> of yours to change "the way C++ is used in general" (a cultural change),
> because it would be up to me to follow the crowd or not. Changes to the
> standard are what I am concerned about. If you do not talk about those,
> then I apologize for the misunderstanding.


Yes, I am suggesting changes to the standard be considered. I've already
suggested the exception mechanism be changed.


>>> Maybe, if cpp was even more powerful and more convenient, a superior
>>> library management could be implemented using macros.

>>
>> I actually have a wishlist item in the KDevelop bug database that
>> suggests attempting such a thing using #pragma and a strategy of
>> filename, resource name consonance.
>>

>
> Sounds interesting and cool.


I recently found there is more infrastructure in the code base for KDevelop
which might facilitate this than I previously thought. This in particular:
http://www.kdevelop.org/HEAD/doc/api/html/classAST.html

I have the sense that Roberto Raggi's AST might provide a good foundation
for an entire C++ compiler. In comparison to what I saw in the gcc source
code, Roberto's seems a lot cleaner.
--
"[M]y dislike for the preprocessor is well known. Cpp is essential in C
programming, and still important in conventional C++ implementations, but
it is a hack, and so are most of the techniques that rely on it. ...I think
the time has come to be serious about macro-free C++ programming." - B. S.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Struts - bean:write or html:text - not getting bean value - Please help jill Java 5 12-15-2005 03:03 PM
Differnce between Java Bean and Enterprise Java Bean Markku Salminen Java 3 01-21-2004 09:25 AM
Mr. Bean Complete Bean NOT complete!! Waterperson77 DVD Video 5 12-10-2003 05:22 PM
can a session bean return a local entity bean object? David Thielen Java 2 09-12-2003 07:45 AM
To bean or not to bean... Benjamin Stewart Java 0 06-30-2003 12:34 AM



Advertisments