Help needed: Building an intuitive understanding of closures, scoping and type-stability

A globally scoped function accessing a global variable is not generally considered a closure; many languages with the former lack the latter. i is bound to the only closure in your examples.

This doesn’t work because C isn’t const. It didn’t matter for the @code_warntype C(... line because neither the callable nor arguments need to be assigned to const variables for the runtime dispatch and type inference, in fact dispatch is done with respect to the callable and the arguments.

The wider compiler is pretty complex, but you can definitely follow the type inference part, occasionally even do better. Unfortunately you don’t have direct control over the type inference process, so when that happens, the most you can do is manually annotate some variables to give the compiler more hints.

It doesn’t do value semantics, it’s still capturing a variable, only the let st = st part made a new st variable that is local to the let block and never reassigned. If you had reassigned it, the compiler can’t infer it anymore even if all reassignments occurred prior to capturing and didn’t even change the type; that is one example of how you could do type inference better than the compiler. The only way to “capture by value” is to directly store the value in a struct instance, which you can make callable.

If you want to make a global variable inferrable, the easiest way is to make it const, promising it’ll never be reassigned, so it’ll always have the same type. The 2nd easiest way is annotating the variable with a concrete type, much like how you annotate struct fields for type stability. Reassignment works if the values can be automatically converted to the annotated type, which isn’t necessarily concrete; if you have some unexpected type inference problems check if you unintentionally annotated an abstract type. There isn’t a provided way to automatically annotate the concrete type from the right-hand value, but there’s a macro with an atypical use of the local statement that accomplishes that. Unlike a const variable whose value can often be inlined, the typed global variable’s value is retrieved through a couple dereferences, but that bit of overhead is well worth the type stability.

1 Like