Live data from Hacker News

Obvious things C should do

digitalmars.com

271–280 of 310 posts

Re: Obvious things C should do

#271
post #235

Earlier quoted context omitted.

> Header files are one of the things I miss the most about languages that aren't C. Having a very clear distinction between public and private, and interface and implementation is one of my favourite things about C code (at least the way I write it). I always found this argument baffling, because the way some other language solve this problem is with tooling, which is a much better way to do it in my opinion. Take Ru…

The include file mechanism is a hack that was acceptable at the time when machines were extremely underpowered, so only the simplest solutions had a chance to be implemented within a reasonable time frame. By now, of course, precompiled headers exist, but their interplay with #define allows for fun inconsistencies. And, of course, they leak implementation as much as the author wants, all the way to .h-only single-fil…

Precompiled headers are a terrible misfeature. I ban them in any code base I am responsible for.

They encourage the use of large header files that group unrelated concerns. In turn that makes small changes in header files produce massive, unnecessary rebuilds of zillions of object files.

The clean practice is to push down #includes into .c files, and to ruthlessly eliminate them if at all possible. That speeds up partial rebuilds enormously. And once you adopt that clean practice, pre-compiled headers yield no benefit anyway.

Re: Obvious things C should do

#272
post #79

I write unit tests for my C code all that time. It's not difficult if you use a good build system and if you are willing to stomach some boilerplate. Here is one test from my "test suite" for my npy library: void test_load_uint8() { npy_arr *arr = npy_load("tests/npy/uint8.npy"); assert(arr->n_dims == 1); assert(arr->dims[0] == 100); assert(arr->type == 'u'); npy_free(arr); } int main(int argc, char *argv[]) { PRINT_…

Your function looks like it's doing I/O, which won't work at compile time test. Here's an example of a unittest for the ImportC compiler: struct S22079 { int a, b, c; }; _Static_assert(sizeof(struct S22079){1,2,3} == sizeof(int)*3, "ok"); _Static_assert(sizeof(struct S22079){1,2,3}.a == sizeof(int), "ok"); The semantics are checked at compile time, so no need to link & run. With the large volume of tests, this speeds…

This works in regular C as sizeof() is a constant expression, but perhaps that was your point?

Re: Obvious things C should do

#273
post #162

The most obvious thing c should do is... evolve. Even Fortran seems to have added object-oriented constructs, all kinds of new types and concurrent and parallel programming

It has and it does. Compare modern C with c89

It won't become D and you can probably be fairly sure it won't grow a standard garbage collector and object system.

Re: Obvious things C should do

#274
post #235

Earlier quoted context omitted.

> Header files are one of the things I miss the most about languages that aren't C. Having a very clear distinction between public and private, and interface and implementation is one of my favourite things about C code (at least the way I write it). I always found this argument baffling, because the way some other language solve this problem is with tooling, which is a much better way to do it in my opinion. Take Ru…

The include file mechanism is a hack that was acceptable at the time when machines were extremely underpowered, so only the simplest solutions had a chance to be implemented within a reasonable time frame. By now, of course, precompiled headers exist, but their interplay with #define allows for fun inconsistencies. And, of course, they leak implementation as much as the author wants, all the way to .h-only single-fil…

Modules already existed in programming languages outside Bell Labs in the same decade, like the Modula-2 you quote.

Re: Obvious things C should do

#275
post #187

Earlier quoted context omitted.

This test/src separation always felt like html/css to me. When still using C, I wrote tests right after a function as a static function with “test_” in the name. And one big run-all-tests function at the end. All you have to do then is to include a c file and call this function. Why would I ever want to separate a test from its subject is a puzzling thought. Would be nice to have “testing {}” sections in other langua…

Because tests also serve as api validations. If you can't write a test for functionality without fiddling with internal details the api is probably flawed. Separation forces access via the api.

I don’t need anything to be “forced” on me, especially when this forcing is nominal and I can #include implementation details. You may need that in teams with absurdly inattentive or stubborn members, but for you-personally it’s enough to get the principle and decide when to follow it. The idea is to simply keep tests close to the definitions because that’s where the breaking changes happen.

