8 ms·
It's 2023 - even MSVC has supported C11 and C17 for a while now. C89 is no longer a feature to advertise, it's an unhelpful constraint forcing poorer quality c
by eqvinox 3y ago
It's 2023 - even MSVC has supported C11 and C17 for a while now. C89 is no longer a feature to advertise, it's an unhelpful constraint forcing poorer quality code. A good example is that CspChan_closed should use the bool type added in C99.
There's nonstandard nomenclature in "_dispose"; if the constructing function is called _create, the common pattern is to pair it with _destroy.
typedefs ending with _t are reserved for standards extensions, though these days people ignore this a lot because it feels like general practice to add _t.
There's no way to pass in a custom allocator, or logging callback, or set some debug logging flags. Maybe something to tackle later.
Both _select functions fall short in that they do not allow select'ing on channels + other file descriptors simultaneously. General library design practice is to have the library return a file descriptor that can be used in whatever event loop the application already uses. (The fd can be a dummy pipe or eventfd.)
All of these things are in the header, so they matter the most as they set ABI and API for any user. Unfortunately getting them right as early as possible is important to avoid breaks; yet very hard to do since often API aspects only become clear after a library has non-trivial users.
[edited to tone down a bit]
- 1vuio0pswjnm7 3y agoPerhaps I'm readint it wrong bu this comment is crticising someone for not using added language features. Maybe the author does not need them. "YAGNI". IMO, it should be the author's choice whether or not to utilise certain features. As someone else noted in another comment, C89 is more portable than C11 or C17. To me, C89 is like Bourne shell. An author can choose to write scripts in Bash but they will not be as portable as ones written in Dash, nor as fast. The only constraint I have run into with C89, when compiling lex.yy.c, is that it has a limit of 32767 lines.
- coumbaya 3y agoNot dismissing anything you said but bool isn't C89 right ? Back ~6 years ago when I worked in embedded C89, bool was just a #define true (1==1), #define false (0==1) so I guess it makes sense it isn't in the lib ?
- eqvinox 3y agoIndeed, bool (or _Bool) was added in C99, hence my pointing out it not being used… it's not in C89. It matters because the return value sense is different; an "int" return for a status-ish thing in a modern library generally means 0 for success, nonzero for error codes. "bool" is the other way around, 0 for failure-y. In this case it's a status retrieval function so it's pretty clear that it's intended as a boolean but it'd still be better to actually make it bool.
- coumbaya 3y agoAh, I get it now, thx.
- dang 3y agoI realize your intention is to provide good feedback and you obviously know a lot, but if you could shift the pH slightly away from acidic, that would be better. Keep in mind that criticisms like this have a tendency to land 10x harder than you intended. https://news.ycombinator.com/showhn.html https://news.ycombinator.com/showhn.html
- helsinki 3y agoHow much do you get paid to be mod?
- defrost 3y agoUndisclosed: https://www.newyorker.com/news/letter-from-silicon-valley/the-lonely-work-of-moderating-hacker-news https://www.newyorker.com/news/letter-from-silicon-valley/th... .. but likely more than either of us get paid to comment.
- deleted 3y ago[deleted]
- eqvinox 3y agoSigh. Yes. Valid. I'll go edit it a bit.
- swingingFlyFish 3y agoThe other reason to love this place is OPs take rebuke with grace. Kudos to you sir.
- dang 3y agoAppreciated!
- pwdisswordfishc 3y ago[flagged]
- 3y ago
- oconnor663 3y ago> that's just the header You're providing a ton of code style feedback. That's fair, code style is important, I'm not saying you shouldn't. But surely when providing style feedback in public you could take a friendlier tone :(
- eqvinox 3y agobtw, just to note, both your and dang's comment were very appropriate in calling me out for the very poor form of the original comment. Either of your comments would've reminded me that I don't normally do that, and I would've gone back and edited it. I replied to dang's comment (the "Sigh. Yes. Valid.") because I saw that first, but I also appreciate your pointing out the same thing, and in particular that you did so without reacting to my bile with more bile yet. Thanks!
- oconnor663 3y agoNo worries!
- wiseowise 3y agoWhat's unfriendly in their tone?
- IAmLiterallyAB 3y agoThey edited their original comment before you saw it, apparently the original tone was a bit harsh
- kazinator 3y ago> should really be a bool bool is actually #define bool _Bool. You have to include <stdbool.h> to get it. That's ugly enough not to want to use it. I'm looking at the April 2023 draft of ISO C. Under "Relational Expressions" I see that the result of an expression like x < y isn't bool, but ... int. Here is the exact wording, minus a footnote reference: Each of the operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) shall yield 1 if the specified relation is true and 0 if it is false. The result has type int. int is still the Boolean type in C, and null pointers and zeros are still falsy, relational expressions yield 0 or 1 of type int, and #define bool is just a sham for anal retentives. > typedefs ending with _t are reserved for standards extensions That is inaccurate. It's POSIX that reserves this namespace. Even if you're targeting POSIX, the reservation has next to no practical meaning, and can safely be ignored. Here is why. What POSIX says is that when new type names will be introduced in the future in POSIX, they will have _t as a suffix. Well, so what? New type names in ISO C will also have _t suffixes, yet ISO C doesn't say anything about that being "reserved". When a new identifier is introduced, it has to start and end in something. Whenever POSIX introduces a new public identifier in the future, that identifier will either start with "a", or else with "b", or with "c" ... does that mean that we should stop using all identifiers in order not to tread on a reserved space? When you have a language without namespaces/packages, you just live with the threat of a clash and deal with it when it happens. Name clashes are not just with standards like ISO C and POSIX but vendor extensions and third-party code. The mole is only a problem when it rears its head, and that's when you whack it.
- eqvinox 3y ago> bool is actually #define bool _Bool. You have to include <stdbool.h> to get it. That's ugly enough not to want to use it. Sure, which is why it got changed to a keyword in C23. I'll agree this should have happened earlier. The return type of comparison operators is entirely irrelevant; you don't build APIs by reference to the return type of a comparison operator. It makes a difference to the reader whether your source code says "int" or "bool", that alone is all the reason anyone should need. > That is inaccurate. It's POSIX that reserves this namespace. You got me there. However, the question is, why would you add the _t? It serves no purpose. Typedefs have their own namespace anyway, you're not working around some possible collision by adding the _t. That said I've already noted this is a commonly ignored aspect. I suppose it "feels" better/correct to some readers. I will happily agree this is the weakest point of my feedback either way, yet I still rather point it out and have people learn more details about this.
- sylware 3y agoEven C has already a syntax way too rich and complex (and C11 and C17 tantrums are making things worse). Integer promotion should go, like implicit cast for anything except void* and literals, but we are missing a dynamic/static casts syntax explicit split. Only one loop keyword, loop {}, no switch, no anonymous block, no "a?b:c" operator. typedef has to go, (and typeof,generic,etc), the variable arguments of preprocessor function should be defined once and for all. __thread must go as tls should be managed dynamically and explicitely with the system interface, never statically and hidden by the runtime. Only sized primitive types (u8/s8...). That said, anonymous union/struct are very nice for complex memory layout. And all the things I am forgetting right now. With the pre-processor and coding discipline you can get close to that already, but I was told that what I am describing is basically the simplicity of rust syntax, true? Namely it is easier to write a naive rust compiler than a C compiler?
- IlliOnato 3y agoWhat's wrong with ternary operator ("a?b:c") ? It seems many people hate it but I've never seen a reason for it. This operator is very useful and uncontroversial in Perl, it's normal (and quite readable) in selecting a value for assignment. One is expected to use good practices with it, but it is nice. Is the problem the fact that in C you can use it instead of if, selecting not values but actions, like (a > b) ? printf("A") : printf("B");
- zogrodea 3y agoI (a different person replying to your post) don't mind ternary operators, but I do prefer if-expressions which convey the same thing semantically but can be nicer to read (and also way better when chaining else-if ladders - nested ternaries can be a nightmare to read). https://stackoverflow.com/a/46843369 https://stackoverflow.com/a/46843369
- IlliOnato 3y agoChained ternaries are quite readable when formatted as tables... a = (x < 5 ) ? 'LESS' : (x > 5 ) ? 'MORE' : 'SAME';
- MrRadar 3y agoAlso, as someone who wrote code that had to support C89-only compilers as recently as 5 years ago, I noticed immediately that this code mixes code and variable declarations which strictly C89 compatible compilers will barf on. That said, this code also uses pthreads which is not exactly as portable as "pure C89" implies either.
- tomcam 3y ago> It's 2023 - even MSVC has supported C11 and C17 for a while now. C89 is no longer a feature to advertise There are plenty of constrained environments where this is indeed a feature to advertise, namely older machines and embedded systems.
- 38 3y ago> older machines Anything from the 80s/90s isn't really worth supporting. We gotta draw the line somewhere.
- fweimer 3y agoBut it's not actually written in C89. It uses POSIX threads, flexible array members, anonymous unions, bitfield members that are not int, declarations intermixed with statements. And that's just what “gcc -std=c89 -pedantic-errors” reports.
- pengaru 3y agoThe standards extensions reservation of _t is such a non-issue I don't understand why people even bother mentioning it anymore. It's become such a common practice to suffix your typedefs with _t it's practically a de facto standard at this point. Since everyone's already namespacing types with some kind of prefix, I don't see the problem nor have I ever experienced a negative consequence after decades of writing C this way.
- neverartful 3y agoNo good deed goes unpunished.
- Rochus 3y agoAmen.
- Galanwe 3y ago> It's 2023 - even MSVC has supported C11 and C17 for a while now. C89 is no longer a feature to advertise, it's an unhelpful constraint forcing poorer quality code. Oh come on, let's not play the language police... You are entitled to your language likings, others are not. C89 is simple, straightforward, no bells and whistles, and some people like that (I do). > There's nonstandard nomenclature in "_dispose"; if the constructing function is called _create, the common pattern is to pair it with _destroy. "Nonstandard" says who? In my 20 years of C I've seen all possible combinations of _init/_create/_new/_alloc _free/_deinit/_release/_delete/_destroy/_dispose. As long as it's consistent across the codebase, it's fine. > typedefs ending with _t are reserved for standards extensions, though these days people ignore this a lot because it feels like general practice to add _t. Not really. The usual convention for _t is to differentiate between raw struct names and typedef structs, such that you know whether you have to prefix "struct" during declaration. i.e. `struct foo {}`/`typedef struct {} foo_t` > Both _select functions fall short in that they do not allow select'ing on channels + other file descriptors simultaneously. Good point
- dekhn 3y agoI feel like this comment could be best structured in the form of a series of commits sent as a combined Merge Request. First, a commit to change the docs to say it's a pure C99 (or C11 or C17) implementation. Second, for each of your points, a single commit fixing each style issue (_dispose -> _destroy, typedefs). Seperately, another MR with the commit for _select improvements. Or maybe just send the C99 one first, and if that gets rejected, don't bother with the rest.
- jansommer 3y agoMSVC lacks some C99 features like variable length arrays and complex numbers. There's always a work around, but wouldn't want to use that compiler for C unless I had to. Going for C89 for a truly portable project is probably fine.
- arp242 3y agoMSVC added that a few years ago. It took them a (very) long time, but it should now be fully C99-compliant, even C17 I think (either fully or mostly).
- jansommer 3y agoNo. That syntax is not supported. Try a VLA and see how it goes. Then try a complex number or read the docs: "The compiler doesn't directly support a complex or _Complex keyword" - https://learn.microsoft.com/en-us/cpp/c-runtime-library/complex-math-support?view=msvc-170 https://learn.microsoft.com/en-us/cpp/c-runtime-library/comp...
- pjmlp 3y agoSupporting C11 and C17 by definition doesn't require supporting C99 features made optional in C11.
- Conscat 3y agoI would note that Tiny C Compiler is used a fair amount in the wild today, even beyond its stated use cases on the landing page, and C89 is the only standard that it fully supports.
- jamal-kumar 3y agoOut of curiosity where is tinycc still being used?
- rurban 3y agoWith big code bases, to get fast feedback. For me it's 200ms vs 3min
- defrost 3y agoFun stuff like running OS's in your browser: https://bellard.org/jslinux/ https://bellard.org/jslinux/ and by a dedicated few to this day: https://lists.gnu.org/archive/html/tinycc-devel/ https://lists.gnu.org/archive/html/tinycc-devel/ It's not much but it's not dead.
- Conscat 3y agoLanguages that transpile to C code like it because, if the C is generated by another compiler, then the C language's expressiveness doesn't really matter, and TCC builds machine code pretty fast.
- arp242 3y agoAccording to the README it supports most of C99, and even some things beyond that. It's not clearly defined what's meant with "most" or what's not supported, but since I've never had any problems with any C99 code I've written I suspect it's mostly fairly little used stuff (complex numbers?), and it seems that for all practical purposes tcc supports C99 for almost all codebases.
- Rochus 3y ago> edited to tone down a bit How generous. The comment reminds me of this passage in C. Northcote Parkinson's famous 1957 book: "The man who is denied the opportunity of taking decisions of importance begins to regard as important the decisions he is allowed to take. He becomes fussy about filing, keen on seeing that pencils are sharpened, eager to ensure that the windows are open (or shut), and apt to use two or three different-colored inks." How can it be that in HN a comment like this, which is all about trivialities and the personal sensitivities of the commentator, and which contributes nothing relevant to the matter at hand, receives the most upvotes? Is this comment somehow pinned to the top instead? Many here seem just disparaging about Reddit, but if you want to see an actually useful and intelligent comment from someone who actually knows something about the subject, take a look here: https://old.reddit.com/r/C_Programming/comments/18fzr1a/a_pure_c89_implementation_of_go_channels/kcxi4p5/ https://old.reddit.com/r/C_Programming/comments/18fzr1a/a_pu.... I'd expect at least that level from comments on HN.
- sevagh 3y ago>How can it be that in HN a comment like this, which is all about trivialities and the personal sensitivities of the commentator, and which contributes nothing relevant to the matter at hand, receives the most upvotes? Is this comment somehow pinned to the top instead? I feel like purposely emphasizing C89 in your project name is meant to highlight some sort of greybeard or serious hacker aspect to it. Presumably the poster was thinking along the lines of "if you're trying to show how proficient you are with a sharp knife, here's a list of all the ways you cut yourself with it."
- anitil 3y agoFor me C89 means 'will build anywhere' whereas C99+ means 'may or may not build anywhere', rather than a value judgement about the author. But my background was in firmware where sometimes you were using custom compilers or very old compilers.
- cellularmitosis 3y agoAs someone whose idea of fun is trying to compile open source software on OS X / PowerPC, portability has a special place in my heart. While I view open source software as a "gift to the world", C89 + MIT is at the far end of the spectrum of how generous that gift is. https://imgflip.com/i/89b05r https://imgflip.com/i/89b05r
- jjgreen 3y agoIIRC, reservation of _t in typedefs is for the POSIX rather than C standards.
- accelbred 3y agoC89 is a requirement where I work still, so C89 libraries are useful here. We support vendor C toolchains that don't always have C99 features.
- Brian_K_White 3y agoIt's 2023, and I love this. There is no reason to criticize the mere fact that someone took the effort to make something that portable. Even if you think they wasted their time, they didn't waste your time, and I value the existence of things like this, which means even if you don't, at least some others do.
- kevin_thibedeau 3y agoC89 sometimes actually means gnu89 which is decidedly non-portable to modern standards in subtle ways. It's time to put that horse to pasture and consider at least using a 24 year old standard instead.
- Brian_K_White 3y agoIf gnu89 is not a perfect c89, so what? c11 is also not a perfect c89. ruby is also not a perfect c89. Swift is more convenient than c89 for ios. c89 doesn't have tons of features that c# has. We could say true yet irrelevant things all day long. You don't like c89 flavor ice cream, got it. So what?
- epcoa 3y agoThe only thing that matters here rather than the nonsense hypotheticals is that they are right, the library isn’t C89 as pointed out by others. This isn’t about not liking C89 flavor ice cream, but calling it C89 when it isn’t. Like, of all things why mislead about that? Very bizarre behavior from the OP and these comments. The more reasonable discussion then becomes: fix the non C89 issues so the statement becomes accurate, disclose that it uses extensions, or as some have constructively suggested consider just targeting C99 rather than GNU89. Not sure why you think criticism of something not being what it claims is inappropriate.
- deleted 3y ago[deleted]
- __d 3y agoOk, I agree that these points might have been made more constructively, but ... They're mostly legitimate, good-quality feedback for a new C library. _create/_destroy -- yes; custom allocator, logger, debug level setting -- yes; returning a file descriptor -- yes; the implied suggestion to move stuff out of the header -- yes. This is important feedback. These things will require a breaking change down the line unless you tackle them before 1.0. I encourage the author to take this onboard: it'll make your own life easier and your library a better C citizen.
- buildartefact 3y agoDo you know of a good style guide that encapsulates common conventions like create/destroy?