Why doesn't this return statement return?

When attempting to return out of a function’s loop, the following return statement instead behaves like a break statement: breaking out of the loop but not returning from the function.

function mweret()
	# write temp file
	fn = "temp.txt"
	write(fn, "1\n2\n3\n2\n1\n")
	
	# read temp file
	nLine = 0
	linePrev = ""
	open(fn, "r") do f
		while !eof(f)
			line = readline(f, keep=true)
			print(line)
			nLine += 1
			if linePrev > line
				println("non-increasing order at line $nLine")
				close(f)
				rm(fn)
				return nothing
			end
			linePrev = line
		end
	end # open
	
	println("POST LOOP!")
end

In contrast, when looping through similar elements but in a vector, the return statement behaves as expected: breaking out of the loop AND returning from the function.

function mweret2()
	iPrev = 0
	nElement = 0
	for i in [1; 2; 3; 2; 1]
		println("$i")
		nElement += 1
		if iPrev > i
			println("non-increasing order at element $nElement")
			return nothing
		end
		iPrev = i
	end
	println("POST LOOP!")
end

The open(...) do notation defines a new anonymous function in the indented block, which is then passed to open as a first parameter. Therefore, the return inside the block exits the anonymous function back into mweret.

In the second function mweret2, the return exits mweret2 function as expected.

TL;DR The do notation is a confusing at first (for me too), but then becomes natural and useful.

9 Likes

Easy to fix:

function mweret()
        # write temp file
        fn = "temp.txt"
        write(fn, "1\n2\n3\n2\n1\n")

        # read temp file
        nLine = 0
        linePrev = ""
        open(fn, "r") do f
                while !eof(f)
                        line = readline(f, keep=true)
                        print(line)
                        nLine += 1
                        if linePrev > line
                                println("non-increasing order at line $nLine")
                                break
                        end
                        linePrev = line
                end
        end # open
        
        println("POST LOOP!")
end

In my application, I want to break out of the loop AND avoid the post loop processing AND abort the application. So my simple fix was to use the error function.

You could also let the anonymous function return something informative like a Symbol or Bool flag. E.g.

function mweret(seq)
    # write temp file
    fn = tempname()
    write(fn, join("$x\n" for x in seq))

    # read temp file
    nLine = 0
    linePrev = ""
    open(fn, "r") do f
        while !eof(f)
           line = readline(f, keep=true)
            print(line)
            nLine += 1
            if linePrev > line
                println("non-increasing order at line $nLine")
                return false  # Indicates we stopped early
                # Cleanup is handled by open(::Function, ...) itself
            end
            linePrev = line
        end
        return true  # We went through the entire file
    end || return  # (or exit() instead of return if you want to terminate the application)
    println("POST LOOP!")
end
julia> mweret([1, 2, 3, 4, 5])
1
2
3
4
5
POST LOOP!

julia> mweret([1, 2, 3, 2, 1])
1
2
3
2
non-increasing order at line 4
1 Like