Hacker News new | ask | show | jobs
by nwmcsween 2935 days ago
The no malloc within the library cannot be overstated, let the user of the library decide what is best and do not do some junk like `some_fn()` and require an implicit `some_free()`
3 comments

Although it may work for the integer hash set, forcing the application to deal with potential resizing when adding to a generic hash table is painful. I'll note too that the growable buffer example linked at the end violates the no malloc rule.
I disagree. This is an artificial limitation that severely hampers the library's capabilities. That kind of discipline may be fine for normal linear string-crunching, but it's cumbersome to an asinine degree if your library needs to do any sort of complex ADT manipulation.
It calls to mind Fortran-style function docs which would give a formula to compute the size of a work array for the caller to provide. That really ties the implementation to the header. It was really boring to work with, though it often pushed you to understand what was going on inside.
This kind of interface was common in fortran 77. I’m guessing you’ve used BLAS/LAPACK? In more modern fortran, it’s not so usual. Also, Fortran is much more high level than C, and how memory is allocated etc is compiler dependent to a much larger degree than for C.

I’d recommend writing a Fortran 95 wrapper which creates work arrays for you if you really need to use such routines.

Most often you do not need any sort of "complex ADT"; in that case the no-malloc advice is good but harmless.

Sometimes, you can probably do without any "complex ADT"; in that case, the no-malloc advice forces you to find the clean solution without complex ADT, thus it is really great.

In the rare cases when you intrinsically need a complex ADT, then you do it. The advice is a spirit, not an unbreakable constraint. Just like not using goto.

It's also necessary if you want to use the library at all in situations where you can't assume that a heap allocator is available.
If you need aligned memory (e.g., for SIMD operations), it can be better to assume control of allocation.
But what if "some" is not subject of my program and I want to offload it's complexity away so that I can concentrate on actual subject of my program? In that case wouldn't it be better to have some_alloc, some_foo, some_free rather than to need each user to make their own, probably buggy and slow allocator?

If I'm making image editor, allocating bitmaps myself is fine, if I'm writing crud app, not so much.

> need each user to make their own, probably buggy and slow allocator

What's wrong with malloc?

At least in game development, custom allocation code is often used to either provide more debugging and profiling capabilities, or otherwise add functionality to the generic C or C++ allocator. Every good middleware library provides a way to hook into memory allocation, and ideally annotates each allocation with some sort of tag or label, so it's possible to track from the outside what an allocation was used for.
Nothing I was thinking about allocations of more complex structures (that at the end use malloc)
We use wrappers where I work, as we track all allocations. We can provide application context if something goes wrong, we can track usage (per thread, per subsystem, over time), and probably most importantly, we know the allocation pattern of our applications better.
glibc malloc provides a way of hooking into memory management calls without having to use wrappers: https://www.gnu.org/software/libc/manual/html_node/Hooks-for...
A library is not a framework. A library provides the basic bricks and typically the users build a layer that fit their needs. It could be, for instance, C++ classes.

Furthermore if the authors of the library think they know better with regard to allocation, they can provide an allocator as a separate addition to the library.