Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@inbounds loses expression value #9774

Closed
ArchRobison opened this issue Jan 14, 2015 · 9 comments
Closed

@inbounds loses expression value #9774

ArchRobison opened this issue Jan 14, 2015 · 9 comments

Comments

@ArchRobison
Copy link
Contributor

It appears that wrapping an expression in @inbounds causes its value to be lost.

julia> function bar(x,j)
           @inbounds x[j]
       end
bar (generic function with 1 method)

julia> println(bar(Int[1,2,3],2))
nothing

This seems surprising. If there's no easy way to fix the surprise, let's at least document it.

@eschnett
Copy link
Contributor

I think you can fix this by writing @inbounds in front of the function declaration (@inbounds function ...).

I think that you could change the implementation of @inbounds to use an anonymous function instead. The @par macros etc. do this. I don't know how this efficient is, though. This would make the @inbounds macro translate the code into something like

begin
    boundscheck(:yes);
    r = (()->x[j])()
    boundscheck(:pop);
    r
end

This has the disadvantage that it would "eat up" return statements. That is, code such as

if cond
   @inbounds return x[j]
end

would be translated into a sequence such as the one above, where the return statement does not end the current function any more.

The underlying problem here is that @inbounds tries to insert a statement (boundscheck(:pop)) into the code that is not executed at run time; instead, it is only a marker for the compiler at compile time. This seems brittle, and goes against the grain of Julia. For example,

boundscheck(:yes)
return 5
boundscheck(:pop)

is actually sensible code, and the boundscheck(:pop) must not be eliminated.

@JeffBezanson
Copy link
Member

I forced everything into statement position to defer possible evaluation-reordering problems.

Yes, this is a messy compile-time feature. I think an efficient run-time version of this is extremely hard! Obviously anything like global boundscheck=false is a non-starter. I question whether a run-time version of this (even if efficient) is even desirable. This is only for performance, and hence, unfortunately, an undisciplined, extra-linguistic hack.

@ArchRobison
Copy link
Contributor Author

Could @inbounds act like @fast_math, and replace calls to getindex and setindex with getindex_fast and setindex!_fast? Or does that just confuse other consumers of the parse tree?

@simonster
Copy link
Member

Ref #8227 for further discussion of possible reimplementations of @inbounds.

@ivarne
Copy link
Member

ivarne commented Jan 24, 2015

Closing, as everything here is covered by #8227.

Currently the original function has to be written

function bar(x,j)
    @inbounds return x[j]
end

but as all statements in Julia return a value (or nothing::Void), this is pretty unintuitive.

@ivarne ivarne closed this as completed Jan 24, 2015
@eschnett
Copy link
Contributor

Actually, there is one statement that does not return anything: return. typeof(return 0) yields an error.

@jiahao
Copy link
Member

jiahao commented Jan 24, 2015

There might be a misunderstanding here. typeof(return 0) is a syntax error. return still returns nothing.

julia> f() = return
f (generic function with 1 method)

julia> typeof(f())
Void

@eschnett
Copy link
Contributor

I was comparing the return statement other statements. All other statements can be used in a context such as x = (STATEMENT), only return cannot. My guess is that the reason is that, since return will leave the current function, the assignment x=... would never be reached, so it's turned into a syntax error to avoid confusion.

However, it is exactly this property of the return statement that makes it difficult to implement @inbounds returning a value. The implementation of @inbounds needs to insert a statement after the end of the region which it modifies, and thus it needs to capture the value calculated by this region -- and this is not possible because a sequence such as

disable_checks
result = (ORIGINAL_CODE)
enable_checks
result

is ill-formed if ORIGINAL_CODE is a return statement.

However, @inbounds is probably going to be implemented in a different manner (similar to `@fastmath), and this issue won't be relevant then.

@jiahao
Copy link
Member

jiahao commented Jan 24, 2015

Ah, thanks for the explanation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants