Dennis Ritchie -- An Appreciation

I

Ian Collins

Nonsense. They are quite preferable to littering 'if (xx != 0)' all
over the place in a great number of situations. Any time it is quite
common for an object to be non-existent and the behavior is always the
same, a null object encapsulates the situation quite nicely. Client
code doesn't need to care, nor should it.

Very true, I was thinking "null references"!
 
I

Ian Collins

But not everyone uses the iterator system consistently.

But the C++ standard library does and that's what matters.
You need two requirements. You need the iterators to be set up
correctly. But you also need functions like add and divide to be
defined correctly. The mean of a list of integers is not usually an
integer.

The use of iterators for the C++ standard library algorithms is a sound
and pragmatic design choice. It is sound because anything that behaves
like an iterator can be used, so for example we can use std::sort on an
array as well as a C++ container. It was pragmatic because early
compilers did not support template parameters that are templates, so a
container couldn't have been used as a template parameter
 
N

nroberts

In the general case you can't make start point to const data (and your
C++ version doesn't use const).

The C++ version can be const or non-const. It doesn't specify and
lets the type resolution establish and check const correctness based
on the template parameters.

This is actually one thing that really, really bothers me in C. In
order to have a for_each that works on const or non-const data you
either need to write it twice or use non-const. The usual approach in
C seems to be to use non-const even when it's not necessary. This
means of course that you've got a bunch of interfaces that claim to
use non-const when they really don't change anything. For example, it
is quite common to see:

void fun(char*);
char * str = "hello";
fun(str);

If we are to only make those assumptions that the function's
declaration can establish then this use is illegal and dangerous. But
in C you can't actually be sure about this and it is not uncommon to
see such use. Just the other day in fact I pointed out to someone
unit testing C code that it was crashing because the function actually
DID modify the parameters and he was passing it static strings
probably stored in r/o memory.

Of course, then you get these same programmers coming into C++ who are
not in the habit of writing const-correct code, don't understand it,
and find it annoying because it's always complaining. So instead of
figuring it out they write interfaces that lack const correctness as
they did in C and you get the same big f'n mess or worse.
 
I

Ian Collins

Most functions operate on lists. C provides one easy way to set up a
list, which is as an array. The consequence is that, in C programs,
lists are usually arrays, unless there's a pressing performance need
for another structure. The result is that, _in practice_ functions
tend to be inter-operable. The interfaces are kept clean and simple.

Which is why C++ algorithms use iterators, they are interoperable and
the interfaces are kept clean, simple and consistent. You can use them
with any container, including arrays!
You can even, very frequently, call a C function from another
language.

That's because C is the common denominator on most platforms.

Your sig is missing the trailing space by the way.
 
N

nroberts

On Oct 30, 3:33=A0pm, Malcolm McLean <[email protected]>
wrote: [snip]
That's not to say you never use other structures, there's a case for
representing the bonds between atoms as a graph, for instance, you
might want to do that for some applications.
again wouldn't arrays of structs be more natural than strcuts of
arrays?

As a side note, there is a subtle bias in C in favor of arrays of
structs rather than structs of arrays.  If we are using indices rather
pointers it doesn't affect the code much.  Thus

    a.x  /* array of structs vs */
    a.x  /* struct of arrays    */

are much the same.  However if we use pointers the choice matters.
Frex suppose we are walking through x to find a particular record.
With an array of structs we have something like:

    for (ap=a;ap<ap_end;ap++) {
       if (f(ap->x)) calc(ap);
    }

Writing the equivalent code using a struct of arrays is not quite so
simple. :)


I think both of you will have to forgive my ignorance here because
I've never seen arrays and structs as interchangeable constructs. I
mean, I realize you CAN implement a sort of struct in a byte buffer,
but if someone was doing this on a regular basis I'd have to wonder if
they were coding while under the influence of a grand maul seizure or
something.

So, how and when could you convert a "struct of arrays" into an "array
of structs"? For example, lets say I have a struct of arrays:

struct has_arrays
{
char fname[128];
char lname[128];
char mi;
};

How does C bias me toward converting that into an array of structs?
What would such a construct look like?
 
I

ImpalerCore

It doesn't really solve the problem. One of the most dangerous
features of C is the ability to typedef a basic type to something
like, say DWORD. Then you find yourself rewriting perfectly good code,
just because someone decided to put DWORDs where they really meant
"int", and the code no longer runs under the particular operating
system where DWORDs are used.

Do you have the same problem with int32_t? The only difference is
that one is *standardized* and the other 'DWORD' is not. The
underlying concept is the same; you want a double-word on
architectures that support 16-bit integers and those that support 32-
bit integers.

The benefit of typedefs is that it allows a module writer to define
types with stricter semantics. In this case, 'DWORD' has stricter
semantics because it is required to be 32-bits; an 'int' type does
not.

One can also use typedefs to define a common name to a type with
specific semantics. The example I commonly use is using an typedef of
'int' to define a type to represent a month.

typedef int greg_month;

Even though 'int' is the base type, the added semantics placed on
'greg_month' is that it is only allowed to store values from 1 to 12,
and perhaps -1 to represent an error state. Writing a function API
using these typedefs increases developer comprehension.

void create_report( struct my_report* report,
struct my_data* data,
greg_month start,
greg_month end );

One could certainly use 'int' in the start and end months, but
'greg_month' is a better visualization of its constraints than 'int'.
One sees 'greg_month' and knows that its implied range is from 1 to
12; the same cannot be said for using 'int'. Unfortunately C does not
provide automatic enforcement of those semantics, and the module
writer must take pains to code constraints to ensure that the values
passed into 'start' and 'end' match the desired semantics for the type
'greg_month'.

What one gains in developer comprehension becomes a flaw at the
integration stage. If one wants to use different libraries by
different people with different representations of the same thing, it
quickly becomes difficult to reconcile these differences. It is a
fundamental flaw of typedefs, as the plethora of boolean type styles
before standardization in C99 demonstrates.

Even so, I still believe the use of typedef to be a net positive even
though integration is a serious problem.
But it alleviates it, because it's easy to write a function that
operates on lists (a list is an ordered collection, usually of like
items) as taking an array and a count. It's hard to do anything
fancier, like wrapping the list into a structure with a "length"
member, creating a linked list, or semi-hardcoding the length of the
array with a preprocessor define. So the plugs might not fit the
sockets, but at least all the sockets are set up in a similar way.

Once you start allowing containers, that simplicity goes.

I consider simplicity and power at two ends of a spectrum. If one
must start from scratch, there is a lot to be said to start with
simplicity. But as the limitations of simplicity become apparent,
people will desire constructs with more power. And if power comes in
the form in a library that is standardized (STL), it is reasonable to
believe that one can use that standard to justify using a complex
library, just as one should prefer to use a C standard function.

That power comes with a cost, which is increased sophistication and
comprehension required for all developers using the library. I find
that this effect results in the increased stratification in the
expertise of C++ over C developers. Are you in the strata that can
properly use the STL, or template meta-programming, or designing class
hierarchies, or exception handling, and the list of features keep
growing.

I view C and C++ not as superior or inferior to one another, but as
points on this spectrum with their own advantages and disadvantages.

simplicity<----------------------->power

C++ is stretching their position to the right, while C tends to enjoy
its position where its at.

Best regards,
John D.
 
J

James Kuyper

On Mon, 31 Oct 2011 03:20:15 -0700 (PDT), Nick Keighley
again wouldn't arrays of structs be more natural than strcuts of
arrays?

As a side note, there is a subtle bias in C in favor of arrays of
structs rather than structs of arrays. �If we are using indices rather
pointers it doesn't affect the code much. �Thus

� � a.x �/* array of structs vs */
� � a.x �/* struct of arrays � �*/

are much the same. �However if we use pointers the choice matters.
Frex suppose we are walking through x to find a particular record.
With an array of structs we have something like:

� � for (ap=a;ap<ap_end;ap++) {
� � � �if (f(ap->x)) calc(ap);
� � }

