What makes a good C/C++ programmer?

G

Gianni Mariani

Manuel said:
There are a couple of things wrong with that code, first is off topic
since you were testing the candidate knowledge of C++ not his
understanding of threading and your pet library.

But you need to know what C++ does with a virtual method and class
construction. Many C++ programmers (sadly) don't. I'm not sure I agree
that it's OT.

Second auto-starting
the thread in A's constructor prevents further derivation as the thread
will start running with a not fully constructed object. Thread start up
must be always done after construction, that is why your base clase
at::Task (correctly) provides a Start() method rather than spawning them
in the constructor.
Great.


But as I said, for testing C++ knowledge is off topic. And as threading
question, pretty basic.

I agree. It's pretty basic.

BTW - there is another problem.
 
A

Alf P. Steinbach

* Manuel Petit:
* Gianni Mariani said:
b) Explain what is wrong with this code:

[snip]
Second auto-starting
the thread in A's constructor prevents further derivation as the thread
will start running with a not fully constructed object. Thread start up
must be always done after construction

For this design, yes. Ideally, in a better design, the most derived
constructor is where the thread should get started, because thread start
is a once-only action ~100% coupled to object construction. See below.

that is why your base clase
at::Task (correctly) provides a Start() method rather than spawning them
in the constructor.

Providing a function to be called once _after C++ construction_ is,
simply put, blotched design from a type-safety point of view.

In most situations where that is seemingly called for, FAQ 23.4, at
<url:
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.4>,
provides sound alternatives (might I immodestly mention that that FAQ
item resulted from an initiative by me to get that info into the FAQ,
just to make clear to Gianni that I understand those issues?).

This is, however, not a situation where 23.4 applies.

Instead, this is a situation where the client class code can not
completely specify the full C++ object construction, seemingly requiring
a "post-constructor-execution" language feature.

And one solution is then to provide a template class that typewise must
be used to create a _concrete class_ from any client code task class,
and that ideally does not, typewise, allow further derivation.

Example code, where I've omitted the "don't allow further derivation"
part (can be implemented by adding a virtual base class, overhead):


#include <iostream>
#include <ostream>

class AtTask
{
template< typename Task_ > friend class AtConcrete_;

private:
struct PrivateType {};
void virtual ensureAbstractClass( PrivateType& ) const = 0;

void start()
{
std::cout << "Starting..." << std::endl;
}
};

template< typename Task_ >
class AtConcrete_: public Task_
{
private:
void virtual ensureAbstractClass( AtTask::privateType& ) const {};
public:
AtConcrete_() { AtTask::start(); }
};

class A: public AtTask
{
};

int main()
{
AtConcrete_<A> obj;
}
 
G

Gianni Mariani

#include said:
#include <ostream>

class AtTask
{
template< typename Task_ > friend class AtConcrete_;

private:
struct PrivateType {};
void virtual ensureAbstractClass( PrivateType& ) const = 0;

void start()
{
std::cout << "Starting..." << std::endl;
}

public:
void wait()
{
}
};

template< typename Task_ >
class AtConcrete_: public Task_
{
private:
void virtual ensureAbstractClass( AtTask::privateType& ) const {};
public:
AtConcrete_() { AtTask::start(); }

~AtConcrete_() { AtTask::wait(); }

};

class A: public AtTask
{
};

int main()
{
AtConcrete_<A> obj;
}

I like the idea but.

This would make it hard to multiply inherit Task.

class ATask : public Task_
{
virtual void AWork() = 0;
};

class BTask : public Task_
{
virtual void BWork() = 0;
};

class DoubleTask : public ATask, public BTask
{
virtual void AWork() { .... doing A thing }
virtual void BWork() { .... doing B thing }
};

No way AtConcrete_ would work here.

Thread-pool objects have this pre-destructor behaviour as well. I have
not yet published the thread-pool implementation but there is a way to
use this technique of yours since all thread pool "events" in a class
are "registered" in a virtual base class.

BTW - I didn't get much feedback on the idea of adding a language
feature to do this automagically on comp.std.c++. I still would like to
see that happen.
 
A

Alf P. Steinbach

* Gianni Mariani:
public:
void wait()
{
}


~AtConcrete_() { AtTask::wait(); }



I like the idea but.

This would make it hard to multiply inherit Task.

class ATask : public Task_
{
virtual void AWork() = 0;
};

