Am Dienstag, dem 21.07.2026 um 20:34 +0200 schrieb Arsen Arsenović: > Hi Martin, > > Martin Uecker <[email protected]> writes: > > > you seem to take it for granted that it templates improve > > maintainability, but in my personal experience the opposite > > is true. > > No, my hunch that the (currently pre-draft) proposal would improve > maintainability rests on the experience in the JavaScript and Python > cases, in both of which the introduction of gradual typing systems > massively increased the ability to detect bugs ahead of runtime, > approach new code, and modify old code. It does not rest on the > presence of templates. > > Templates are merely a required means by which a similar type system can > be implemented for GCCs 'tree', in GCCs implementation language - C++.
So it *does* rest on the use of templates. > > The statement "templates improve maintainability" is not really a > sensible position to hold, just like "templates reduce maintainability". > > Templates are merely a means of writing generic functions or data > structure. Doing so obviously can be both an improvement in > maintainability and a hindrance to it. > > Which it is depends on the template. I am not sure. Although C++ tries very hard, writing an abstraction using C++ templates is not the same as improving a language itself, so I am not sure one can compare this to TS or Python. > > > > We already have a relatively small base of active developers, and a yet > > > smaller base of reviewers. > > > > I am not sure that adding more complexity would help with this. > > Exactly how almost no TypeScript user needs to learn how to hack the > TypeScript compiler, and how almost no Python user needs to learn how to > hack Mypy et al, and how most C users don't need to learn to hack GCC to > write C, almost no GCC developers will need to look into the tree type > checker. > > That's not to say they shouldn't. There's just no reason to presume > they often will. One would have to learn what it does, and this alone is another obstacle. This is why when I encounter some new project, I much prefer ancient C code compared to some modern C++ cod.e The ancient C code may be horrible, but it is relatively easy to understand what it does, and then one can start to clean it up. For a C++ project, one has to first learn and understand all the fancy abstractions someone had cleverly introduced, and they are never the same, and when they are bad, it is often very painful to correct. You want to introduce such an abstraction. And I can appreciate how it would use of tree code more type safe. I just do not think it is worth it in this form. > > > Speaking for me, I would not be able to contribute anymore if build > > times triple. It is already a pain today and I have fairly fast > > machines available to me. > > I certainly wouldn't expect build times to triple from such a change ;) Well, this was a response to your comment. But just to give you one example how bad it can get, I recently removed as single cuda file with C++ templates from one of my projects, as this single file took as long to compile as the the other 450 c-files in the project. > > Iteration time for me does not tend to be too excessive, even when I'm > just using a core i7-8650u or ryzen 7 3800x. I'd not call them weak, > but they certainly aren't top-notch. > > > > > > > That said, there's no reason why we couldn't make it possible to > > > essentially disable the 'tree' type checking. I don't think that's > > > worth it, frankly, and I think it adds to the combinatorial explosion > > > that is GCC build-time configuration, but we could explicitly make it so > > > that 'ttree' with, say, checking disabled, compiles down to: > > > > > > template<typename...> using ttree = tree; > > > > > > Hence, short-circuiting all or nearly all cost. > > > > If it was my call, I would start by introducing simple wrapper types > > for expressions, types, statements, .. and also only for some parts > > of the code where this makes sense. This would add static > > type checking and readability (!) without adding any cost in terms of > > compilation time. > > This runs into the problem of there being three million existing lines > of code. The frontier between "new-style" code and "old-style" code > would need to be very explicit, and ergo, difficult to move. I don't think this is a problem. One can just start to introduce such types in a small scale and grow the parts that use them. > > This also runs into the problem of the countless cases in GCC where a > function can legitimately accept more than one type of tree, say A and > B. There's no way, in C and C++, to declare a variable/parameter of > type A|B, which is something that does happen in GCC, even where for A > and B the lowest common supertype is 'tree' (using this common supertype > also permits a tree 'C' to be passed, ergo under-constraining). I don't thinks is a problem either. Code that is so generic would just continue to use tree as a generic type. > > This, also, sounds to me exactly like what Jakub was worried about in > the other subthread. Yes. Also I think there would be cases where the code is not generic. At least for the C FE a lot of functions work on only one kind of tree. > On readability: I'm not sure what you imagine, but there's no reason > readability ought to be an issue. > > In each location where 'tree' is listed as a parameter or declared as a > local, one would also list the expected tree codes or similar, just as > they do today (except in the declaration instead of in an assert below a > declaration, which seems to me like a strict improvement, as it moves > relevant information from function bodies to function signatures, > without relying on bit-rotting comments; where there isn't such a check, > 'auto' suffices). An assertion also does not rely on comments. The thing is that a function which works for three random tree codes is weird anyhow. Types should carry some useful semantics, and then they help readability when expressed explicitely. foo(tree< one_of<FUNCTION_DECL, PLUS_EXPR> > x) May be amazing technology, but just tells me the function should not exist in this form. So it only helps writing bad code. foo(expression *e) on the other hand, is very readable and would tell me something useful. > Checks-and-uses of TREE_CODEs would also need to become (explicit) > fallible conversion functions, i.e. > > if (TREE_CODE (t) == A) use t; > > ... becomes: > > if (auto tA = try_as_tree_or_whatever<A> (t)) use tA; > > ... or such. (I'd have preferred if the 'tA' could shadow 't', but > unfortunately if it were to shadow 't' in the then branch, it'd also > have to shadow it - a lot less usefully - in the else branch; that's not > an issue in this trivial example but is in general) Thi could look almost identical in C if (auto e = cast_down(expression, t)) ... if one wanted to. > > > > When I was initially thinking about this problem, I did put this down as > > > a design goal for a different reason: showing that GCC would compile to > > > the same machine code anyway even with this typechecking added, thus > > > making it easier to approve the patch series. > > > > > > I'm now of the opinion that this original goal of mine isn't worth it, > > > especially as we could use 'ttree' to provide member accessors to > > > increase the level of assistance that can be provided by editors and/or > > > decrease verbosity (discovering what the correct accessor is for some > > > part of some tree_code is a bit of an art even today; this also did come > > > up in the C++ NAS patch, where TREE_LANG_FLAG_... was being used > > > incorrectly - this, too, could've been prevented, but luckily Thomas > > > caught it in review). > > > > > > Of course, the latter is also impossible in case we do this short > > > circuiting for sake of compilation time. > > > > > > I really do wish I had a partially done example, so that we could do > > > some empirical study on this. But, alas… > > > > > > > I agree that catching errors at compile time is good, but in > > > > many cases this can be achieved in C just as well. I usually find > > > > that people underestimate what can be done in C alone. Clearly, C++ > > > > allows you to do more sophisticated typing (I wrote for some time > > > > expression-template libraries before I decided that this just takes > > > > too much of my time). Being clever with C++ templates is - in my > > > > experience - usually a bad trade-off as the cost in complexity and > > > > compilation times exceeds the improvements in type safety you can > > > > achieve in this way. > > > > > > Please implement a conversion operator in C. Adjusting 'tree' is a > > > non-starter without those. > > > > In my experience, having implicit conversions makes it harder > > to read and maintain code. > > Indeed, I agree. Implicit conversion are in general not good. But > user-defined implicit conversions are the only way to implement gradual > typing in a statically typed language, or at least the only one that > comes to mind. > > We need some way to tell the $host compiler "okay, this conversion is > sound", "okay, this conversion *may* be sound, but perform this > assertion at runtime", "okay, this conversion is never sound, fail to > compile". > > The only way to do that are user-defined conversions, and generic ones > at that. > > A user-defined conversion template, at compile-time, knows the start and > end type, and ergo has sufficient information to implement custom typing > rules like those. I do not understand why the conversions need to be implicit. I have C code with cast_down, cast_up macros, where cast_down checks the dynamic type. > > > > > > > Then, we'll also need packs of types and of heterogeneous values that > > > can be manipulated at compile-time, to represent sum types. > > > > > > > I agree, but the untypedness of tree is not the fault of C... > > > > > > I agree, but I never said that it was. Just that we can't fix it in C > > > in a viable way. > > > > > > > ... and changing this would not require switching to C++. > > > > > > It would. There is no method by which we can implement correct rules > > > for gradual typing in C. Especially not earlier versions of C. > > > > Gradual typing can also be done in C. For example, here > > is a variadic type: https://godbolt.org/z/d8djYsMx5 > > > > (And in this example, the compiler completely removes all > > overhead for the dynamic type checking and devirtualizes all > > functions) > > This response makes me think that we're talking past each-other. > > What you showed seems analogous to our starting point today, not the end > point I'd like to see. > > Indeed, considering 'variadic*' analogous to 'tree' in your example > would, in terms of type safety, be exactly equivalent to what we have > today (well, except that "variadic*" can be anything, and trees can > "only" be anything packaged in a tree node). Yes, the variadic would be correspond to a generic type such as tree. But the point is that you can cast from/to a specific static type. This is what I would call gradual typing. > > What I want is to be able to specify "okay, this 'variadic*' [or tree] > can only be X, Y or Z, or ..." in a declaration, and have the compiler > verify that as well as it can, while still being somewhat compatible > with existing code. This serves the purpose of self-documentation and > type safety. (note that we're going from "tree" -> "one of ... trees", > rather than going from a concrete type to a less specific one). The core feature you want to have is the one_of<X, Y, Z> type, but I am not entirely sure why. > It'd be nice if I could, say, convert the C FE to what I'm imagining in > time for Cauldron, but I fear that may be optimistic. > > Doing so would eliminate all ambiguities and perhaps even alleviate > concerns. Or the opposite. I would rather convert the C FE to C, which would be a good idea for many reasons, including being more attractive to C programmers, but also to exercise language interoperability in GCC itself. > > Also, of course, what the correct thing to do here is can only be > learned through practice - abstract ideas come from practice and must > return to practice. I'm sure I'm overlooking something in abstract > thinking; updating actual code (a "mere" 100k LoC frontend) would mean > that practical considerations have to be taken into account. > > But, I certainly won't be able to work on this during work hours, and > most of my "free" time is anything but.. so I can't be sure that I can > finish it by then. As I said, it's not simple. > > (also, should 'variadic' be called variadic? and not 'any' or > 'variant'? I may be missing something, but I do not understand the > naming. This also isn't ISO C, whereas this can be done in ISO C++) It uses GNU extensions but I think it could be done in ISO C as well. Yes, it would be better to call it variant. > > > > > > > > It would simply require to introduce C types for each specific node > > > > type. > > > > > > The "simply" here is doing a lot of heavy lifting. There's nothing > > > "simple" about changing *the* core type of a 3 million LoC codebase. > > > > > > > > As I said, gradual typing is the only alternative to dynamic typing > > > possible for GCC today. > > > > > > C lacks user-defined conversions; this alone makes it impossible to > > > implement gradual typing in C. > > > > You can implement conversions just fine, you can just not have > > implicit conversions. > > By conversion I'm of course referring to user-defined implicit > conversions. User-defined explicit conversion are just unary functions, > and obviously C has those. > > C does have too many implicit conversions already. I am fine with the implicit conversions C has as there is a sufficiently simple rule I learned once and that I can remember. I am not too excited about programmer-defined implicit conversions. Martin
