Function definition inside let-block impacting performance?

This already happens whenever you conditionally assign an anonymous function to a single identifier:

if cond;  f=x->x  else  f=x->x^2  end  

the idea here is just to extend this to local named functions, and to use similar semantics that we use for local constants, if we can find agreeable rules for that.

The difference when you conditionally define a named function at global scope to be one thing or another is that there aren’t two types under the hood; only one version is compiled. But this is under the hood anyway; most users don’t notice.

The idea here is to treat local named functions as local consts with regard to how their initial declarations should interact with conditionals, and add some minor additional rules to handle how methods can be added (i.e. only allow methods to be added within the same branch where the function is declared).

For the general case, I agree. For example, a must certainly be in a Box{Any} here:

f, g = let a = 0.5
    _f(x) = (a = a * x; a)
    _g(x) = (a = a / x; a)
    _f, _g
end

This is discussed in the first “difficulty” of idea 3 here. We can annotate the types of either x or a to fix this, which of course limits the usefulness of lowering to use type inference here.

However, there are many “special cases” where closures either mutate a capture independent of their arguments, or capture something which is mutated in their parent scope—if lowering had access to return types it could correctly parameterize the box. Here’s a tricky example of this.

Ah, good point. Even if Iseven and Isodd access a shared storage element, if I construct an array of Isevens and an array of Isodds this information will be copied twice.

If I’m not mistaken, this suffers from the same issue.