# Output arguments of functions must be pre-defined? (Julia version 1.8.2)

**URL:** https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321
**Category:** New to Julia
**Tags:** question
**Created:** [November 16, 2022, 1:59am UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321 "2022-11-16T01:59:40Z")
**Posts on this page:** 18
**Page:** 1

<div class="post-metadata">

### Author: ![mmv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mmv/32/26323_2.png) [@mmv](https://discourse.julialang.org/u/mmv)
#### Post date: [November 16, 2022, 1:59am UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/1 "2022-11-16T01:59:40Z")

</div>

- The documentation states explicitly that “The default behavior in Julia when types are omitted is to allow values to be of any type. Thus, one can write many useful Julia functions without ever explicitly using types.” (see [Types · The Julia Language](https://docs.julialang.org/en/v1/manual/types/), start of third paragraph).

- Indeed, the input arguments of a function do not need to be defined explicitly before calling the function, and this lack of requirement allows the function to be used with different argument types:

```julia
julia> function f1(x, y)
       x + y
       end
f1 (generic function with 1 method)

julia> f1(1, 2)
3

julia> f1(1.2, 3.4)
4.6

```

- However, this flexibility apparently does not apply to output arguments:

```julia
julia> function f2(x, y, z)
       z = x + y
       return 0 # template for an error code
       end
f2 (generic function with 1 method)

julia> f2(1, 2, z)
ERROR: UndefVarError: z not defined
Stacktrace:
 [1] top-level scope
   @ REPL[32]:1

```

even though it should be easy to infer the type of z from those of x an y.

- And it looks like considering an output argument as an optional argument with a pre-assigned type and default value is not acceptable either:

```julia
julia> function f3(x, y, z::Float64 = 0.0)
       z = x + y
       return 0
       end
f3 (generic function with 2 methods)

julia> f3(1, 2, z)
ERROR: UndefVarError: z not defined
Stacktrace:
 [1] top-level scope
   @ REPL[34]:1

```

- Question: Why is it mandatory to pre-define the types of output arguments since they are computed inside the function? Output arguments are frequently used in C, FORTRAN, IDL and other such languages: it is cumbersome to require users to pre-define the type of output arguments when calling external functions in those languages (specifically ccall), especially because this requires a rather intimate knowledge of the exact requirements of those external functions, as well as a translation table between types in those two languages (as described in [Calling C and Fortran Code · The Julia Language](https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/#mapping-c-types-to-julia))…

Thanks for clarifying those points.

---

<div class="post-metadata">

### Author: ![benninkrs](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/benninkrs/32/3191_2.png) [@benninkrs](https://discourse.julialang.org/u/benninkrs)
#### Post date: [November 16, 2022, 2:21am UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/2 "2022-11-16T02:21:52Z")

</div>

In your examples `z` is not an output, it is an input. The error you see is because you are trying to call your functions with an input variable that you have not assigned any value to.

---

<div class="post-metadata">

### Author: ![PeterSimon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petersimon/32/25193_2.png) [@PeterSimon](https://discourse.julialang.org/u/PeterSimon)
#### Post date: [November 16, 2022, 2:22am UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/3 "2022-11-16T02:22:00Z")

</div>

Your errors have nothing to do with output types. There is no variable named `z` in the global scope to pass to your functions as an input argument. You’d get the same error just typing `z` at the REPL.

---

<div class="post-metadata">

### Author: ![mmv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mmv/32/26323_2.png) [@mmv](https://discourse.julialang.org/u/mmv)
#### Post date: [November 17, 2022, 9:46pm UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/4 "2022-11-17T21:46:14Z")

</div>

@benninkrs and @PeterSimon: Thanks for taking the time to answer. I’m coming from the IDL world, where the following sequences of operations are perfectly legal (in this case on a MacBook Pro):

```julia
IDL> cd, "/Users/michel/IDLWorkspace/Default"
IDL> .RESET_SESSION
IDL> spawn, 'ls out_*.pro'
out_arg1.pro
IDL> spawn, 'cat out_arg1.pro'
FUNCTION out_arg1, x, y, z
   z = x + y
   RETURN, 0
END
IDL> .compile -v '/Users/michel/IDLWorkspace/Default/out_arg1.pro'
% Compiled module: OUT_ARG1.
IDL> res = out_arg1(1, 2, z)
IDL> print, res
       0
IDL> print, z
       3
IDL> res = out_arg1(2.2, 4, z)
IDL> print, z
      6.20000
IDL> res = out_arg1("Hello ", "World!", z)
IDL> print, z
Hello World!

IDL> spawn, 'cat out_arg2.pro'
FUNCTION out_arg2, x, y, z
   IF (y GT 0) THEN BEGIN
      z = x + y
      RETURN, 0
   ENDIF ELSE BEGIN
      z = "Second argument of out_arg2 cannot be negative."
      RETURN, 1
   ENDELSE
END
IDL> .compile -v '/Users/michel/IDLWorkspace/Default/out_arg2.pro'
% Compiled module: OUT_ARG2.
IDL> res = out_arg2(2.2, 4, z)
IDL> print, z
      6.20000
IDL> res = out_arg2(2.2, -4, z)
IDL> print, z
Second argument of out_arg2 cannot be negative.

```

So, in IDL, the type and value of a function argument do not need to be defined in advance, and can even change at run time…

My current focus is on understanding the underlying logic of Julia rather than fixing a particular code. Specifically, I wish to clarify rules for either properly setting up the arguments of `ccall`s to external libraries, or for correctly converting codes from IDL to Julia.

Looking at the definition of f2 in an earlier message, it looks like the REPL does not object to those statements. It is only when attempting to execute the f2 function that the error occurs (or is reported). So is it correct to say that

- ALL arguments of Julia functions are considered input arguments (in the sense that they must have a specific type and value by runtime)?
- Outputs are meant to be transferred to the calling environment through the returned value (or tuple)?
- To the extent the values of some of the input arguments can be changed by the function, those arguments behave like output arguments in other languages?

Thanks for your thoughts on these questions. Michel.

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [November 17, 2022, 9:52pm UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/5 "2022-11-17T21:52:25Z")

</div>

> [@mmv](#):
>
> ```julia
> IDL> print, z
> 3
> 
> ```

IDL is wild LOL.

what does it do if you use `z` before assignement inside `out_arg1`? for example

```julia
FUNCTION out_arg1, x, y, z
   print, z
   z = x + y
   RETURN, 0
END

```

also I don’t like how Z leaks into the global scope in IDL

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [November 17, 2022, 9:53pm UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/6 "2022-11-17T21:53:37Z")

</div>

you should forget IDL, Julia does things very differently for variable scoping:

```julia
julia> function f(z)
           z = 3
           return z
       end
f (generic function with 1 method)

julia> f(2)
3

julia> z
ERROR: UndefVarError: z not defined

julia> z = 0
0

julia> f(z)
3

julia> z
0

```

---

<div class="post-metadata">

### Author: ![mmv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mmv/32/26323_2.png) [@mmv](https://discourse.julialang.org/u/mmv)
#### Post date: [November 17, 2022, 10:07pm UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/7 "2022-11-17T22:07:42Z")

</div>

Well… it’s precisely because I know that IDL is a comparatively old language that I am learning a new one, and that I am asking those questions!

I can’t safely switch to Julia until I fully understand and master the intricacies of properly translating IDL codes to Julia… This is not a matter of liking or disliking a particular language, but rather of moving rationally and methodically, to avoid breaking tens of thousands of perfectly working lines of code through a botched translation. So my questions still stand.

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [November 17, 2022, 10:16pm UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/8 "2022-11-17T22:16:15Z")

</div>

> [@mmv](#):
>
> It is only when attempting to execute the f2 function that the error occurs (or is reported).

The problem has nothing to do with `f2` really. The problem is that you are trying to do something with `z` (passing it to a function) that is not defined. This is exactly the same error:

```julia
julia> z
ERROR: UndefVarError: z not defined

julia> z = 1
1

julia> z
1

```

I would recommend spending some time with the Julia manual, for example  
[Functions · The Julia Language](https://docs.julialang.org/en/v1/manual/functions/) and [Scope of Variables · The Julia Language](https://docs.julialang.org/en/v1/manual/variables-and-scoping/) might particularly be useful reading.

[Values vs. Bindings: The Map is Not the Territory · John Myles White](https://www.johnmyleswhite.com/notebook/2014/09/06/values-vs-bindings-the-map-is-not-the-territory/) is also a good post that I usually links to people being a bit confused about variables and objects in Julia.

I think those parts answer the questions you have.

---

<div class="post-metadata">

### Author: ![mmv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mmv/32/26323_2.png) [@mmv](https://discourse.julialang.org/u/mmv)
#### Post date: [November 17, 2022, 10:27pm UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/9 "2022-11-17T22:27:59Z")

</div>

Thanks a lot, @kristoffer.carlsson: your constructive input is very much appreciated.

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [November 17, 2022, 10:40pm UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/10 "2022-11-17T22:40:15Z")

</div>

If you really wanted to return something through an argument, it would need to look something this:

```julia
julia> function f2!(x, y, z)
           z[] = x + y
           return 0
       end
f2! (generic function with 1 method)

julia> z = Ref{Any}()
Base.RefValue{Any}(#undef)

julia> f2!(1, 2, z)
0

julia> z[]
3

```

I’m not sure why you would need to do this though.

The exclamation mark is a convention to indicate that you’re modifying one of the arguments.

If you need to output two arguments, the idiomatic way would be

```julia
function foo2(x, y)
    if y > 0
        z = x + y
        return 0, z
    else
        z = "Second argument of out_arg2 cannot be negative."
        return 1, z
    end
end

julia> foo2(1, 2)
(0, 3)

julia> status, z = foo2(1, 2)
(0, 3)

julia> status
0

julia> z
3

julia> status, z = foo2(1, -2)
(1, "Second argument of out_arg2 cannot be negative.")

julia> status
1

julia> z
"Second argument of out_arg2 cannot be negative."

```

Of course if you wanted to report an error, you probably should throw an `ArgumentError`:

```julia
julia> function bar2(x, y)
           y > 0 || throw(ArgumentError("Second argument of bar2 cannot be negative"))
           x + y
       end
bar2 (generic function with 1 method)

julia> bar2(1, 2)
3

julia> bar2(1, -2)
ERROR: ArgumentError: Second argument of bar2 cannot be negative
Stacktrace:
 [1] bar2(x::Int64, y::Int64)
   @ Main .\REPL[25]:2
 [2] top-level scope
   @ REPL[27]:1

julia> status, z = try
           0, bar2(1,2)
       catch err
           1, err
       end
(0, 3)

julia> status
0

julia> z
3

julia> status, z = try
           0, bar2(1,-2)
       catch err
           1, err
       end
(1, ArgumentError("Second argument of bar2 cannot be negative"))

julia> status
1

julia> z
ArgumentError("Second argument of bar2 cannot be negative")

```

---

<div class="post-metadata">

### Author: ![mmv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mmv/32/26323_2.png) [@mmv](https://discourse.julialang.org/u/mmv)
#### Post date: [November 17, 2022, 11:14pm UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/11 "2022-11-17T23:14:18Z")

</div>

Thanks @mkitti: What I gather from this discussion is that all arguments of Julia functions must be either fully defined (type and value) or represented by an appropriate place holder like Ref{T}() before calling the function.

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [November 17, 2022, 11:37pm UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/12 "2022-11-17T23:37:16Z")

</div>

IDL has an implicit pass-by-reference convention.

Julia uses [pass-by-sharing](https://docs.julialang.org/en/v1/manual/functions/#Argument-Passing-Behavior).

> [@mmv](#):
>
> What I gather from this discussion is that all arguments of Julia functions must be either fully defined (type and value) or represented by an appropriate place holder like Ref{T}() before calling the function.

Basically, at call time, roughly yes. There is no implicit pass-by-reference in Julia.

Let me try to challenge this just so we have sufficient understanding.

```julia
julia> function f2!(x, y, z)
           z[] = x + y
           return 0
       end
f2! (generic function with 1 method)

julia> function g(x,y)
           z = Ref{promote_type(typeof(x), typeof(y))}()
           f2!(x, y, z)
           z[]
       end
g (generic function with 1 method)

julia> g(1, 2)
3

julia> g(π, 1im)
3.141592653589793 + 1.0im

```

In using `f2!` within `g`, we have not explicitly defined a type or value for `x` and `y`. However, when `g` is actually invoked, we will know the types and values of `x`, `y`, and `z`. That is the types can be inferred at the last minute.

The macro `@code_warntype` will show you how types are inferred when you the call the function `g`:

```julia
julia> @code_warntype g(1, 2)
MethodInstance for g(::Int64, ::Int64)
  from g(x, y) in Main at REPL[47]:1
Arguments
  #self#::Core.Const(g)
  x::Int64
  y::Int64
Locals
  z::Base.RefValue{Int64}
Body::Int64
1 ─ %1 = Main.typeof(x)::Core.Const(Int64)
│ %2 = Main.typeof(y)::Core.Const(Int64)
│ %3 = Main.promote_type(%1, %2)::Core.Const(Int64)
│ %4 = Core.apply_type(Main.Ref, %3)::Core.Const(Ref{Int64})
│ (z = (%4)())
│ Main.f2!(x, y, z)
│ %7 = Base.getindex(z)::Int64
└── return %7

julia> @code_warntype g(π, 1im)
MethodInstance for g(::Irrational{:π}, ::Complex{Int64})
  from g(x, y) in Main at REPL[47]:1
Arguments
  #self#::Core.Const(g)
  x::Core.Const(π)
  y::Complex{Int64}
Locals
  z::Base.RefValue{ComplexF64}
Body::ComplexF64
1 ─ %1 = Main.typeof(x)::Core.Const(Irrational{:π})
│ %2 = Main.typeof(y)::Core.Const(Complex{Int64})
│ %3 = Main.promote_type(%1, %2)::Core.Const(ComplexF64)
│ %4 = Core.apply_type(Main.Ref, %3)::Core.Const(Ref{ComplexF64})
│ (z = (%4)())
│ Main.f2!(x, y, z)
│ %7 = Base.getindex(z)::ComplexF64
└── return %7

```

---

<div class="post-metadata">

### Author: ![mmv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mmv/32/26323_2.png) [@mmv](https://discourse.julialang.org/u/mmv)
#### Post date: [November 17, 2022, 11:58pm UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/13 "2022-11-17T23:58:02Z")

</div>

@mkitti: Thanks a lot; that’s interesting and enlightening.  
@kristoffer.carlsson: Thanks for pointing out the web page of John Myles White, which is indeed very useful.

---

<div class="post-metadata">

### Author: ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)
#### Post date: [November 18, 2022, 12:11am UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/14 "2022-11-18T00:11:15Z")

</div>

There is no such thing in Julia as an “output argument”.

Therefore, everything you pass into a Julia function must have a value.

If that value is mutable, you may mutate it within the Julia function.

If you mutate the value of an argument by convention you end your function name with an exclamation point `!`

Hope that helps

---

<div class="post-metadata">

### Author: ![mmv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mmv/32/26323_2.png) [@mmv](https://discourse.julialang.org/u/mmv)
#### Post date: [November 18, 2022, 12:13am UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/15 "2022-11-18T00:13:05Z")

</div>

@dlakelan: Yes, it does. Thanks for your input.

---

<div class="post-metadata">

### Author: ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)
#### Post date: [November 18, 2022, 12:26am UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/16 "2022-11-18T00:26:48Z")

</div>

Note that Julia passed arguments by “sharing” but a Julia function can not change the binding of a variable that the caller has.

```julia
function outer()
   z=1
   inner!(z)
   return z
end

function inner!(z)
   z = 2 # this should compile to a noop
   return 100
end

```

`outer()` should return 1 (I’m on my phone so can’t verify). The reason is that in the `inner!` function the assignment just changes the binding of the totally independent variable z within the inner! function. Numbers are not mutable. When you pass a mutable struct the outer function and the inner function are both “pointing to” or “bound to” the same struct. When the inner function mutates the struct the outer function will see the mutated state of the struct because it is bound to the same object as the one the inner function sees.

---

<div class="post-metadata">

### Author: ![mmv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mmv/32/26323_2.png) [@mmv](https://discourse.julialang.org/u/mmv)
#### Post date: [November 18, 2022, 12:32am UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/17 "2022-11-18T00:32:46Z")

</div>

@dlakelan: Indeed:

```julia
julia> function outer()
          z=1
          inner!(z)
          return z
       end
outer (generic function with 1 method)

julia> function inner!(z)
          z = 2 # this should compile to a noop
          return 100
       end
inner! (generic function with 1 method)

julia> outer()
1

```

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [November 18, 2022, 9:57am UTC](https://discourse.julialang.org/t/output-arguments-of-functions-must-be-pre-defined-julia-version-1-8-2/90321/18 "2022-11-18T09:57:07Z")

</div>

> [@mmv](#):
>
> ```julia
> julia> function inner!(z)
> z = 2 # this should compile to a noop
> return 100
> end
> inner! (generic function with 1 method)
> 
> ```

It does compile to a no-op.

```julia
julia> @code_llvm inner!(5)
; @ REPL[1]:1 within `inner!`
define i64 @"julia_inner!_136"(i64 signext %0) #0 {
top:
  ret i64 100
}

```