If you can't write a test for functionality without fiddling with internal details the api is probably flawed

This logic is flawed. If you have an isolated implementation for some procedure that your api invokes in multiple places (or simply abstracted it out for clarity and SoC), it’s perfectly reasonable to test it separately even if it isn’t officially public.

Re: Obvious things C should do

#276

Header files are one of the things I miss the most about languages that aren't C. Having a very clear distinction between public and private, and interface and implementation is one of my favourite things about C code (at least the way I write it). Being able to just read through a library's .h files to know how to use it is really nice. Typically, my .h files don't really look like my .c files because all the docume…

Object Pascal (not the original Pascal) versions like Delphi and Free Pascal have syntax and semantics for interface and implementation sections of the module. Wouldn't be surprised if Modula-2 and Ada had that too.

That was inherited from UCSD Pascal, and also incorporated into ISO Extended Pascal, which was supposed to be a more industry friendly revision of ISO Pascal, but by then Object Pascal was the de facto standard.

Modula-2 modules are based on Xerox Mesa, and do have split sections, as does Ada.

Additionally, Modula-2 and Ada modules/packages have a powerful feature that is seldom used, multiple interfaces for the same module implementation, this allows to customise the consume of a module depending on the customer code.

Re: Obvious things C should do

#277
post #270

Earlier quoted context omitted.

Linkers are slow and clunky. Yes, there is a crossover point where executable tests are faster.

For one of my C projects (ca. 450 c-files), full rebuild time on my (not super fast) laptop is just below 10 seconds (incremental builds < 1s). Compiling and linking all unit tests takes a second, and running all unit tests takes 6-7 seconds. So even running the optimized code for the tests almost doubles the time for rebuilding the full project. Although I like the machine code to be tested that is actually used. (B…

What about putting common template parameters into an external template in a binary libray?

Re: Obvious things C should do

#278
post #186

Earlier quoted context omitted.

Object Pascal (not the original Pascal) versions like Delphi and Free Pascal have syntax and semantics for interface and implementation sections of the module. Wouldn't be surprised if Modula-2 and Ada had that too.

I remember int/impl sections since the 1990’s turbo pascal, which wasn’t “object” still, iirc. Also, commercial closed-source units (modules) were often distributed in a .tpu/.dcu + .int form, where .int was basically its source code without the implementation section.

Interesting.

Yes, I remember the .tpu and .dcu filename extensions.

IIRC, .tpu stood for turbo pascal unit, and .dcu may have meant delphi compiled unit, not sure of the latter.

I don't remember the .int extension, but it would have been there, of course, if you say so.

What was the use of the .int file?

Re: Obvious things C should do

#279

Earlier quoted context omitted.

I have the impression you're mixing single-pass compilation and O(1) memory use of the compiler. As is, C already is single-pass compilable, modulo some unnecessary syntax ambiguities. As the compiler reads the text, it marks some character strings as tokens, these tokens are grouped as a fragment of code, and some fragments of code are turned into machine code. A simple function of a 100 lines doesn't need to be par…

You cannot do any optimization when generating machine code that way. That's fine for a primitive compiler built for a school project, but not much else. (Even "no optimization" switch settings on a compile do a lot of optimizations, because otherwise the code quality is execrable.)

> That's fine for a primitive compiler built for a school project, but not much else.

Not true.

On the one hand, just see how many non-compiled languages are used outside of primitive school projects.

On the other hand, this simpler approach is actually faster for writing actually fqst compilers. Many modern compiled languages have compilers that work on the order of ~100ms on a simple file with 1k LoC, when it could (and arguably should) work on the order of ~1ms, IOW, imperceptible given the syscalls overhead.

A 100x faster compiler that generates meh code is more useful 99% of the time: when one is recompiling all the time during development.

Re: Obvious things C should do

#280

Header files are one of the things I miss the most about languages that aren't C. Having a very clear distinction between public and private, and interface and implementation is one of my favourite things about C code (at least the way I write it). Being able to just read through a library's .h files to know how to use it is really nice. Typically, my .h files don't really look like my .c files because all the docume…

TypeScript has that.

Although it can infer types and generate the declaration fully

Post reply on HN