On Wed, Jul 22, 2026 at 12:15:44AM +0200, Arsen Arsenović wrote:
> Interesting, I thought that this specific example was overly favourable
> to the idea of in-language gradual typing.
>
> It's the trivial case where one check is replaced by another check whose
> result also gets encoded in the type system/current scope.
>
> Such a case - converting a check into a check + extra information in the
> variable type pretty much mechanically - seemed like strictly an
> improvement to me.
>
> In the languages I was mentioning as a reference, as well as in some
> others like Kotlin, the check alone would mean that 't' gets a narrower
> type definition in the scope of the then stmt, but this isn't possible
> in C++, sadly.
>
> Note that, at least initially, calling a function that receives a typed
> tree with an untyped tree should be possible (and result in the compiler
> automatically adding a runtime check), and calling a function that
> receives an untyped tree with a typed tree should probably always be
> possible. This is indeed what would allow for a gradual change.
>
> What was problematic in that example?
All of it?
Ugly syntax, having to type more than before (and thus having to deal with
line wrapping more as well), having to introduce new vars for the dyn_cast
way and being tied to if statements.
With TREE_CODE/gimple_code/GET_CODE etc., one can choose coding style which
is most appropriate for a particular case. If statement or several of
those, switch case, tables indexed by the codes with extra data.
One switch is much nicer than having to add 50
if (auto a = dyn_cast <...> (t))
...
else if (auto b = dyn_cast <...> (t))
...
else if (auto c = dyn_cast <...> (t))
...
not to mention that if you e.g. leave out default: the compiler can
complain about missing new cases etc.
But, if you switch on TREE_CODE/gimple_code/GET_CODE etc., if some APIs
enforce this static typing mess, you need to add a lot of as_a <...>
(something). In my experience, in most cases it is in most cases just a
single use per the corresponding switch case or dyn_cast etc.
If you want to add temporaries in a switch, you then need to wrap
code after each case with {} because C++ only allows jumping across
vacuous initializations (so auto can't be then really used for the
temporaries otherwise and one has to separately declare and initialize those
otherwise).
We have is_a.h in GCC since 2012, I see around 1550 as_a, 1010 dyn_cast
and 720 is_a uses, several of us had to type a few hundreds of those during
that time. I don't remember a single case where this mess would have
prevented introducing a bug in gcc for me. I vaguely remember hundreds
of cases where runtime checking diagnosed bugs, many of those when I was
writing my patches, significantly more afterwards reported in bugzilla.
So, to me all this is extra pain for absolutely no gain.
The thing I like least from these is as_a. Some APIs (e.g. gimple) have
overloads for both gimple * and some particular derived class from that,
gcall *, gswitch *, etc., while others have just the latter, if one uses
switch on the gimple_code, then the common thing is as_a, typically just
once, to make those APIs happy.
Jakub