Writing the equivalent code using a struct of arrays is not quite so
simple. :)


I think both of you will have to forgive my ignorance here because
I've never seen arrays and structs as interchangeable constructs. I
mean, I realize you CAN implement a sort of struct in a byte buffer,
but if someone was doing this on a regular basis I'd have to wonder if
they were coding while under the influence of a grand maul seizure or
something.

So, how and when could you convert a "struct of arrays" into an "array
of structs"? For example, lets say I have a struct of arrays:

struct has_arrays
{
char fname[128];
char lname[128];
char mi;
};

How does C bias me toward converting that into an array of structs?
What would such a construct look like?


Well, in general it only makes sense if every member of the struct is an
array, and all of the arrays have the same length, and that length
corresponds to the count of something. Arrays which are simply places to
store strings don't count as arrays for this purpose. An example a
struct of arrays where it might actually make sense to convert it into
that would make more sense:

struct asteroids {
char name[MAX_ASTEROIDS][NAME_LENGTH];
double position[MAX_ASTEROIDS][3];
double velocity[MAX_ASTEROIDS][3];
double mass[MAX_ASTEROIDS];
int num_asteroids;
} asteroid_list;

The corresponding array of structs would look like:

struct asteroid_list {
int num_asteroids;
struct asteroid{
char name[NAME_LENGTH];
double position[3];
double velocity[3];
double mass;
} list[];
} asteroids;
 
B

Ben Bacarisse

The C++ version can be const or non-const. It doesn't specify and
lets the type resolution establish and check const correctness based
on the template parameters.

I did not say that very well. I meant that nothing in the C++ forces
the iterators to be const ones so, this should have been reflected in
the C code if it is going to put up as a comparison.

<snip>
 
B

Ben Bacarisse

Malcolm McLean said:
The point is, you're unlikely to make this particular mistake in C.

That seems to be quite a different point to the one I was commenting on.

Generally, you don't have this sort of problem. Functions written in C
can be made reusable with a minimum of effort, and can be embedded in
other programs with a minimum of fuss. That's much less true of
functions that use elaborate container systems. They tend to be
difficult to integrate.

And if this third point had been the one you'd originally made I would
not have disagreed. Low-level functions written in lower-level
languages are almost always easier to integrate in other systems. This
has provided a new role for C in some areas -- as the natural language
for easily integrated, portable, libraries.
 
N

nroberts

33=3DA0pm, Malcolm McLean <[email protected]>
wrote:
[snip]
That's not to say you never use other structures, there's a case for
representing the bonds between atoms as a graph, for instance, you
might want to do that for some applications.
again wouldn't arrays of structs be more natural than strcuts of
arrays?
As a side note, there is a subtle bias in C in favor of arrays of
structs rather than structs of arrays. =A0If we are using indices rather
pointers it doesn't affect the code much. =A0Thus
=A0 =A0 a.x =A0/* array of structs vs */
=A0 =A0 a.x =A0/* struct of arrays =A0 =A0*/
are much the same. =A0However if we use pointers the choice matters.
Frex suppose we are walking through x to find a particular record.
With an array of structs we have something like:
=A0 =A0 for (ap=3Da;ap<ap_end;ap++) {
=A0 =A0 =A0 =A0if (f(ap->x)) calc(ap);
=A0 =A0 }
Writing the equivalent code using a struct of arrays is not quite so
simple. :)

I think both of you will have to forgive my ignorance here because
I've never seen arrays and structs as interchangeable constructs.  I
mean, I realize you CAN implement a sort of struct in a byte buffer,
but if someone was doing this on a regular basis I'd have to wonder if
they were coding while under the influence of a grand maul seizure or
something.
So, how and when could you convert a "struct of arrays" into an "array
of structs"?  For example, lets say I have a struct of arrays:
struct has_arrays
{
 char fname[128];
 char lname[128];
 char mi;
};
How does C bias me toward converting that into an array of structs?
What would such a construct look like?

Oh dear.  Nobody is saying that arrays and structs are interchangable.
The issue at hand is the choice between using an array of structs or
an "equivalent" struct of arrays.  Let's take your example.  

    struct name_struct {
        char fname[128];
        char lname[128];
        char mi;
    };

Is just a struct, even though some fields are arrays.  The following
statement creates an array of structs.  

    struct name names[100];

is an array of structs.  

Now instead of using an array of structs we could use an struct
holding arrays.  It would look like this:

    struct name_fields {
        char fname[100][128];
        char lname[100][128];
        char mi[100];
    } names;

The array of structs and the struct of arrays have the same data, but
the data ordering is different.

Is this clear?


OK, what is C specific about preferring one over the other? Why is
*C* biased to using arrays of structs rather than these struct of
arrays abominations over and above simple, basic, common sense?
 
M

Malcolm McLean

That seems to be quite a different point to the one I was commenting on.
Not really.

Probably most C programmers, at some time, have played with

struct string
{
int len;
char *str;
};

However they soon realise that all they're achieving is making it hard
to integrate string functions. You can make a mess in C if you want,
but you have to go out of your way to code it. So most people don't
bother. They drop the struct string nonsense and just pass about char
*s, which is the standard way. (You can argue whether the standard
plugs and sockets are well designed or not, that's a slightly
different matter).

In C++, it's much easier to do the equivalent. All you need to do is
to use std::string and char *s in the same program, and you've soon
got a mess.

Now of course, by itself, just having two string types which can be
interconverted easily enough is not going to bring down the program.
It's the accumulation of problems like that which eventually makes
code unmaintainable.
 
M

Markus Wichmann

Not having scope tied destructors hurts. There are a whole lot of
methods for simplifying code through tying to scope that can't be done
without them. The gcc compiler has an extension though that allows
this in C. Of course it is quite obviously possible to go without
these things in C, especially since you're probably not using
exceptions (setjmp/longjmp is available but pretty rarely used), it
just makes things easier and more straight forward in some people's
opinions.

Some people like being able to create a variable that is guaranteed to
have a function called on it so you can fill that function with
important things like closing file handles, releasing resources,
etc... That way you don't have to remember to do so for every error
condition and in the right order, and only those parts you've
initiated, etc... Other people find the hiding of these details in an
interface like that makes code harder to understand and prefer the
verbosity of having to clean up properly for different conditions
within the block that deals with those conditions. Neither
perspective is wrong.


All of these features are important and have their uses. They can all
be used badly. Poor design is poor design in C, C++, or any other
language.

True, but in C++ you have more possibilities for bad design.
Consider this function:

void function_that_outputs_blob(blob* b);

If that function does something other than outputting a blob, whatever
that means, then people reading code that use it are not going to know
what that code does. This is exactly the same for using standard
function names like operator++ to mean something other than the
standard use or having conversion operators for types to which
conversion makes no sense.

That is right, but at the very least, people reading the code are able
to detect a call to a function, unlike the line I posted.
These later cases can all occur in C if the line is changed to:

*x += (*y)++;

That's true too, but then you actually know that x and y must be
pointers, which isn't obvious from the C++ line.
Only if you're an idiot. I'm sorry, but it's simply true. If you
can't look at declarations of your x and y variables to see what type
they are then you are quite fucked in whatever language you choose to
be programming in.

You actually did notice that I also included "operator++(typeof y)" in
the list of stuff that might be defined somewhere? Well, yeah, that's
exactly what I meant. It could be defined _fucking_anywhere_. Needn't be
anywhere near the declaration or definition of typeof y.
Which is a pretty excellent example of great use of templates.

No templates were used in that implementation. It was a class that went
something like:

class TSPrintf {
std::string format;
unsigned int pos;
public:
TSPrintf(const std::string&);
TSPrintf& operator()(unsigned int);
TSPrintf& operator()(char);
TSPrintf& operator()(const char*);
TSPrintf& operator()(you_name_it);
};

The call would then go like

TSPrintf("%u errors in %u lines\n")(errors)(lines);

And if you tried funny stuff like