class BTask : public Task_
{
virtual void BWork() = 0;
};

class DoubleTask : public ATask, public BTask
{
virtual void AWork() { .... doing A thing }
virtual void BWork() { .... doing B thing }
};

No way AtConcrete_ would work here.

As I remarked earlier (then wrt. what I am willing to state) blanket
statements have a nasty habit of turning out false.

All you have to do, if you Really Want this functionality, is to
register a task to be started in the AtTask constructor (and of course
de-register that task, if still registered, in the destructor). If on
the other hand you don't want that functionality then the above
Concrete_ template class would give a compile time error for multiple
inheritance of AtTask. So the choice is free: one can design a safe
interface for one or the other, or possibly make support for this or
that a policy, and that's the choice to make.

There might be more and better ways (there is a possible dynamic
allocation and synchronization overhead in registering), but the above
was my first millisecond-response idea. Uh, wait. The client can
possibly pass a type-list as template parameter to AtConcrete_... And
so on. Never say never! :) I leave the details to you. Btw., yes, I
would be interested in your solution to the bitcounting template.
 
G

Gianni Mariani

Alf said:
* Gianni Mariani:



As I remarked earlier (then wrt. what I am willing to state) blanket
statements have a nasty habit of turning out false.

All you have to do, if you Really Want this functionality, is to
register a task to be started in the AtTask constructor (and of course
de-register that task, if still registered, in the destructor). If on
the other hand you don't want that functionality then the above
Concrete_ template class would give a compile time error for multiple
inheritance of AtTask. So the choice is free: one can design a safe
interface for one or the other, or possibly make support for this or
that a policy, and that's the choice to make.

There might be more and better ways (there is a possible dynamic
allocation and synchronization overhead in registering), but the above
was my first millisecond-response idea. Uh, wait. The client can
possibly pass a type-list as template parameter to AtConcrete_... And
so on. Never say never! :) I leave the details to you. Btw., yes, I
would be interested in your solution to the bitcounting template.

I implemented somthing similar to this for thread pool "events". I'm
trying to figure out the trade-offs in making threads (Task) more
complex. You can't save a lazy programmer all the time.
 
M

Manuel Petit

Gianni said:
I agree. It's pretty basic.

BTW - there is another problem.

Yeah, yeah, yeah... destruction, etc... in the same category as the
construction problem. Still off-topic if what you wanted is to test a
candidate C++ knowledge.


manuel,
 
G

Gianni Mariani

Manuel said:
Yeah, yeah, yeah... destruction, etc... in the same category as the
construction problem. Still off-topic if what you wanted is to test a
candidate C++ knowledge.

Then the whole thread is off-topic.... Even if it isn't OT, it's lame
and you and I are wasting our time.
 
K

Keith Thompson

Joseph Turian said:
ERT,


Shouldn't we first discuss what makes someone a good human being,
before tackling more specific and complicated questions?

Yes, absolutely, because the question of what makes someone a good
human being is really what comp.lang.c++ and comp.lang.c are all
about. It's a pity that both newsgroups have such misleading names.
 
K

Keith Thompson

Christian Bau said:
You make the assumption that one starts as a rookie and progresses to be
an expert. Some people don't.

Some people have 20 years of experience. Others have 1 year of
experience 20 times.
 
R

Rufus V. Smith

Mike Wahler said:
A good programmer is one who does not describe himself
as "[insert name of language or tool here] programmer",
but one who knows how to solve problems effectively, using
available tools. One who knows how to learn to use those
tools which are new to him. One who knows to look for
existing solutions (or components of them) before attempting
to recreate them yet again.

Perfect, Mike! I will use that as a guideline when I'm tuning
my resume in my next job search!

It may be that many people hiring won't fully "get it" when
stated that way.

But the ones who "get it" are the ones I'd prefer to work for.

(Incidentally, the folks at my current job are ones who do "get it")

Rufus

This reminds me of the description of an engineer
(paraphrased)

An engineer is a person
who creates what he/she wants
from what he/she has.

or (I can't help myself)

God grant me
1) The pragmatism to acquire the tools that are available
2) The ability to create the tools that are not
3) The wisdom to know the difference
 
C

Chris Croughton

God grant me
1) The pragmatism to acquire the tools that are available
2) The ability to create the tools that are not
3) The wisdom to know the difference

Oh, that one is eminently quotable!

Chris C
 
J

Jerry Coffin

Mike Wahler wrote:

[ ... ]
A good programmer is one who does not describe himself
as "[insert name of language or tool here] programmer",
but one who knows how to solve problems effectively, using
available tools.

While I sympathize with this sentiment, I think it oversimplifies the
real situation a bit. There are lots of problems and lots of tools.
Different tools have differing levels of applicability to those
problems. While it's certainly true that a good programmer will avoid
using a tool that's particularly ill-suited to a given problem, it
isn't necessarily true that he'll always choose fairly/equally among
the available tools.

First of all, spending weeks learning a new tool because it _might_ be
5% better for some small/rare job may make little sense unless he's
reasonably certain he'll be able to apply that tool to a lot of jobs.

Second, he should look not only at the task at hand, but what it may
grow into -- it can often make a great deal of sense to start with a
tool that borders on overkill, rather than one that's highly effective
as it stands right now but won't scale well over time.

Finally, a programmer may have enough greater proficiency with one tool
than another that it's perfectly reasonable for him to describe himself
as a user of that tool, even if he's perfectly open to using others
when they work well.

As an obvious example I'm pretty sure I've described myself as "a C++
programmer". I've certainly written a lot of code in a lot of other
languages, and have no problem with using other tools when they appear
well-suited to the task at hand. Nonetheless, my proficiency with C++
is such that my tendency is to use it unless some other tool appears
_substantially_ better for the task at hand. At least in my case, this
seems to be somewhat justified -- I'd guess that around half the time I
start trying to do something in some other language, I end up doign it
in C++ before I'm done.
 
C

Chris Croughton

First of all, spending weeks learning a new tool because it _might_ be
5% better for some small/rare job may make little sense unless he's
reasonably certain he'll be able to apply that tool to a lot of jobs.

And apply it well, not just as a "Swiss Army Knife" (Leatherman?) used
because it's the one which does everything. And in many cases one which
other people can pick up and use/modify/fix (Perl, for instance, it
fairly easy to write but every Perl writer I know is familiar with a
different subset of the language, often making it difficuly for a
maintainer to pick up).
Second, he should look not only at the task at hand, but what it may
grow into -- it can often make a great deal of sense to start with a
tool that borders on overkill, rather than one that's highly effective
as it stands right now but won't scale well over time.

Heh. It was said of me when I was at university that if I wanted to
know the square root of 2 I would start by writing a program that
calculated the roots of nth order complex polynomials. It wasn't quite
true, I probably wouldn't have bothered with complex coefficients (but
would probably have left 'hooks' so that they could be added if
wanted)...
Finally, a programmer may have enough greater proficiency with one tool
than another that it's perfectly reasonable for him to describe himself
as a user of that tool, even if he's perfectly open to using others
when they work well.

Yup. I use awk, sed and grep by preference for shell programming, but I
can also use other languages where it makes sense (and other shells on
other OSs).
As an obvious example I'm pretty sure I've described myself as "a C++
programmer". I've certainly written a lot of code in a lot of other
languages, and have no problem with using other tools when they appear
well-suited to the task at hand. Nonetheless, my proficiency with C++
is such that my tendency is to use it unless some other tool appears
_substantially_ better for the task at hand. At least in my case, this
seems to be somewhat justified -- I'd guess that around half the time I
start trying to do something in some other language, I end up doign it
in C++ before I'm done.

As far as most job agencies I've used are concerned (I was a contractor
for 12+ years, and may be again) they like descriptions like "C
programmer" or for that matter "C/C++ programmer" (or "C++/C" if the C++
skills are greater), they can see at a glance that the person has C and
C++ experience (or C/Fortran, Ada/Pascal/Cobol or other combinations).
They will look at the detailed experience description later, but they
make the initial cut on the description. Yes, they are often
non-technical and will tend to assume that knowledge of C implies
knowledge of C++ (and "What's the difference between C and Fortran?"),
but then they also treat all databases as equivalent, it has nothing to
do with the notation (many non-computer-literate people will also assume
that "you know computers, can you fix my Windoze machine?" without
realising that there is any difference between a PC with WinXP and a VAX
running OpenVMS and that experience with one does not imply familiarity
wth the other).

Chris C
 

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

Forum statistics

Threads
474,200
Messages
2,571,046
Members
47,646
Latest member
xayaci5906

Latest Threads

Top