Can I make a Function Call Itself?

Hi everyone.
This might be a REALLY silly question, but I wonder if it is possible.

I am making this function Set_Up(). It is design to load all other functions in my code, force precompilation, load global variables, etc.

Because sometimes something goes wrong I have:

try

Do a lot of things

catch e

    printstyled(" An error ocurred.",color=:red)
    printstyled("Please run Set_Up() again.",color=:red)
    sleep(1)

end

I wonder if inside the catch I can tell the function to run itself again. Something like:

try

Do a lot of things

catch e

    printstyled(" An error ocurred.",color=:red)
    printstyled("Set_Up() will run again after 1 second.",color=:red)
    sleep(1)
    Set_Up()
end

Thanks in advance!

Yes. I actually implemented this for a network handshaking function a few years ago. I did also have a “retries” variable that increments on each restart, with provision to exit if too many retries. This kept the function from being stuck too long (in practice the restart hardly ever happened, without there being a network glitch).

There should be no difficulty in practice.
For example, the following function will run successively once being called.

function hello()
  println("hello")
  hello()
end

But I guess finding the reason that leads to “something goes wrong” makes more sense here.

This is called recursion, an important technique in computer science. Note that each call allocates on the stack, so if you go too deep you will get a stack overflow (which gave its name to a famous website).

julia> counter = 0;

julia> function f()
           global counter += 1
           f()
       end;

julia> f()
ERROR: StackOverflowError:
Stacktrace:
 [1] f()
   @ Main ./REPL[12]:2
 [2] f() (repeats 79980 times)
   @ Main ./REPL[12]:3

julia> counter
130830

So f was able to call itself recursively 130830 times before the stack grew too big.

3 Likes

Well, don’t keep us in suspense forever, what is the name of this famous website?

3 Likes

Hmm Hi guys.
I tried this… but my code just gets into a loop and never actually finishes… Not sure why.
I wonder if there is a line to kill the current execution and then call the function again.

What goes wrong is that some libraries in the OS need to be called twice (GMT package) for them to work. This is a problem of the package … and I can’t fix it hehehe.

Can’t tell if joking… https://stackoverflow.com/

2 Likes

With recursion, at some point you have to return anything which is not the function call to ensure that the recursion terminates. You do this via a conditional like “if counter > 100” and return nothing for that case.

For some kind of repeated call, you can also use retry (from HTTP if I’m not mistaken)

Can any one give me an example to make sure that the recursion happens only once?

function myrecursion(depth::Int,arg)
    if depth>=2
        return nothing 
    else 
        println(arg)
        @info("myrecursion was called (depth=$(depth))")
        return myrecursion(depth+1,arg)
    end
end

myrecursion(0,"foo")
0

3 posts were split to a new topic: Does Julia have tail call optimization?

I’m late to the party, but I want to point out that AFAIK the better practice would be to use a loop as opposed to recursion. Something like:

function Try_Set_Up()
  try
    # Do setup stuff
  catch e
    # Report error
    return false
  end
  return true
end

function Set_Up_Keep_Trying()
  setupsuccess = false
  while !setupsuccess
    setupsuccess = Try_Set_Up()
    if !setupsuccess
      sleep(1)
    end
  end
end

Or if you wanna be slick:

function Set_Up_Keep_Trying()
  while true
    Try_Set_Up() ? break : sleep(1)
  end
end

To limit the number of iterations:

function Set_Up_Keep_Trying(; attempts=10)
  setupsuccess = false
  for i in 1:attempts
    if Try_Set_Up()
      setupsuccess = true
      break
    else
      sleep(1)
    end
  end
  setupsuccess || println("Setup failed after $attempts attempts")
end
3 Likes

Great! Thank @jeffreyesun