TSPrintf("%s errors\n")(errors);

with errors being an unsigned int variable, the compiler would call
TSPrintf::eek:perator()(unsigned int), which would detect that it has been
called with a format specifier of "%s" and thus would throw an exception.
If that's the only example that you've seen though then you're
obviously not looking at a lot of C++.

I looked at the STL at another point and lost myself in the code
somewhere. It's a bit astonishing what kind of stuff you actually need
to do before you can shift strings into streams.
If you want to write generic code that operates at the static type
level then you really need templates. Macros can almost get you there
but at a very high cost.

I guess this is where we actually deviate: In C my code isn't meant to
be general. There is a sane level of generalization in the standard
library (what with qsort() and bsearch()), but the code I write is meant
to solve a specific problem.

C++ however advocates a bottom-up design which often leads to more code
being written than actually used. Also, the code is more general,
because you think about needing a list, before you think about needing a
list of integers. (OK, bad example, as there's already std::list available)
The one thing that can be said against templates is that they can be
hard to learn. The syntax isn't exactly optimal and the requirements
of when, where, and how to use the typename and template keywords can
be confusing. For example:

template < typename T >
struct example
{
typedef typename T::some_typedef local_typedef;

template < typename U > static void fun();
};

example<int>::template fun<double>();

It's kind of confusing and ugly.

Yeah. And local typedefs don't always serve to really abbreviate things
as they were meant to. I once read a template that went along the lines of:

template <typename T> class X {
typedef T my_local_type;
}

I don't see why one would "abbreviate" T with "my_local_type", but hey,
that's how they roll. So you cannot figure out what a class function
actually returns even after you read the declaration.
Bloated? Depends on how much
depends on the templates' parameters. If none of it does, then yeah
it's going to be unnecessarily bloated. If most of it does then no,
it's going to be about as "bloated" as it has to be.

Of course, the generic programming paradigm, which is what templates
are pretty much about, is often foreign to someone stuck in the C
world and unwilling to expand their knowledge. This is no different
from any other tool though. If you don't want to learn these things,
that's fine, but your willing ignorance isn't a good argument.

Well, I guess you're right about that. I still think it is good design
to actually write only the stuff you need. I once wrote a matrix class.
I only needed it to contain integers, so I wrote it like this. I don't
see why I should have written a template class. Just so that at some
later point I could reuse it? But then again, this class was half a
day's work, so there's no real point. Plus I actually only needed the
Gauss-Jordan algorithm.

CYA,
Markus
 
I

Ian Collins

Well, I guess you're right about that. I still think it is good design
to actually write only the stuff you need. I once wrote a matrix class.
I only needed it to contain integers, so I wrote it like this. I don't
see why I should have written a template class. Just so that at some
later point I could reuse it? But then again, this class was half a
day's work, so there's no real point. Plus I actually only needed the
Gauss-Jordan algorithm.

That's a fair call. If sometime later you need to use the class for
some other type, that's the time to make it generic.
 
N

Nick Keighley

Nobody said anything about Hungarian notation.  That's a straw man.

ok, a bit quick on the Hungarian. Type information in variable names
is IMO, a bad idea.
OK, well I'm looking at that function and I have no idea what you are
intending with it.  I really doubt that knowing the definitions of
MyType would help me either.

Yes, but in general MyType would have a meaningful name.

Bearing adjustBearing (Bearing& b, Angle& adjustment)
{
return b + adjustment++;
}

ok, one of them has some semantics embedded in the name. But I think
arithmatic types are bad examples of what I'm talking about.
int q;

Tell me, what is the intended use of q?

it's an integer. If you meant to limit it some way you should have
chosen a more semantically meaningful type. Though addmittedly Ada is
better at that than C++ or C.
void (*f)(int,int,double);

pick a better name than f? Though I agree it would be hard in this
case.
Tell me, what does f do?
sin(double);

You should be able to tell me since the types tell you enough, right?

With things like names or counts or sizes you probably needed sematic
information the type. With higher level (domain level) types it
becomes less necessary.

Success send (Stream&, const Message&);
void basestation_reset (Basestation&);
 
M

Malcolm McLean

On 30.10.2011 18:43, nroberts wrote:

C++ however advocates a bottom-up design which often leads to more code
being written than actually used. Also, the code is more general,
because you think about needing a list, before you think about needing a
list of integers. (OK, bad example, as there's already std::list available)
I find a lot of my C functions are general. That's partly a reflection
of the type of code I write, at the moment, mainly code to explore DNA
sequence data. So I have a lot of functions for pattern matching and
doing statistics and loading files in various formats, which I then
plug together with throw-away code.
 
N

Nick Keighley

On Oct 31, 1:07=A0pm, (e-mail address removed) (Richard Harter) wrote:
33=3DA0pm, Malcolm McLean <[email protected]>
wrote:
[snip]
That's not to say you never use other structures, there's a case for
representing the bonds between atoms as a graph, for instance, you
might want to do that for some applications.
again wouldn't arrays of structs be more natural than strcuts of
arrays?
As a side note, there is a subtle bias in C in favor of arrays of
structs rather than structs of arrays. =A0If we are using indices rather
pointers it doesn't affect the code much. =A0Thus
=A0 =A0 a.x =A0/* array of structs vs */
=A0 =A0 a.x =A0/* struct of arrays =A0 =A0*/
are much the same. =A0However if we use pointers the choice matters.
Frex suppose we are walking through x to find a particular record.
With an array of structs we have something like:
=A0 =A0 for (ap=3Da;ap<ap_end;ap++) {
=A0 =A0 =A0 =A0if (f(ap->x)) calc(ap);
=A0 =A0 }
Writing the equivalent code using a struct of arrays is not quite so
simple. :)
I think both of you will have to forgive my ignorance here because
I've never seen arrays and structs as interchangeable constructs.  I
mean, I realize you CAN implement a sort of struct in a byte buffer,
but if someone was doing this on a regular basis I'd have to wonder if
they were coding while under the influence of a grand maul seizure or
something.
So, how and when could you convert a "struct of arrays" into an "array
of structs"?  For example, lets say I have a struct of arrays:
struct has_arrays
{
 char fname[128];
 char lname[128];
 char mi;
};
How does C bias me toward converting that into an array of structs?
What would such a construct look like?

Oh dear.  Nobody is saying that arrays and structs are interchangable..
The issue at hand is the choice between using an array of structs or
an "equivalent" struct of arrays.  Let's take your example.  
    struct name_struct {
        char fname[128];
        char lname[128];
        char mi;
    };
Is just a struct, even though some fields are arrays.  The following
statement creates an array of structs.  
    struct name names[100];
is an array of structs.  
Now instead of using an array of structs we could use an struct
holding arrays.  It would look like this:
    struct name_fields {
        char fname[100][128];
        char lname[100][128];
        char mi[100];
    } names;
The array of structs and the struct of arrays have the same data, but
the data ordering is different.
Is this clear?

OK, what is C specific about preferring one over the other?  Why is
*C* biased to using arrays of structs rather than these struct of
arrays abominations over and above simple, basic, common sense?


CORAL-66 for instance was far more biased. It allowed ARRAY containing
RECORD but not RECORD containing ARRAY
 
N

nroberts

On 30.10.2011 18:43, nroberts wrote:

True, but in C++ you have more possibilities for bad design.

Because you said so....ok.
That is right, but at the very least, people reading the code are able
to detect a call to a function, unlike the line I posted.

Why do they need to? All they should be caring about is that x is
being incremented by y and then y is incremented. Who cares if that's
a set of CPU statements or another set of CPU statements? That's the
whole point of working at a higher level than machine language.
That's true too, but then you actually know that x and y must be
pointers, which isn't obvious from the C++ line.

Again, it shouldn't matter. The kind of convoluted situations in
which you don't know that x and y reference the same variable do not
generally occur.
No templates were used in that implementation. It was a class that went
something like:

class TSPrintf {
    std::string format;
    unsigned int pos;
    public:
        TSPrintf(const std::string&);
        TSPrintf& operator()(unsigned int);
        TSPrintf& operator()(char);
        TSPrintf& operator()(const char*);
        TSPrintf& operator()(you_name_it);

};

The call would then go like

TSPrintf("%u errors in %u lines\n")(errors)(lines);

And if you tried funny stuff like

TSPrintf("%s errors\n")(errors);

What a limited, unfortunate, and fragile design.
I looked at the STL at another point and lost myself in the code
somewhere. It's a bit astonishing what kind of stuff you actually need
to do before you can shift strings into streams.

In other words, "I don't understand it, ergo it's evil." You could
have learned a lot from the STL.
C++ however advocates a bottom-up design which often leads to more code
being written than actually used. Also, the code is more general,
because you think about needing a list, before you think about needing a
list of integers. (OK, bad example, as there's already std::list available)

Well, at least YOU know what I'm thinking.
Yeah. And local typedefs don't always serve to really abbreviate things
as they were meant to. I once read a template that went along the lines of:

template <typename T> class X {
    typedef T my_local_type;

}

I don't see why one would "abbreviate" T with "my_local_type", but hey,
that's how they roll.

Which is your ignorance. You should be trying to loose it, not coddle
it and turn it into your argument.

Often one needs to instantiate the type of a parameter or a return.
The broken template you wrote to make a mean for example should have
used this technique. Tell me, do you know how templates that make use
of class X instantiations would get T without that local typedef? I
do:

template < typename T > struct get_T_from_X;
template < typename T > struct get_T_from_X< X<T> > { typedef T
type; };

There are often times when this method is necessary and important, but
even then it's easier to write the default case to refer to a local
typedef instead of specializing to get the parameter.

Of course, all of this is so that you CAN tell what type you are
working with, be that in a return or a parameter. With the new C++
you can use decltype for a return type, but not so easily for the
parameter. This can be much more difficult though, requiring calls to
other 'functions' like declval and such. I don't think the local
typedef solution is going to be superseded any time soon.
So you cannot figure out what a class function
actually returns even after you read the declaration.

You need to learn a little about the subject you are speaking about
before your arguments are anything but vapor.
Well, I guess you're right about that. I still think it is good design
to actually write only the stuff you need. I once wrote a matrix class.
I only needed it to contain integers, so I wrote it like this. I don't
see why I should have written a template class. Just so that at some
later point I could reuse it? But then again, this class was half a
day's work, so there's no real point. Plus I actually only needed the
Gauss-Jordan algorithm.

"I once wrote a matrix class that was only capable of working on
integers. I didn't need anything more than that. Thus I don't see
why anyone would need something that worked on more types."

Got it.

You remind me of the people who've never graduated high school, never
read a book other than some holy scripture, and then yell and scream
about how all the scientists are wrong.
 
M

Malcolm McLean

Because you said so....ok.

What a limited, unfortunate, and fragile design.

In other words, "I don't understand it, ergo it's evil."  You could
have learned a lot from the STL.

Which is your ignorance.  You should be trying to loose it, not coddle
it and turn it into your argument.

You need to learn a little about the subject you are speaking about
before your arguments are anything but vapor.

You remind me of the people who've never graduated high school, never
read a book other than some holy scripture, and then yell and scream
about how all the scientists are wrong.
Relax.

There are two components to the system, the computer and the human
programmer.

It's no good having a programming language which is superbly
efficient, malleable, with automatic error-checking and so on, if for
some reason humans find it difficult to use. There's not much point
blaming the human for his stupidity, unless you can hire someone else,
and very frequently the person you might really want is nowhere to be
found.
 
N

nroberts

Relax.

There are two components to the system, the computer and the human
programmer.

It's no good having a programming language which is superbly
efficient, malleable, with automatic error-checking and so on, if for
some reason humans find it difficult to use. There's not much point
blaming the human for his stupidity,

There is when it clearly their own doing.
 

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,091
Messages
2,570,604
Members
47,223
Latest member
smithjens316

Latest Threads

Top