Skip to content

Do not capture recursive local function's self-identifier (to avoid box) #53295

Open
@uniment

Description

@uniment

Consider the function:

julia> fibby = let
           fib(n) = n1 ? n : fib(n-1)+fib(n-2)
       end
(::var"#fib#3") (generic function with 1 method)

This is approximately equivalent to:

struct var"#fib#3" <: Function
    fib :: Core.Box
end
(fib::var"#fib#3")(n) = n1 ? n : fib.fib.contents(n-1)+fib.fib.contents(n-2)
fibby = let 
    fib = var"#fib#3"(Core.Box())
    fib.fib.contents = fib
end

The fact that the recursive function boxes its reference to itself here is obviously inefficient and undesirable.

My understanding is that fib's reference to itself must be boxed because of the rule that whenever a capture is or can be assigned after its closure's instantiation, then that capture must be boxed: obviously this is usually a good rule, since the capture's new value could otherwise be unknown to the closure during the closure's lifetime. Here, lowering detects that the local fib identifier's first and only assignment occurs after the local functor object's instantiation, so following this rule, it boxes fib.

However, I propose we carve an exception to this rule for the function's own identifier: if the function's local identifier is only ever assigned to the functor object itself and has no other syntactical assignments anywhere, then it is obvious that the value this identifier is assigned to is always known to the closure throughout its lifetime—it is itself! Thus, with such an exception made, I would hope that lowering could be changed such that the code above would instead become approximately equivalent to:

struct var"#fib#3" <: Function end
(fib::var"#fib#3")(n) = n1 ? n : fib(n-1)+fib(n-2)
fibby = let 
    fib = var"#fib#3"()
end

(this proposal solves #47760 but more elegantly so I'm closing that issue)

Metadata

Metadata

Assignees

No one assigned

    Labels

    compiler:loweringSyntax lowering (compiler front end, 2nd stage)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions