Global variables / performance / data passing

I think you may have a hard time avoiding const.

Closures are wonderful, but, if you define closures as global variables:

const a = 1
foo(x,a) = a*x
fuu = (x) -> foo(x,a)
fii(x) = foo(x,a)

They are just that, variables, whose types cannot be inferred.

julia> @code_warntype fuu(2) # good
Body::Int64
1 ─ %1 = Main.a::Core.Compiler.Const(1, false)
│   %2 = (Base.mul_int)(%1, x)::Int64
└──      return %2

julia> @code_warntype fii(2) # good
Body::Int64
1 ─ %1 = Main.a::Core.Compiler.Const(1, false)
│   %2 = (Base.mul_int)(%1, x)::Int64
└──      return %2

julia> bar(x) = fuu(x) # trying to use fuu from another module
bar (generic function with 1 method)

julia> @code_warntype bar(2) # yikes
Body::Any
1 ─ %1 = (Main.fuu)(x)::Any
└──      return %1

(Note that you can just copy and paste the above code into the REPL; Julia will automatically delete the julia> s.)

You could do

julia> mutable struct Foo{T} <: Function
           a::T
       end

julia> (f::Foo)(x) = f.a * x

julia> const foo_instance = Foo(1)
(::Foo{Int64}) (generic function with 1 method)

julia> foo_instance(2)
2

julia> @code_warntype foo_instance(2)
Body::Int64
1 ─ %1 = (Base.getfield)(f, :a)::Int64
│   %2 = (Base.mul_int)(%1, x)::Int64
└──      return %2

julia> bar2(x) = foo_instance(x)
bar2 (generic function with 1 method)

julia> @code_warntype bar2(2)
Body::Int64
1 ─ %1 = Main.foo_instance::Core.Compiler.Const(Foo{Int64}(1), false)
│   %2 = (Base.getfield)(%1, :a)::Int64
│   %3 = (Base.mul_int)(%2, x)::Int64
└──      return %3

julia> foo_instance.a = 4
4

julia> bar2(2)
8

But then your program is still dependent on global state. Common blocks are bad.
They make managing things more complicated. Especially multithreading, if you ever plan on using @threads.

2 Likes