Engineering a list container. Part 1.

B

Ben Bacarisse

jacob navia said:
But it forces it upon you!

In C you can do it:

1) Without destructors using a GC In that case the code is even shorter:
2) Using a common heap you can free all memory used by all the created
lists in a single call to "DestroyHeap"

3) Using destructors as I showed you in the last message.

Which one is choosen depends on your application and context. Now,
in C++ you have only ONE method: destructors. It is forced upon you
by the language. Method 1 (GC) is inefficient because the destructors
are called anyway. The same for method 2.

All these options are available in C++ and since you don't have to have
a destructor there's no cost unless you need one.

What does the CCL do about allocators? Can one control where storage
comes from for different container objects? This is important to make
number 2) really useful.

<snip>
 
M

Malcolm McLean

Memory isn't the only resource you may want to release....
Yes and no.
Bit shuffling should be treated separately from IO. Bit shuffling needs memory,
but nothing else.
The type safety aspect shouldn't be so readily dismissed. Finding an
apple in a list of oranges can lead to some interesting bugs!
Baby X doesn't have any type safety. You pass it void *s which it passes
back to you. The syntax is a slight nuisance, but I haven't had any type
mismatch problems when using it.
 
B

Ben Bacarisse

Malcolm McLean said:
Yes and no.
Bit shuffling should be treated separately from IO. Bit shuffling
needs memory, but nothing else.

Modern software is usually written at a higher level than IO and bit
shuffling. Things like file locks, semaphores, DB transactions and so
on might all be one or the other at some level, but you want to be able
to treat them as resources.

<snip>
 
G

Guest

fopen () can't be written in standard C.

I don't believe there is a C++ conspiracy against C
 
J

jacob navia

Le 23/12/2013 12:48, Ben Bacarisse a écrit :
All these options are available in C++ and since you don't have to have
a destructor there's no cost unless you need one.

Of course you can write C in C++.
What does the CCL do about allocators?

You can replace them at a global level or at a container level.
This means that you can replace the standard allocator for ALL
containers or just put a specialized allocator for a single
container.
Can one control where storage
comes from for different container objects?

Yes, see above.

This is important to make
number 2) really useful.

Yes.
 
J

jacob navia

Le 23/12/2013 15:55, (e-mail address removed) a écrit :
fopen () can't be written in standard C.

It can be written in C. Most implementations are written in C and
call the operating system I/O functions.

The purpose of fopen is to present a COMMON INTERFACE that allows
to hide all those operating system specific functions and ake the
code portable.

The same with the CCL: to present a common interface to several
containers that makes the code using it PORTABLE across implementations
I don't believe there is a C++ conspiracy against C

That doesn't surprise me.
 
M

Malcolm McLean

Modern software is usually written at a higher level than IO and bit
shuffling. Things like file locks, semaphores, DB transactions and so
on might all be one or the other at some level, but you want to be able
to treat them as resources.
I see most programs as having a core algorithm or functionality, then lots
of essentially uninteresting UI code or "business logic" around it.
Generally the core functionality is written in C, the surrounding code can
be written in anything. Frequently these days it's Javascript, though I
tend to use Perl.
Core functionality can be inherently IO bound (networking software, a web
crawler, some types of signals processing, window managers), but more often its bit shuffling and should be written as bit shuffling. Then you only need to
write it once. Parallelisation and pacifiers present problems, however.

Baby X is IO bound. Virtually everything it does is sending messages of
one sort or another to the windowing system to put up pretty pictures on
screen. There are just a few helper functions which do bit shuffling.
But Crossword Designer, currently my most popular program (download it
from Sourceforge and tell your friends to do that same) has at its core
a function to fill grids from a word list. That's all separated out from
the GUI code. At some point I'll port it from MS Windows to Baby X.
 
I

Ian Collins

Malcolm said:
I see most programs as having a core algorithm or functionality, then lots
of essentially uninteresting UI code or "business logic" around it.

You miss the point. GC is often presented as a silver bullet when in
practice it only helps with one (memory) of the many resources a
programme might be required to manage.
 
M

Malcolm McLean

Malcolm McLean wrote:

You miss the point. GC is often presented as a silver bullet when in
practice it only helps with one (memory) of the many resources a
programme might be required to manage.
A Turing machine consists of a pencil, an eraser, a contraption to draw or
erase marks according to a limited set of states, another contraption to
move the pencil forwards or backwards a step, and an infinite tape.
malloc() is your infinite tape. Memory is not just another resource, it's
more fundamental than that.

