CCL vs STL: a comparison

J

jacob navia

Le 12/05/12 08:18, Gareth Owen a écrit :
Jacob's code contains an explicit cast of a void* to an int*, meaning
the programmer has to track the data types and then tell the compiler
what they are, rather than have the compiler track and check the types.

He doesn't seem to believe this to be a drawback.

Describing the C++ as "less error prone" would be something of an
understatement.

Yes. C++ is the best thing since sliced bread.

In C, the programmer has to do more work. But he gains more control
of what is going on, and avoids a complex (and more error prone yes)
language.

It is my personal view, that is why I insist in developing in C. You
are entitled to your opinion of course. But I thought that in a C group
we would discuss how to improve C.

What would you propose? (Besides the obvious "Use C++")
 
J

jacob navia

Le 12/05/12 00:36, BartC a écrit :
Shame you can't use immediate data. Then that line becomes:

ilist.Add(L,0);

You can specialize the sample implementation file to an int list.
In that case, you make a new interface automatically called

iIntList

and you use

iIntList.Add(L,0);
 
I

Ian Collins

Le 12/05/12 08:18, Gareth Owen a écrit :

Yes. C++ is the best thing since sliced bread.

Did anyone here make that claim?
In C, the programmer has to do more work. But he gains more control
of what is going on, and avoids a complex (and more error prone yes)
language.

Kindly explain (I bet you won't) how

List *L;
int data;
L = iList.Create(sizeof(int));

data = 0;
iList.Add(L,&data);
iList.PushFront(L,&data);
data = 2;
iList.InsertAt(L,1,&data);
data = 5;
iList.Add(L,&data);
data = 6;
iList.Add(L,&data);
iList.Apply(L,PrintInt,stdout);
iList.Finalize(L);

gives the user more control and is less error prone than than

list<int> L = {0, 2, 0, 5, 6};

As I've said many times, the complexity in a given problem is fixed,
where it occurs (in the language or in the code) is variable.

It's worth noting that most of the C++ improvements Ben introduced use
new C++ features. This is because a large proportion of the new
features in C++11 were added to make the programmer's job easier. It's
a pity C11 didn't set out with the same objective.
It is my personal view, that is why I insist in developing in C. You
are entitled to your opinion of course. But I thought that in a C group
we would discuss how to improve C.

Well that's a bit rich considering it was you who introduced the comparison!
What would you propose? (Besides the obvious "Use C++")

Use the best tool for the job, which doesn't have to be C or C++.
 
J

jacob navia

Le 12/05/12 10:09, Ian Collins a écrit :
Kindly explain (I bet you won't) how

List *L;
int data;
L = iList.Create(sizeof(int));

data = 0;
iList.Add(L,&data);
iList.PushFront(L,&data);
data = 2;
iList.InsertAt(L,1,&data);
data = 5;
iList.Add(L,&data);
data = 6;
iList.Add(L,&data);
iList.Apply(L,PrintInt,stdout);
iList.Finalize(L);

gives the user more control and is less error prone than than

list<int> L = {0, 2, 0, 5, 6};

Wait Ian, if I use C99 I can write:

List *L = iList.InitializeWith(sizeof(int),5, (int []){0, 2, 0, 5, 6});

The purpose of my example was to show how Add, InsertAt, etc are used,
not to build precisely a list of those 5 integers!
 
I

Ian Collins

Le 12/05/12 10:09, Ian Collins a écrit :
Kindly explain (I bet you won't) how

List *L;
int data;
L = iList.Create(sizeof(int));

data = 0;
iList.Add(L,&data);
iList.PushFront(L,&data);
data = 2;
iList.InsertAt(L,1,&data);
data = 5;
iList.Add(L,&data);
data = 6;
iList.Add(L,&data);
iList.Apply(L,PrintInt,stdout);
iList.Finalize(L);

gives the user more control and is less error prone than than

list<int> L = {0, 2, 0, 5, 6};

Wait Ian, if I use C99 I can write:

List *L = iList.InitializeWith(sizeof(int),5, (int []){0, 2, 0, 5, 6});

The purpose of my example was to show how Add, InsertAt, etc are used,
not to build precisely a list of those 5 integers!

That's better, but what would happen if you wrote

List *L = iList.InitializeWith(sizeof(int),4, (int []){0, 2, 0, 5, 6});
 
J

jacob navia

Le 12/05/12 11:23, Ian Collins a écrit :
Le 12/05/12 10:09, Ian Collins a écrit :
Kindly explain (I bet you won't) how

List *L;
int data;
L = iList.Create(sizeof(int));

data = 0;
iList.Add(L,&data);
iList.PushFront(L,&data);
data = 2;
iList.InsertAt(L,1,&data);
data = 5;
iList.Add(L,&data);
data = 6;
iList.Add(L,&data);
iList.Apply(L,PrintInt,stdout);
iList.Finalize(L);

gives the user more control and is less error prone than than

list<int> L = {0, 2, 0, 5, 6};

Wait Ian, if I use C99 I can write:

List *L = iList.InitializeWith(sizeof(int),5, (int []){0, 2, 0, 5, 6});

The purpose of my example was to show how Add, InsertAt, etc are used,
not to build precisely a list of those 5 integers!

That's better, but what would happen if you wrote

List *L = iList.InitializeWith(sizeof(int),4, (int []){0, 2, 0, 5, 6});

As I said before, the better way to write that is:

int tab[] = {0, 2, 0, 5, 6};
#define NB_ELEM(tab) (sizeof(tab)/sizeof(tab[0])
List *L = iList.InitializeWith(sizeof(int),NB_ELEM(tab),tab);
 
I

Ian Collins

Le 12/05/12 11:23, Ian Collins a écrit :
Le 12/05/12 10:09, Ian Collins a écrit :

Kindly explain (I bet you won't) how

List *L;
int data;
L = iList.Create(sizeof(int));

data = 0;
iList.Add(L,&data);
iList.PushFront(L,&data);
data = 2;
iList.InsertAt(L,1,&data);
data = 5;
iList.Add(L,&data);
data = 6;
iList.Add(L,&data);
iList.Apply(L,PrintInt,stdout);
iList.Finalize(L);

gives the user more control and is less error prone than than

list<int> L = {0, 2, 0, 5, 6};


Wait Ian, if I use C99 I can write:

List *L = iList.InitializeWith(sizeof(int),5, (int []){0, 2, 0, 5, 6});

The purpose of my example was to show how Add, InsertAt, etc are used,
not to build precisely a list of those 5 integers!

That's better, but what would happen if you wrote

List *L = iList.InitializeWith(sizeof(int),4, (int []){0, 2, 0, 5, 6});

As I said before, the better way to write that is:

int tab[] = {0, 2, 0, 5, 6};
#define NB_ELEM(tab) (sizeof(tab)/sizeof(tab[0])
List *L = iList.InitializeWith(sizeof(int),NB_ELEM(tab),tab);

That's what we have to do in "old" C++ but the updated standard makes
life easier and safer.
 
B

BartC

jacob navia said:
Le 12/05/12 11:23, Ian Collins a écrit :
As I said before, the better way to write that is:

int tab[] = {0, 2, 0, 5, 6};
#define NB_ELEM(tab) (sizeof(tab)/sizeof(tab[0])
List *L = iList.InitializeWith(sizeof(int),NB_ELEM(tab),tab);

I've tried hard to like this library but, having to stick within the
limitations of standard C, I think you've got your work cut out trying to
make it not look clunky.

As I understand your original example, you're trying to do something like
this:

L:=()
L.append(0)
L.prepend(0)
L.insert(1,2)
L.concat((5,6))
print (L)

You can probably do pretty much this now, in half-a-dozen different
scripting languages. The above is not typed, so perhaps you can formalise it
by declaring:

List L or List int L

at the top. Then that will use flex int arrays as the C and C++ fragments
would do (although I understand the CCL doesn't know about type, only size).

Both the examples in your original post have plenty of extra clutter
compared with my minimalist version. Maybe the newer C++ comes closer to
doing this, but probably by having to enhance the language and at a cost of
considerable extra complexity (and the original C++ wasn't exactly simple).

Perhaps you should be comparing your CCL code, with a version in C that
doesn't use CCL, although the latter is likely to be specialised. (You gave
one example of a specialised version, and it did look more streamlined.)

Also, maybe compare performance; whether it's faster than C++ might be of
interest (but I guess that depends on compiler). Both are likely to be a lot
faster than any of those scripting languages.

It's also possible that appearance is not so important, if a library such as
CCL is going to be used behind the scenes. Then users will wrap it with an
interface of their choice, and perhaps with shorter names ('InitializeWith'
looks long-winded). The important thing then are the list-processing
facilities that are provided.
 
J

jacob navia

Le 12/05/12 14:14, BartC a écrit :
perhaps with shorter names ('InitializeWith'
looks long-winded)

Yes, you are right. I will change that to
InitWith (6 chars less) that is as explicit but
shorter. I will review other longnames also.
 
J

Jens Gustedt

Salut,

Am 11.05.2012 18:59, schrieb jacob navia:
Here is a comparison of two source codes that use the C++ STL and the
C containers library (ccl).

I think your example is a nice demonstration of the features of your
library, but I also think it would gain a lot if you would put it in
the context of C11, especially when you compare to C++.

C11 has type generic macros and the simplicity of using your library
would gain a lot if the interfaces were type generic. Things like

data = 0;
iList.Add(L,&data);

i.e having to assign to a variable, first, before being able to add an
element to a list is a no-go. Additionally, it lacks at least a simple
check for consistency to see if sizeof data is the size that you
initially gave to your list through iList.Create.

I can imagine the reason why it looks like this (probably your
function is just doing a memcpy so you can't do with an rvalue) but
interfaces like that will not be widely used, I think.

For a generic interface I'd do something like

#define getLvalue(X) \
_Generic((X), \
int: (int){ (X) }, \
...etc... \
)

#define iListAdd(L, X) iList.Add(L, (dynamic_asser(theSizeOfElements(L)
== sizeof X), &getLvalue(X)))

Or, alternatively I would change the interfaces of your functions that
they all also receive the size of the data element that is to be
stored and then have something simpler like

#define iListAdd(L, X) iList.Add(L, &getLvalue(X), sizeof X)

Your iList.Apply function then also could be encapsulated in a macro
that would make the call side look something like

ILIST_APPLY(L, int, i) {
fprintf(extraArgs,"%d ",i);
}

no need to distract the programmer by forcing him to define a function
specially for that. (But I am well aware that such constructs would
face much reluctance for inclusion in a C standard.)

Please don't get me wrong, I am just saying that a "naked" type
agnostic interface like you defined and implemented it is not
sufficient. But it could be a first step (or stage) for such a library
if you'd offer a type generic interface on top of it. Modern C gives
you all the tools you need for that.

If the C library were designed today, it would be designed with type
generic interfaces à la tgmath.h I think that any future additions to
the library should follow such a pattern.

Jens
 

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,079
Messages
2,570,574
Members
47,207
Latest member
HelenaCani

Latest Threads

Top