Limitations to the fix of #265?

Are these things still supposed to happen after #265 was fixed?

Fine:

               _
   _       _ _(_)_     |  A fresh approach to technical computing
  (_)     | (_) (_)    |  Documentation: https://docs.julialang.org
   _ _   _| |_  __ _   |  Type "?help" for help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 0.6.0-rc1.0 (2017-05-07 00:00 UTC)
 _/ |\__'_|_|_|\__'_|  |  
|__/                   |  x86_64-linux-gnu

julia> Base.promote_rule(::Type{Float64}, ::Type{Float32}) = Float32
WARNING: Method definition promote_rule(Type{Float64}, Type{Float32}) in module Base at float.jl:359 overwritten in module Main at REPL[1]:1.

julia> 1.0 * 1.0f0
1.0f0

julia> 1.0f0 * 1.0
1.0f0

Not fine:


               _
   _       _ _(_)_     |  A fresh approach to technical computing
  (_)     | (_) (_)    |  Documentation: https://docs.julialang.org
   _ _   _| |_  __ _   |  Type "?help" for help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 0.6.0-rc1.0 (2017-05-07 00:00 UTC)
 _/ |\__'_|_|_|\__'_|  |  
|__/                   |  x86_64-linux-gnu

julia> 1.0 * 1.0f0
1.0

julia> Base.promote_rule(::Type{Float64}, ::Type{Float32}) = Float32
WARNING: Method definition promote_rule(Type{Float64}, Type{Float32}) in module Base at float.jl:359 overwritten in module Main at REPL[2]:1.

julia> 1.0 * 1.0f0
1.0

julia> 1.0f0 * 1.0
1.0f0

In theory this could happen if there is a missing dependency edge (just a random thought - do these get populated for inlined constants like the type coming from promote_type?)

This kind of thing can happen with @pure functions (which don’t support this kind of updating, or sub-specialization for that matter) but I would suggest it’s a bug if there are no pure or generated functions involved. Maybe it is worthwhile to raise an issue on github?

cc @jameson

Thanks. There’s a good deal of @_pure_meta in the promote machinery, so I guess that would explain it.

Yep, apparently evaluation of @pure functions doesn’t create back-edges:

julia> @Base.pure foo() = Float64
foo (generic function with 1 method)

julia> bar() = convert(foo(), 1)
bar (generic function with 1 method)

julia> bar()
1.0

julia> foo() = Int
foo (generic function with 1 method)

julia> bar() # still uses old foo() output
1.0

julia> bar() = convert(foo(), 1) # redefine to enforce compilation
bar (generic function with 1 method)

julia> bar()
1

julia> foo() = Float64
foo (generic function with 1 method)

julia> bar() # uses new foo() as it wasn't @pure when bar was compiled
1.0

Looks issue-worthy to me, even if it is not too important and might sit there for a while.

To be clear - the fact that pure functions don’t create back edges is well understood by the Julia maintainers (for instances, Jameson Nash took lead on implementeing both pure functions and the 265 fix).

The way forward here might be to remove the pure annotations surrounding promote_type and replace them with inlines. Assuming this doesn’t slow anything down!

AFAICT @pure was seen as a crutch while the long term plan is to support automatic and robust constant propagation through (provably) “effect free” functions during inference, so that pure annotations are unnecessary (though don’t trust me as I may have misunderstood this). For the moment, only use them when you know definitions they depend on won’t ever change.

2 Likes