-
Notifications
You must be signed in to change notification settings - Fork 149
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
incorrect pure
annotations
#95
Comments
Hi Jameson, Thanks for the information. I'm still trying to read between the lines here - is this related to worlds / JuliaLang/julia#265? As in, the system cannot update functions when a new I'm only asking because I was a little surprised to see "any function which can be overloaded should not be marked If this is related to enforcing consistent worlds, would it be fundamentally a bad thing if Two more questions: Can I redefine an Finally, with "you should trust that inference can figure out that returning a constant has no side-effects" the reason I use |
It's not specifically related to worlds, although it wasn't as interesting (observable) when everything was treated incorrectly.
right. If the method shouldn't be overloaded (including anything that it needs to call), then it's not incorrect. But quite often those functions are simply returning constants or static-parameters, in which case the annotation is unnecessary.
yes,
Of course. If you don't see that happen somewhere, file a bug report.
It's a simplistic recursive algorithm right now (i.e. a function is effect-free if it doesn't do anything that has a side-effect). And yes allocation of immutables and Types is effect-free. |
Cool. Thanks for the clarifications. I was planning to redo a lot of core stuff in this package in light of the improved subtype algorithm, since it "breaks" my current constructors and so-on (which are a mess of trial-and-error to work around the kinks in the old subtype algorithm), so I'll revisit the
Is there a simple list of side-effects/effect-free operations? I'm guessing this list of effect-free is quite short:
I would be natural for users to assume that EDIT: sorry that code snippet was munged. |
That method is effect-free and would get constant-folded. It's purity is debatable, although generally the distinction is unnecessary in practice. |
But it isn't constant folded, in the sense that inference wraps it as
True in most cases. I seem to have a habit of pushing the boundaries... :) The above example has been annoying for both |
inference is not the same as constant-folding. but yes, I wouldn't be surprised if you needed to have a |
Indeed. :) |
|
That should be fine - I think "specialised" would be more accurate than "overloaded" - ie a signature that is more specific than a previous, pure one. And even then, it depends on the order of definition and usage. The point being the "world" (fix for JuliaLang/julia#265) is not updated for pure functions as a "dependency edge" is not generated so the compiler can go back and insert the specialised result. Paraphrasing Jameson, needing to do that would defeat the purpose of pureness, where you are asserting a transformation can be made at any stage without ill effect. In practice, if all your specializations are defined before they are used anywhere, then you shouldn't run into inconsistencies. I.e. It's the same rules of v0.5 where the compiler might not use the latest version of functions in all cases (but v0.5 is still a useful language). Furthermore, here, I think if a user creates a new subtype of The worlds would become inconsistent if, after using the package for a while, a user decided to change the size definition for a Of course, we should investigate which pure annotations can be removed without screwing performance (inferrability), but I haven't got around to it yet. (Does what I wrote make sense, @Jameson?) |
helpful |
That sounds mostly right. The only part I would suggest is wrong is:
@JeffreySarnoff in your example, it appears that that declaration is in fact valid, although it is generally better to let the compiler (which can also observe this fact without too much difficulty) handle this particular optimization, so I would suggest that it is unnecessary and thus "improper". |
I'd love to see a simple practical example where using |
I'd like to see a simple (yet not likely discovered and made as optimized without @pure) practical example where for one function with two distinct signatures of the same arity (one which is subsumptive of another). |
This is not not necessarily true / sufficient for a function to be pure, since the compiler works to specialize for classes of types, not just concrete types. Hence the properties of any element of that class can't be changed / overridden for any method marked I didn't record specifics, but I opened this issue because someone asked me why For practical examples of where people have run into this, see any of the duplicate issues associated with JuliaLang/julia#265. |
OK, I hadn't seen this before. I'm still not clear of exactly what situations this occurs in (specifics would be welcomed, but we can work with this). I suppose the ridiculous proportion of generated functions in this package would have sheltered us somewhat... One use case for julia> using StaticArrays
julia> f() = Val{size(SMatrix{3,3})}
f (generic function with 1 method)
julia> f()
Val{(3,3)}
julia> @code_warntype f()
Variables:
#self#::#f
Body:
begin
return Val{(3,3)}
end::Type{Val{(3,3)}}
julia> size2{N,M}(::Type{SMatrix{N,M}}) = (N,M)
size2 (generic function with 1 method)
julia> g() = Val{size2(SMatrix{3,3})}
g (generic function with 1 method)
julia> g()
Val{(3,3)}
julia> @code_warntype g()
Variables:
#self#::#g
Body:
begin
return (Core.apply_type)(Main.Val,$(QuoteNode((3,3))))::Type{_<:Val}
end::Type{_<:Val} Another current use case is the reverse, to try to get input constants into type variables. In I suppose we could change the API in both cases to use the |
I assume you must have had something before As for making tuples of parameters, that works just fine for me: julia> struct T{A, B} end
julia> f{A, B}(::Type{T{A, B}}) = (A, B)
f (generic function with 1 method)
julia> g() = Val{f(T{1, 2})}
g (generic function with 1 method)
julia> @code_typed g()
CodeInfo(:(begin
return $(QuoteNode(Val{(1, 2)}))
end))=>Type{Val{(1, 2)}} Currently the only generic advice I can offer is my trailing type parameters package (https://github.com/vtjnash/ComputedFieldTypes.jl) to store the computation results combined with function boundaries such that the computation is memoized over the inner loop. I realize though that allowing any sort of computed field types (aka JuliaLang/julia#18466) also ensures that it'll be heap allocated, so not a huge win here. |
Thanks for the advice.
Nope, StaticArrays was authored specifically for v0.5. These packages (ImmutableArrays, FixedSizeArrays and StaticArrays) are typically using the latest-and-greatest to maximise performance and genericism and compatibility with Given this history, we always expected to have to rewrite parts of the package to take advantage of v0.6 (or it would seem likely that someone else would!). Were there any compiler optimizations in v0.5 (specializations for non-concrete types) which these overloaded
So, you are saying that if
That is a (very nice!) improvement in v0.6. My result was for v0.5. It's truly wonderful that creating tuples is now pure (i.e. constant propagates), and I see also indexing them is also pure:
This was a really tricky thing to work around in v0.5... and was one of the reasons for not keeping the sizes as type vars as they were in FixedSizeArrays. |
See #105. We still use |
Possibly related to #106, but that seems unlikely. |
I think this has been fixed for a while, but I'm closing this with #121 |
The
Base.@pure
annotation means "the result of this function is not dependent on any part of the system other than the arguments". Therefore, any function which can be overloaded should not be marked@pure
, as inference will not be able to get the correct answer. In general, you should trust that inference can figure out that returning a constant has no side-effects, and permit it to still construct its method dependency edges (e.g. avoid annotating anything as@pure
)The text was updated successfully, but these errors were encountered: