[HN Gopher] Maximal min() and max()
       ___________________________________________________________________
        
       Maximal min() and max()
        
       Author : immibis
       Score  : 174 points
       Date   : 2024-08-07 16:26 UTC (2 days ago)
        
 (HTM) web link (lwn.net)
 (TXT) w3m dump (lwn.net)
        
       | baggy_trough wrote:
       | 47MB of code from a min/max macro is simply hilarious!
        
         | dfox wrote:
         | The effects of preprocessor in C are quite significant. Old DOS
         | Turbo C had shown amount of lines compiled and the speed in the
         | compilation progress window in the IDE. IIRC straight
         | #include <stdio.h>         #include <stdlib.h>         int
         | main(int argc, char**argv){           puts("hello, world");
         | return EXIT_SUCCESS;         }
         | 
         | came to something ridiculous on the order of 100k lines.
        
           | CGamesPlay wrote:
           | Well, the #includes are hiding quite a few lines underneath
           | them. While probably not 100k, I wouldn't be surprised if it
           | was, say, 20k.
        
       | jonathrg wrote:
       | That series of macros is a nice demonstration of the incredible
       | effort it takes to attempt the most basic generic programming in
       | C. Perhaps it would be more productive to just accept the
       | limitations of the language and define a version of `min` and
       | `max` for each type.
        
         | lifthrasiir wrote:
         | That will make `typedef` much less useful, though. C is the
         | real problem; not the attempt to do generic programming in C.
         | (And `_Generic` won't solve this problem anyway. Only a GCC
         | extension of statement expressions will.)
        
         | asplake wrote:
         | Also a demonstration of how much work other compilers do for
         | you behind the scenes.
        
           | Groxx wrote:
           | Ehhh... not much more so than how much `npm install` hides.
           | These macros are part of a gigantic tower of absurdity that
           | costs many, _many_ times more than they need to, but we use
           | them because dev time is more valuable than CPU time.
        
             | rerdavies wrote:
             | Dev time spent waiting for compiles is way more expensive
             | than CPU time.
        
               | hughesjj wrote:
               | Well, depends on how much CPU time we're talking about.
               | 
               | The Linux kernel is one of the few cases where just the
               | sheer scale of instances may make a difference
        
               | Groxx wrote:
               | And way, way, WAY less expensive than a troubleshooting
               | session
        
           | jonathrg wrote:
           | A compiler for a language with generic types will definitely
           | do less work to implement generic min/max than the C
           | preprocessor has to do in order to perform all the text
           | substitutions generated by these macros.
        
             | asplake wrote:
             | Oh totally! It has the information to do it both properly
             | and efficiently.
        
           | usr1106 wrote:
           | Or a demonstration about the poor state of programming
           | languages in 2024.
           | 
           | Of course there are others than C. But not many suitable for
           | writing a kernel. And no obvious choice for what Linux could
           | do today. Of course they are starting with Rust, but nobody
           | can predict when that will make the last C macro unnecessary.
           | Unless your prediction is never...
        
             | pjmlp wrote:
             | Plenty of kernels have been written in other languages,
             | naturally UNIX/POSIX folks can hardly think of something
             | else.
             | 
             | Even Linus accepting Rust is kind of interesting, because
             | his C++ rants also apply to plenty of Rust code bases.
        
               | gary_0 wrote:
               | Doesn't Rust's `no_std` make it easy to throw out idioms
               | you can't use (or don't like) and just keep the syntax
               | and most of the tooling? I recall that one of Linus's
               | preconditions for inclusion was that Rust's default of
               | panic!ing on allocation failures had to be overrideable.
               | 
               | Whereas C++ tends to make you eat the whole enchilada.
        
               | pjmlp wrote:
               | C++ compilers have similar options, e.g. VC++ has
               | /kernel, and there is the freestanding standard as well.
               | 
               | Also see Embedded C++ as used by macOS IO Kit, which
               | thankfully there isn't a Linus at Apple.
               | 
               | Regarding Rust, no_std, doesn't change the npm like
               | dependencies, macro festival (with two ways of doing all
               | kinds of stuff), abstraction party with type driven
               | development, the compile times.
        
               | tialaramex wrote:
               | The C++ "freestanding" even when the current round of
               | work is completed, is nowhere close to Rust's core.
               | 
               | Partly this is because Rust thought about this earlier,
               | and partly it's because of the relationship between C++
               | and the allocator, having _operators_ for a feature which
               | might not even exist on your target, awkward.
        
               | pjmlp wrote:
               | True, doesn't change the fact that outside Linus hate for
               | C++, other places, with more sensible persons, have
               | chosen otherwise.
        
               | gary_0 wrote:
               | It's not just Linus. I use C++ daily for a variety of
               | things, but I understand the hesitance to use it in real-
               | world kernels and embedded code. For instance: The
               | switches to disable features like exceptions are
               | generally considered "not supported, use at own risk";
               | removing them is not an official part of the language.
               | C++ templates are slow to compile and have many obvious
               | shortcomings -- but if you avoid them, you're back to
               | using C macros. The C++ abstract machine puts a lot of
               | weird complications in the way, adding new UB landmines
               | on top of C.
               | 
               | This doesn't mean using C++ for kernels and such is
               | impossible, but anyone with a conservative, risk-averse
               | mindset (like Linus) isn't going to want to touch it.
               | 
               | Rust, on the other hand, was deliberately designed for
               | such things, starting from a fresh sheet of paper. It
               | avoided doing the things that C and C++ did to offend
               | systems programmers, and it paid off.
        
               | j16sdiz wrote:
               | On of the reason is: They have Rust compiler developers
               | on board. This is a "direct line" to any language
               | features or bugs reports.
               | 
               | C++, otoh, is run by committee and far removed from the
               | community. (C is not much better, but at least they are
               | stable)
        
               | pjmlp wrote:
               | Stable? C23 has just been approved.
        
               | PaulDavisThe1st wrote:
               | > C++, otoh, is run by committee and far removed from the
               | community.
               | 
               | It is hard to be close to a community with the size and
               | divergence of the C++ one. It is (relatively) easy to be
               | close to a community the size of the Rust one.
        
               | kbolino wrote:
               | Most kernels not written in low-level languages (C,
               | stripped-down unsafe C++, or assembly) were written for
               | special hardware. Such hardware was built to handle a lot
               | of the low-level details so that the software didn't have
               | to. This particular approach can't be translated by
               | software alone to modern general-purpose microprocessor-
               | based platforms. Even if we were able to transition to
               | such a do-more-work-in-hardware platform _somehow_ , then
               | we would just be trading kernel bugs for hardware bugs,
               | and the latter aren't always fixable (even with firmware
               | and microcode).
        
               | pjmlp wrote:
               | Outside Bell Labs many other languages came to be.
        
               | kbolino wrote:
               | The x86 family didn't come out of Bell Labs. It's not a
               | question of where the programming languages came from but
               | of the boundary line between hardware and software.
        
         | peheje wrote:
         | Why don't they define a min/max for each primitive type? How
         | many are there, 15?
        
           | kzrdude wrote:
           | Even use a macro to define all typed min max macros
        
           | wahern wrote:
           | The reason the current macro is so complex is because it
           | supports _mixed_ types while avoiding (failing on) integer
           | promotion bugs. A version supporting arguments of all the
           | same type would be just as trivial as in C++ (albeit relying
           | on GCC extensions like statement expressions).
        
           | tempfile wrote:
           | This is addressed if you chase down the original kernel
           | mailing list thread (the "flamewar" linked in the article).
           | It was important to Linus that the macro was actually min/max
           | and not min_slong max_uint etc, so that people couldn't
           | "accidentally" use the untyped version. In other words he was
           | trying quite hard to "force" people to use these macros.
           | 
           | If you would then say "why doesn't min/max just implement a
           | switch on each primitive type", I think on some level it does
           | just do that.
        
         | colonwqbang wrote:
         | Genericity is not really the issue as I see it. The basic K&R
         | macro using ?: is fully generic. The problem is that C has
         | implicit conversion between essentially any numeric types. The
         | main point of the kernel macro was to prevent such conversions.
         | 
         | I think implicit type conversion is a mistake, perhaps one of
         | the few true design flaws in C. Languages like haskell and rust
         | went with explicit conversions which is probably a better idea
         | overall, even if it does increase the code verbosity a bit. C++
         | instead doubled down and added many more ways for implicit
         | conversions to happen.
        
           | PaulDavisThe1st wrote:
           | > C++ instead doubled down and added many more ways for
           | implicit conversions to happen.
           | 
           | but also allows you to turn them off for objects, thankfully.
        
       | wakamoleguy wrote:
       | Why are these defined as macros at all? A function call would
       | come with overhead, of course, but wouldn't compilers be able to
       | inline that anyways?
        
         | lifthrasiir wrote:
         | C doesn't have any type-generic function declaration. So any
         | viable solution had to be at least partially powered by a macro
         | and resulting (one-directional) type inference.
        
           | kevin_thibedeau wrote:
           | C11 does with _Generic but it is limited in ways that make
           | min/max implementations flaky.
        
             | pyth0 wrote:
             | Even with _Generic you can't declare generic functions.
             | You'd still need a macro call that uses _Generic to
             | dispatch different implementations depending on the
             | parameter types.
        
               | dwattttt wrote:
               | Generic dispatching all the type combinations (or warning
               | or erroring) wouldn't be a problem in a project the scale
               | of the Linux kernel.
               | 
               | I'm unfamiliar with the incantations needed to try
               | preserve constant expressions though, that might be too
               | much for them.
        
               | lifthrasiir wrote:
               | The concrete problem that the kernel is facing is an
               | exponential growth of macro expansion. Any current
               | solution, safe or not in terms of re-evaluation, needs at
               | least two copies of both arguments to be expanded [1], so
               | expressions like `min(min(a, b), c)` will expand some
               | arguments four times. The growth factor would be much
               | larger than two if the definition wasn't carefully
               | designed to avoid such cases.
               | 
               | [1] `_Generic` also requires at least two because you
               | need one copy to select the generic implementation and
               | another to call it. C23 `typeof` (or the equivalent GNU
               | extension) allows for a compact type tuple matching:
               | inline static int max_int(int x, int y) { return x > y ?
               | x : y; }         inline static unsigned max_uint(unsigned
               | x, unsigned y) { return x > y ? x : y; }         /* ...
               | */              #define MAX(a, b) (_Generic( \
               | (void (*)(typeof(a), typeof(b))) NULL, \             void
               | (*)(int, int): max_int, \             void (*)(unsigned,
               | unsigned): max_uint, \             /* ... */ \
               | default: max_type_error \         ) (a, b))
        
             | kelnos wrote:
             | Also _Generic is intended for a function that takes a
             | single varying type. The kernel's min/max macros allow you
             | to safely mix types.
        
         | ufo wrote:
         | Another issue is that some of these macros are intended to be
         | used in a constant context, such as array dimensions.
        
           | LeifCarrotson wrote:
           | *constant
        
         | olliej wrote:
         | The problem is C lacks an equivalent to C++'s constexpr (or
         | preceding template insanity), so you can't use functions in
         | constant contexts, eg                   struct S {
         | int foo[max(10, 15)];         }
         | 
         | Isn't possible in C, macros are the only option.
         | 
         | So even if you were to try to use _Generic in a macro to handle
         | type correct dispatch you would not be able to use that macro
         | in many of the contexts it is needed.
         | 
         | Honestly constexpr is something that would really help C, and
         | does not need to bring in any other c++ features. Although I
         | guess in this case the lack of the full template and such
         | features set would mean matching the kernel requirements would
         | still require a macro+_Generic to adopt.
        
       | account42 wrote:
       | What C programmers will do to avoid using even a little bit of
       | C++.
        
         | pjmlp wrote:
         | Ever since CFront was born on the same UNIX building at Bell
         | Labs.
        
         | Sharlin wrote:
         | To be fair, it's not like you can just add a "little bit of
         | C++" to the kernel.
        
           | jonathrg wrote:
           | C codebases can often be updated with minor changes to
           | compile with a C++ compiler, after which C++ features can be
           | gradually introduced. Is the Linux kernel different in this
           | regard?
        
             | creeble wrote:
             | Read the LWN comments.
        
               | Groxx wrote:
               | From a moderate skim, I'm not seeing much in there that
               | really addresses this beyond FUD and over-simplification.
               | 
               | Which, I mean... it's the Internet. That's kinda
               | expected. But if there's something specific you're
               | seeing, could you link to it? I'm curious as well what
               | the "stick to C" crowd's reasons are. "C plus this one
               | feature of C++" seems rather defensible at a glance
               | (ignoring the social difficulty in choosing _which_
               | feature), but I 'm sure it's much more complicated than
               | that in practice.
        
               | dzaima wrote:
               | Even if a project can choose some specific feature(s) to
               | switch to C++ for, it'd severely reduce the barrier for
               | adding reliance on more features; why did feature X get a
               | pass, but not this other one? And C++ has a lot of such
               | potential features that are harmless and easy to justify
               | at their best, but can become headaches when used more
               | broadly, requiring everyone and everything to deal with
               | them.
        
               | Groxx wrote:
               | The social aspects are _very_ large and it wouldn 't
               | surprise me at all if that was by far the main reason...
               | but that's much less of an issue in a kernel-like context
               | where there are already oodles of rules beyond "write
               | valid C code". They can and do impose significant
               | limitations on the languages they use, successfully, for
               | decades. Seems like they'd be able to do that with C++
               | too.
        
               | jonathrg wrote:
               | There is a comment purporting to show a difference
               | between compilation speeds in C and C++ which uses
               | iostream for the C++ example, which completely misses the
               | point. Sure C++ has a lot of warts, but in terms of
               | compilation speed it should be completely reasonable to
               | use a few simple template functions.
        
               | Groxx wrote:
               | Yeah, that's the main thing I saw and it's just plain
               | completely wrong. The fact that C++ can _more easily_
               | bloat into large build times, and people frequently make
               | larger-build-time projects in it, implies absolutely
               | nothing about its behavior in replacing simple macros
               | like max /min.
               | 
               | There's ample evidence that it'll build just a fast as C
               | there, so it's not an issue in this context, and that
               | both can build quickly with care. That's kinda the point
               | of C++: you can write plain C code plus [this one thing]
               | and you basically don't pay for the rest, and it
               | generally achieves that.
        
               | jonathrg wrote:
               | They do not address the question at all. Please write an
               | answer yourself.
        
               | wahern wrote:
               | The specific macro discussed in the article is using
               | various GCC builtins to safely support mixed integer
               | types; i.e. failing on unsafe type promotions or
               | coercion, but otherwise working automagically. C++
               | std:min, by contrast, requires all the values to be the
               | same type. AFAIU, to accomplish the same semantics in C++
               | would require either template metaprogramming, or doing
               | something similar to what the current version is doing
               | with macros and GCC builtins. A C++ solution might
               | ultimately be cleaner, but I don't think there's anything
               | in the standard C++ library that is a drop-in
               | replacement.
        
               | creeble wrote:
               | Nor would it perform well during compilation, which is
               | very well discussed in the thread. C++ compilation is
               | slow, like the macro expansion of the C versions of min
               | and max.
               | 
               | It's all in the thread, I don't know how GP missed it.
        
             | jcelerier wrote:
             | $ cd /usr/src/linux         $ rg ' class;'
             | vmlinux.h         8541:struct class;         13515:   long
             | unsigned int class;         16416: unsigned int class;
             | 16917: u8 class;         17351: u8 class;
        
               | jenadine wrote:
               | Yes, with minor changes. A few variables need to be
               | renamed, a few cast need to be added. Some churn for sure
               | on such big codebase, but doable nevertheless. GCC did
               | it, other projects did it, I don't see why the kernel
               | can't.
        
             | samatman wrote:
             | Yes.
             | 
             | https://harmful.cat-v.org/software/c++/linus
        
             | spc476 wrote:
             | At this point, C and C++ are _not_ compatible. Please stop
             | with this  "Oh, just compile C with a C++ compiler." That
             | ship has sailed over twenty years ago with C99. One major
             | difference is designated initializers, which works
             | differently between C and C++ [1]. And C also allows
             | structure literals in function calls:
             | cgci = XCreateGC(                  display,
             | window,                  GCForeground | GCBackground |
             | GCFont,                  &(XGCValues) {
             | .foreground = ccwhite,                    .background =
             | ccblack,                    .font       = cfont->fid,
             | }                );
             | 
             | [1] C++ requires the fields to be initialized in order; C
             | doesn't have this restriction.
        
               | wahern wrote:
               | Compound literals are especially pernicious[1] because
               | GCC and (I think) clang support them in C++ mode, but
               | they have expression lifetime like C++ temporary objects,
               | not block lifetime as in C. That's a guaranteed recipe
               | for dangling pointers and stack smashing/snooping.
               | 
               | [1] From a C++ is just a C superset perspective. In C
               | compound literals are awesome.
        
             | kzrdude wrote:
             | I think the obvious one is that the Linux kernel is no
             | small little project, and any tree-wide change is highly
             | non-trivial. The compressed current source release is 138
             | MB. A 2021/5.11 lines of code figure I found was 30.3
             | million.
             | 
             | It's not impossible, but the Linux kernel is quite a
             | complex project.
        
         | cozzyd wrote:
         | Imagine what the equivalent templated C++ code will expand to!
        
           | OskarS wrote:
           | It will be MUCH less, and much less complex than this.
        
         | alerighi wrote:
         | It would be far easier to add as builtins the features that are
         | missing to GCC than change the language, that would involve
         | rewriting a ton of code (even switching from C to C++ they are
         | not 100% compatible, also, they may introduce bugs difficult to
         | spot cause their incompatibility). The Linux kernel already
         | uses a ton of GCC extensions (even the min/max macros suggested
         | in the article) that is not compatible with other compilers
         | anyway (and I don't see a reason to be, since GCC is the
         | compiler of the GNU project anyway, unlikely to compile the
         | Linux kernel with MSVC, or even I don't see much reasons to use
         | clang anyway).
        
           | gpderetta wrote:
           | > The Linux kernel already uses a ton of GCC extensions
           | 
           | You'll be happy to know that GCC happily compiles C++ then!
           | No need to switch to MSVC.
           | 
           | I'm fact GCC itself successfully switched to C++ from C a few
           | years ago.
        
         | microtherion wrote:
         | To paraphrase Henry Spencer, "Those who dislike C++ are
         | condemned to reinvent it, poorly".
        
         | Am4TIfIsER0ppos wrote:
         | cout << anything << to << avoid << this;
        
         | nialv7 wrote:
         | Or just any other real programming language.
        
       | up2isomorphism wrote:
       | Every time when such thing happens, then it becomes a language
       | suggestion opportunity. But for those who suggest another
       | language, are you going to replace a 50M line code base because
       | of you want have a fancy min / max? I don't think this is a
       | responsible suggestion.
        
         | orf wrote:
         | That's a strawman argument: nobody seriously considers a
         | different language because of a "fancy min/max".
         | 
         | However, hygienic macros that fix entire classes of issues
         | (including this) is a more compelling argument.
         | 
         | Not to say that it makes the case, only that the strawman you
         | wrote is not good.
        
           | tuveson wrote:
           | How would hygienic macros fix this? It seems like the macros
           | were working fine, but the amount of generated code increased
           | compile time significantly. Wouldn't a more sophisticated
           | macro system still generate a bunch of extra code and result
           | in slow compile times? It even seems like the solution was to
           | fall back to "dumb" macros when feasible for compile-time
           | performance reasons.
        
             | tetha wrote:
             | > Wouldn't a more sophisticated macro system still generate
             | a bunch of extra code and result in slow compile times?
             | 
             | Not necessarily.
             | 
             | The preprocessor code here picks up the original source,
             | and blows up the initial code (which is about "min3(long_a,
             | long_b, long_c)") to 47 MB of code. no fancy stuff, just
             | 47MB of C-Code on the disk. That's a lot of code the
             | compiler then has to parse and handle.
             | 
             | If hygienic macros are a first-class citizen in the
             | compiler, the compiler parses the original macro code once
             | and then just modifies it in-memory. There is no reason to
             | write 47MB of code somewhere and read it back, this would
             | just happen as an AST modification in memory.
             | 
             | But that is also a much smaller reason. First-class macros
             | allow the compiler to reason based off of the types and
             | structure of the macro inputs. You don't have to guess if
             | something is constant, bounded, unbounded and such. Strong
             | types can enforce this safely and macros and optimization
             | can use these strong guarantees. And sufficiently strong
             | type information can open doors for far, far more powerful
             | optimizations overall.
             | 
             | Just for the record - I'm fully aware why the kernel is
             | where it is, and why it will stay there, but there is far
             | improved compiler and language theory from there.
        
         | bluedino wrote:
         | I've seen things like Boost included to only use a single
         | function.
        
         | ZoomerCretin wrote:
         | This sounds like a good use case for Zig: great
         | interoperability with C, and support for generics.
        
       | Borg3 wrote:
       | This also shows how programmers sometimes use far too fancy stuff
       | for what they do. If you are doing some intense computation,
       | split it, or do it and later slap sanity check inside. It will be
       | even more readable. If you just play with bunch of vars, sure..
       | min/max macros can be easier to read.
        
       | wood_spirit wrote:
       | Could not the main compilers get involved and add builtins so an
       | ifdef makes the common path on the main compilers like gcc use
       | builtins and the slowdown only hurts those using the less
       | mainstream compilers? If it takes off the other compilers would
       | quickly add the feature.
        
         | sapiogram wrote:
         | What you're suggesting is basically a worse version of adding
         | built-in min() and max() to the C spec. Which, to be fair,
         | would be quite nice, but I guess the working group didn't want
         | it in the standard.
        
           | nullc wrote:
           | Adding a compiler specific builtin is one path for things to
           | get into the language.
        
       | layer8 wrote:
       | This reminds me of how ~25 years ago I wrote little C macro
       | library to perform safe (non-overflowing, and/or saturating)
       | integer arithmetics and comparisons, however the small
       | application I wanted to use it in had the compiler crash after
       | 2-3 hours due to insufficient RAM+swap when compiling a single
       | source file using those macros. It turned out the macro
       | expansions made the translation unit grow to GB size, which must
       | have been 4-5 orders of magnitude over its original size.
        
         | sapiogram wrote:
         | How did that end up happening? Did you define addition
         | recursively or something?
        
           | layer8 wrote:
           | The macros automatically derived the signedness and the
           | minimum and maximum value of the integral types involved, in
           | a way that didn't made platform-specific assumptions like
           | two's complement or no padding bits. Cases like comparing
           | signed long to unsigned long also needed extra logic, due to
           | there being no larger type that encompasses both. I don't
           | remember the details, but it did have a significant number of
           | nested macro invocations.
        
       | usefulcat wrote:
       | > some of the changes to the macros made some developers
       | (including Bergmann) nervous
       | 
       | These macros are now so complex that they're reluctant to touch
       | them. Seems like there is a clear need for some thorough tests
       | here? This is exactly the sort of thing that is eminently
       | testable.
        
         | Vecr wrote:
         | Maybe. Most C code of non-trivial length is UB or at least
         | implementation defined, you really don't want to "tickle"
         | something in a low-level highly used macro.
        
           | usefulcat wrote:
           | Exactly why those macros ought to have tests.
        
             | Vecr wrote:
             | You're exactly right, sorry. I meant that even with tests
             | it's probably too subtle to do the standard test driven
             | design method of programming, you have to be way more
             | careful.
        
       | Joker_vD wrote:
       | (void) (&_x == &_y);
       | 
       | Is this... a check for type-compatibility? I don't think actually
       | produces a compilation error if the types are incompatible.
        
         | cmovq wrote:
         | It produces a warning for incompatible pointer types.
        
           | Joker_vD wrote:
           | Okay, it's better than nothing.
        
             | lokar wrote:
             | Which you can make an error
        
             | mananaysiempre wrote:
             | FWIW, (&_x - &_y) will give you an error instead.
        
       | kibwen wrote:
       | The most pleasant C codebases that I have read essentially banned
       | macros outside of includes, conditional compilation, and named
       | constants. Please just stop trying to use macros to metaprogram
       | in C.
        
       | seanhunter wrote:
       | For everyone with a "why don't they just...?"-type suggestion,
       | it's worth carefully rereading TFA and considering what the
       | macros do now and the problem they are trying to solve.
       | 
       | The macros now do type-safe comparisons that work correctly with
       | combinations of different argument types where this is possible,
       | work in a constant context (eg defining array bounds), work
       | correctly in the face of implicit type coercion and include a
       | 3-way min and max that have these same desirable properties (same
       | as the two way min and max).
       | 
       | The problem(s) are it's a bit slow to compile and the
       | preprocessor expansion (although not necessarily the final
       | generated assembly - didn't see anyone saying that) is a bit
       | bloated.
       | 
       | So when you make a "why don't they just.... ?"-suggestion, make
       | sure your suggestion is at least as good as what they have now in
       | terms of the desirable functionality and correctness and then
       | tackles the actual problems in some way. I'm not sure all of the
       | suggestions I have seen here and in the lwn comments succeed at
       | meeting those two criteria.
        
         | dataflow wrote:
         | I have a "why don't they just" question: if they're going to
         | rely on compiler intrinsics anyway, why don't they just
         | implement the whole darn thing in the compiler and do whatever
         | they want there? If you're going to marry your code to the
         | compiler, at least take full advantage of it?
        
           | seanhunter wrote:
           | I think that's an excellent suggestion tbh (and could meetmy
           | two criteria as well) and someone may well do that.
           | 
           | The thing they want seems perfectly reasonable to me and
           | wouldn't only benefit the kernel.
        
           | starspangled wrote:
           | Assuming good faith, they don't do that because they are
           | kernel developers not compiler developers, and they want it
           | to build on the compilers that real systems have at hand.
           | 
           | If somebody proposed a new extension and got llvm and gcc to
           | both implement it today, they would still need something to
           | work on old compilers. The oldest GCC supported by Linux is
           | 10 years old nearly.
        
             | dataflow wrote:
             | But for older compilers they already have something that
             | compiles correctly for valid inputs, no? They don't need
             | e.g. the type-safety-check nonsense for that. The newer
             | compilers will still catch mistakes in the usage sites via
             | the intrinsics.
        
               | starspangled wrote:
               | For today's compilers they have something that compiles
               | very slowly and they want the type safety checks because
               | those are the ones the kernel developers use. That
               | answers the original question doesn't it?
               | 
               | If a new compiler extension was proposed and implemented
               | and released in both llvm and gcc, some years after that
               | they could drop support. But there would be no real
               | imperative to drop support early since they will already
               | have developed some code that works okay on those
               | toolchains.
        
               | dataflow wrote:
               | > For today's compilers they have something that compiles
               | very slowly and they want the type safety checks because
               | those are the ones the kernel developers use. That
               | answers the original question doesn't it
               | 
               | No, the point was for today's compilers they could have
               | something that compiles quickly and does everything they
               | want.
        
       | metrognome wrote:
       | There are plenty of projects smaller than the Linux kernel that
       | have developed and employed DSLs (to varying degrees of success,
       | I'll grant). I wonder, are there any languages out there designed
       | specifically for kernel programming?
       | 
       | Given the number of preprocessor hacks used in the kernel, and
       | the amount of GCC-specific behavior that the codebase depends on,
       | it seems like they are already halfway there.
        
         | jakobson14 wrote:
         | Honestly, they'd probably be better off if they ditched all the
         | sed/awk/macro BS and just went back to bash scripts (or
         | perl/TCL, if you don't like weird syntax issues) that spat out
         | C code. Rust saw the writing on the wall and implemented proc
         | macros.
         | 
         | Stop using tiny hammers and get a big one.
        
       | 38 wrote:
       | what a pathetic language. modern languages have a fully generic
       | max function, thats also type safe
       | 
       | https://godocs.io/builtin#max
        
       | mastax wrote:
       | My question is, why isn't there a `min() and `max()` in the
       | standard library? Even accepting C's philosophy of a minimalist
       | stdlib, these feel like uncontroversial functionality to me. TFA
       | shows there's enough complexity involved in doing it correctly
       | that it makes sense to provide an implementation rather than have
       | everyone write the same often-subtly-incorrect macros. They could
       | use a `__builtin_cmp(type, a, b)` which can use the correct type-
       | casts and prevent double-evaluation without needing any macro
       | weirdness.
        
       ___________________________________________________________________
       (page generated 2024-08-09 23:02 UTC)