A bit shuffling function can fail for three reasons. A programming bug,
in which case basically there's nothing that can be done because the
function is by definition incorrect (you can alleviate bugs, but that's
a different story). Or it can fail because of bad input, normally that
indicates a bug in caller and the same consideration applies, but occasionally
input is a parsable type expression, where to validate the input would be
almost as difficult as to implement the function. In that case, bad input
should be treated as normal flow control. The only other case, at least that
I can think of, is out of memory. That's the only real fail.
 
B

Ben Bacarisse

jacob navia said:
Le 23/12/2013 12:48, Ben Bacarisse a écrit :

Of course you can write C in C++.

That's not my point. I thought you implied there was an unavoidable
cost from destructors in C++.

(I should have said you don't have to have a destructor that does
anything -- you always have one, it's just that it can be zero cost.)
You can replace them at a global level or at a container level.
This means that you can replace the standard allocator for ALL
containers or just put a specialized allocator for a single
container.

That's good.

<snip>
 
I

Ian Collins

Malcolm said:
A Turing machine consists of a pencil, an eraser, a contraption to draw or
erase marks according to a limited set of states, another contraption to
move the pencil forwards or backwards a step, and an infinite tape.
malloc() is your infinite tape. Memory is not just another resource, it's
more fundamental than that.

You're either still missing the point or being obtuse.

In the original context of cleaning up objects in a container, consider
a list of Blobs where a Blob contains a handle to some other object type
that has to be released when the Blob is destroyed. The handle is a
finite resource; leaking them will eventually case the programme to
crash. How does GC help in this case?
 
J

jacob navia

Le 24/12/2013 01:48, Ian Collins a écrit :
You're either still missing the point or being obtuse.

In the original context of cleaning up objects in a container, consider
a list of Blobs where a Blob contains a handle to some other object type
that has to be released when the Blob is destroyed. The handle is a
finite resource; leaking them will eventually case the programme to
crash. How does GC help in this case?

Well, here you are expecting too much hand holding from the language, as
you are used in C++. C is not C++.

C gives you all the tools to do that kind of gabage collection, and the
CCL too. You can be notified when a list element is being destroyed, and
then release the handle you want.

Or you can just make a table of handles and destroy them when the list
is destroyed.

Etc. There are many solutions. Yes, C++ does more hand holding and you
may want to do that in C++ for easy of programming that particular task.

I am not saying that C++ is the utmost evil.

What is surprising is that in this group that is supposed to talk and
develop the C language there are so many C++ people that feel like
teaching the obtuse C programmers how wonderful C++ is.
 
I

Ian Collins

jacob said:
Le 24/12/2013 01:48, Ian Collins a écrit :

Well, here you are expecting too much hand holding from the language, as
you are used in C++. C is not C++.

I know that. I do use both in my day jobs as I'm sure you are aware.
If hand holding equals fewer bugs and less code, I'm all for it.
C gives you all the tools to do that kind of gabage collection, and the
CCL too. You can be notified when a list element is being destroyed, and
then release the handle you want.

The key difference is being able to rely on automatic cleanup.
Automatic object destruction is just about the only C++ feature that
can't be mimicked in C and it is the main reason I'd prefer C++ to C
given the choice.
Or you can just make a table of handles and destroy them when the list
is destroyed.

Etc. There are many solutions. Yes, C++ does more hand holding and you
may want to do that in C++ for easy of programming that particular task.

I am not saying that C++ is the utmost evil.

What is surprising is that in this group that is supposed to talk and
develop the C language there are so many C++ people that feel like
teaching the obtuse C programmers how wonderful C++ is.

I believe you misinterpret the message. You would probably have less of
a problem convincing C programmers familiar with C++ to use you library
as we are used to having standard containers on hand. The least likely
adopters would be C programmers who prefer to (re)invent their own wheels.

I think the work you have done is a laudable effort. If you can
convince others to use your library, you would stand a better chance of
getting it standardised. I don't envy you herculean effort
standardisation would require...
 
M

Malcolm McLean

You're either still missing the point or being obtuse.

In the original context of cleaning up objects in a container, consider
a list of Blobs where a Blob contains a handle to some other object type
that has to be released when the Blob is destroyed. The handle is a
finite resource; leaking them will eventually case the programme to
crash. How does GC help in this case?
Normally you'd expect a "handle" to be a pointer, maybe with a few bits and
bats bundled with it. The likely problem comes when you don't have GC, and
you want to free the object when the last handle is deleted. But there could
be another scenario.
My view is that when you're doing fancy it's a lot better to call things
explicitly rather than hide control flow in functions which are called
automatically in ways that aren't obvious to the user.

But generally if a bit shuffling function has handles then it suggests a
poor design, which doesn't modularise correctly. There can be lots of reasons
for this, only one of which is incompetence on the part of the programmer.
Usually the problem will be that you're not passing in "state" to the
function explictly, basically you've created a mess with lavish use of
globals, even if you've hidden the fact that they are globals by not making
them global in the syntactical C sense.
 
J

jacob navia

Le 24/12/2013 10:50, Robert Wessel a écrit :
IOW, it cannot be written in standard C.

Because the system specific I/O functions do not belong to the standard
library OF COURSE. But they are (as I said) WRITTEN IN C!
 
B

BartC

Normally you'd expect a "handle" to be a pointer, maybe with a few bits
and
bats bundled with it. The likely problem comes when you don't have GC, and
you want to free the object when the last handle is deleted. But there
could
be another scenario.

Surely handles can be refer to all sorts of resources such as files, screen
windows and objects, images, consoles, processes, dynamic libraries, network
connections ... the list is endless.

All things that are generally considered to be outside the program itself,
and that might require more elaborate cleanup than simply de-allocating any
local memory they might use.
 
J

jacob navia

Le 24/12/2013 11:38, BartC a écrit :
All things that are generally considered to be outside the program itself,
and that might require more elaborate cleanup than simply de-allocating
any local memory they might use.

Yes, that is why the observer interface is implemented in the CCL.

You get called when a container is destroyed and then you can free any
existing handles.
 
M

Malcolm McLean

Surely handles can be refer to all sorts of resources such as files, screen
windows and objects, images, consoles, processes, dynamic libraries, network
connections ... the list is endless.

All things that are generally considered to be outside the program itself,
and that might require more elaborate cleanup than simply de-allocating any
local memory they might use.
We're talking about bit shuffling functions. The reason for considering them
differently is that if you have physical devices other than memory attached
to the computer, you can have all sorts of complications. If you abort a
print job you might need to tell the printer to eject the page, for example,
the potential difficulties are endless. It's even true for memory - you
have to allocate and free it, free() might need to set to DEADBEEF for
security or other reasons, memory might need to be shared, and so on. It's
much better to write functions without a call to malloc() if possible. But
it's inherently hard to do so, the infinite tape is an essential part of the
system.

When I first learnt C++ I experimented with destructors that made space invaders
explode. It was cute. But it was awful programming from a software engineering
perspective.
 
E

Eric Sosman

[...] The point being made was that including some of
the sdtio.h stuff in the standard makes particular sense because it
cannot be implemented in a standard way. By comparison, most (all?)
of the stuff in math.h could (theoretically) be fairly easily removed,
and instead maintained by someone like Boost.

... with a potential performance penalty. As things stand,
the compiler knows what calls to sqrt() or memcpy() or div() do,
and can achieve their effect by using special in-line instructions
like SQRT or MOVB or DIV. The compiler might even pre-compute the
results of some of these "function calls" at compile time,
eliminating not only the call but also the computation itself.
Were it not for the Standard's prescription of what these functions
do, optimizations of this kind would be difficult if not impossible.

(Aside: Yes, I know that a typical machine's "bare" FSQRT
instruction probably isn't a drop-in substitute for sqrt() --
it's unlikely to set `errno' properly in the event of a domain
error, for example. Even so, the compiler could perfectly well
generate an FSQRT instruction followed by a conditional call to
a failure-fixer function, the latter executed only if FSQRT
reports trouble. Or again: The compiler knows about `errno',
so if it sees that the sqrt() call is immediately followed by
a log() call with no inspection of `errno' in between, it can
just shrug, omit the fixup altogether, and use "bare" FSQRT.
Similar strategies can be applied elsewhere, if the instruction
set offers something that "almost" matches the Standard. But
if a call to sqrt() were allowed to do -- well, anything C can
do -- none of this would work.)
 
I

Ian Collins

Malcolm said:
Normally you'd expect a "handle" to be a pointer, maybe with a few bits and
bats bundled with it. The likely problem comes when you don't have GC, and
you want to free the object when the last handle is deleted. But there could
be another scenario.

The obvious counter example is a POSIX file descriptor.
 

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
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top