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++. 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. >> 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. > 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 ;) 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. 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). This, also, sounds to me exactly like what Jakub was worried about in the other subthread. 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). 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) >> 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. >> >> 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). 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). 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. 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 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. -- Arsen Arsenović
signature.asc
Description: PGP signature
