# Function type signature

**URL:** <https://discourse.julialang.org/t/function-type-signature/43101>\
**Category:** General Usage\
**Created:** [July 15, 2020, 3:41am UTC](https://discourse.julialang.org/t/function-type-signature/43101 "2020-07-15T03:41:32Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![pauljurczak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pauljurczak/32/921_2.png) [@pauljurczak](https://discourse.julialang.org/u/pauljurczak)\
**Post date:** [July 15, 2020, 3:41am UTC](https://discourse.julialang.org/t/function-type-signature/43101/1 "2020-07-15T03:41:32Z")

</div>

I defined two methods of a function, which I thought will have different type signatures:

```julia
foo((a, b)) = print(a, "--", b)
foo(a) = print(a)

```

but I’m getting:

```julia
julia> methods(foo)
# 1 method for generic function "foo":
[1] foo(a) in Main at REPL[13]:1

```

instead of expected two methods:

```julia
foo(::Any)
foo(Tuple{::Any, ::Any})

```

Why is that? Also, why the listing is different with a single method (`foo(a)`) vs. multiple methods (`foo(::Any)`)?

When I add:

```julia
foo(t::Tuple{Any, Any}) = print(t[1], "----", t[2])

```

I get:

```julia
julia> methods(foo)
# 2 methods for generic function "foo":
[1] foo(t::Tuple{Any,Any}) in Main at REPL[20]:1
[2] foo(::Any) in Main at REPL[17]:1

```

but when I add:

```julia
foo((a, b)::Tuple{Any, Any}) = print(a, "---", b)

```

it redefines the last method and shows:

```julia
julia> methods(foo)
# 2 methods for generic function "foo":
[1] foo(::Tuple{Any,Any}) in Main at REPL[23]:1
[2] foo(::Any) in Main at REPL[17]:1

```

so the type signature `foo(t::Tuple{Any,Any})` was redefined by `foo(::Tuple{Any,Any})`. Why a slightly different notation?

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [July 15, 2020, 3:49am UTC](https://discourse.julialang.org/t/function-type-signature/43101/2 "2020-07-15T03:49:21Z")

</div>

> [@pauljurczak](#):
>
> `foo((a, b)) = print(a, "--", b)`

It does _look_ like this might restrict the input types of `foo`, but if you try it out you’ll find that this method still matches any arguments. It will simply try to unpack whatever value you pass in, and it will throw an error if that cannot be done. For example:

```julia
julia> foo((a, b)) = @show a b
foo (generic function with 1 method)

julia> foo((1, 2)) # a tuple
a = 1
b = 2
2

julia> foo([1, 2]) # an array
a = 1
b = 2
2

julia> foo(1 => 2) # a pair
a = 1
b = 2
2

julia> foo(1) # a value which cannot be unpacked
ERROR: BoundsError: attempt to access Int64
  at index [2]

```

The `(a, b)` unpacking syntax is _not_ a type restriction on the input, and therefore it does not create a separate method from any other `foo(a)` or `foo(a::Any)`.

---

<div class="post-metadata">

**Author:** ![pauljurczak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pauljurczak/32/921_2.png) [@pauljurczak](https://discourse.julialang.org/u/pauljurczak)\
**Post date:** [July 15, 2020, 4:01am UTC](https://discourse.julialang.org/t/function-type-signature/43101/3 "2020-07-15T04:01:43Z")

</div>

> [@rdeits](#):
>
> The `(a, b)` unpacking syntax is _not_ a type restriction on the input

Thank you. I was just going to post my surprise at:

```julia
julia> foo(1)
ERROR: BoundsError: attempt to access Int64
  at index [2]

```

but now I see that `foo((a, b))` redefined `foo(a)`. Is there an explanation of rationale behind this design choice somewhere?

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [July 15, 2020, 4:34am UTC](https://discourse.julialang.org/t/function-type-signature/43101/4 "2020-07-15T04:34:53Z")

</div>

[https://docs.julialang.org/en/v1/manual/functions/#Argument-destructuring-1](https://docs.julialang.org/en/v1/manual/functions/#Argument-destructuring-1)

---

<div class="post-metadata">

**Author:** ![pauljurczak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pauljurczak/32/921_2.png) [@pauljurczak](https://discourse.julialang.org/u/pauljurczak)\
**Post date:** [July 15, 2020, 4:40am UTC](https://discourse.julialang.org/t/function-type-signature/43101/5 "2020-07-15T04:40:47Z")

</div>

It explains the syntax, but not `foo((a, b))` redefines `foo(a)` design choice.

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [July 15, 2020, 4:50am UTC](https://discourse.julialang.org/t/function-type-signature/43101/6 "2020-07-15T04:50:55Z")

</div>

I take this statement:

> [@](#):
>
> If a function argument name is written as a tuple (e.g. `(x, y)` ) instead of just a symbol, then an assignment `(x, y) = argument` will be inserted for you

as implicitly meaning that `foo((a,b)) = print(a, "--", b)` is equivalent to:

```julia
function foo(argument)
    (a, b) = argument
    print(a, "--", b)
end

```

And that explains why it redefines `foo(a)`.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [July 15, 2020, 4:53am UTC](https://discourse.julialang.org/t/function-type-signature/43101/7 "2020-07-15T04:53:01Z")

</div>

I think the best way to understand the design choice is to try to write the type restriction that you want `f((a,b))` to convert to. It would need to include 2 element arrays tuples and iterables, despite that 2 of the 3 of those don’t have their length as part of their type.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [July 15, 2020, 4:53am UTC](https://discourse.julialang.org/t/function-type-signature/43101/8 "2020-07-15T04:53:15Z")

</div>

> [@pauljurczak](#):
>
> It explains the syntax, but not `foo((a, b))` redefines `foo(a)` design choice.

What signature would you want this method to have? You haven’t constrained it’s input type at all, you just told julia to unpack the argument into two variables `a` and `b`.

---

<div class="post-metadata">

**Author:** ![pauljurczak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pauljurczak/32/921_2.png) [@pauljurczak](https://discourse.julialang.org/u/pauljurczak)\
**Post date:** [July 15, 2020, 4:57am UTC](https://discourse.julialang.org/t/function-type-signature/43101/9 "2020-07-15T04:57:38Z")

</div>

> [@Mason](#):
>
> What signature would you want this method to have?

I expected `foo(Tuple{::Any, ::Any})` as I mentioned in the top post

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [July 15, 2020, 5:01am UTC](https://discourse.julialang.org/t/function-type-signature/43101/10 "2020-07-15T05:01:57Z")

</div>

I guess what’s unclear to me is that you seemed to also be expressing surprise at this:

> [@pauljurczak](#):
>
> When I add:
> 
> ```julia
> foo(t::Tuple{Any, Any}) = print(t[1], "----", t[2])
> 
> ```
> 
> I get:
> 
> ```julia
> julia> methods(foo)
> # 2 methods for generic function "foo":
> [1] foo(t::Tuple{Any,Any}) in Main at REPL[20]:1
> [2] foo(::Any) in Main at REPL[17]:1
> 
> ```
> 
> but when I add:
> 
> ```julia
> foo((a, b)::Tuple{Any, Any}) = print(a, "---", b)
> 
> ```
> 
> it redefines the last method and shows:

What you found is that julia only cares about what’s on the right hand side of `::` for the purposes of dispatch. The left hand side is just about the naming of variables.

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [July 15, 2020, 5:04am UTC](https://discourse.julialang.org/t/function-type-signature/43101/11 "2020-07-15T05:04:28Z")

</div>

> [@heliosdrm](#):
>
> is written as a tuple (e.g. `(x, y)` ) instead of just a symbol

Note that the documentation says “If a function argument name _is written as a tuple_ (e.g. `(x, y)` ) instead of just a symbol” (emphasis added), instead of “if it is a tuple”. So, as @Oscar_Smith has explained, with that syntax you can actually use multiple types of arguments, i.e. it should be considered as `Any`.

---

<div class="post-metadata">

**Author:** ![pauljurczak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pauljurczak/32/921_2.png) [@pauljurczak](https://discourse.julialang.org/u/pauljurczak)\
**Post date:** [July 15, 2020, 5:10am UTC](https://discourse.julialang.org/t/function-type-signature/43101/12 "2020-07-15T05:10:46Z")

</div>

> [@Mason](#):
>
> julia only cares about what’s on the right hand side of `::` for the purposes of dispatch

Thank you. This should find its way into the manual. It is the simplest answer to my question.

Can you comment on:

```julia
[1] foo(t::Tuple{Any,Any}) in Main at REPL[20]:100:

```

vs.

```julia
[1] foo(::Tuple{Any,Any}) in Main at REPL[23]:100:

```

I this case, Julia cared a little bit about what is on the left side of `::`.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [July 15, 2020, 5:17am UTC](https://discourse.julialang.org/t/function-type-signature/43101/13 "2020-07-15T05:17:43Z")

</div>

> [@pauljurczak](#):
>
> I this case, Julia cared a little bit about what is on the left side of `::` .

Methods have the same signature. Julia just captures the names of arguments for pretty printing in things like `methods`, but whether or not you name an argument, it matches in exactly the same way.

---

<div class="post-metadata">

**Author:** ![pauljurczak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pauljurczak/32/921_2.png) [@pauljurczak](https://discourse.julialang.org/u/pauljurczak)\
**Post date:** [July 15, 2020, 5:23am UTC](https://discourse.julialang.org/t/function-type-signature/43101/14 "2020-07-15T05:23:56Z")

</div>

> [@Mason](#):
>
> Julia just captures the names of arguments for pretty printing

Is it consistent, though?

```julia
foo(a) = print("-", a)
foo(t::Tuple{Any, Any}) = print(t[1], "----", t[2])
......
julia> methods(foo)
# 2 methods for generic function "foo":
[1] foo(t::Tuple{Any,Any}) in Main at REPL[4]:1
[2] foo(a) in Main at REPL[1]:1

```

Why not `foo(a::Any)` in the second line?

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [July 15, 2020, 5:27am UTC](https://discourse.julialang.org/t/function-type-signature/43101/15 "2020-07-15T05:27:12Z")

</div>

Ah, maybe I’m misunderstanding you a little. We just use `foo(a)` to implicitly mean `foo(x::Any)`. The `::Tuple{Any, Any}` is important because it tells you there are two elements. It could be `NTuple{2, Any}` I suppose.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [July 15, 2020, 5:31am UTC](https://discourse.julialang.org/t/function-type-signature/43101/16 "2020-07-15T05:31:54Z")

</div>

By the way, with MLStyle.jl it’s possible to make custom destructuring syntax that’s a bit more powerful than Julia’s and automatically constraints types.

```julia
using MLStyle, ExprTools

macro destruct(fdef)
    d = splitdef(fdef)
    dargs = Tuple(deepcopy(d[:args]))
    d[:args] = map(1:length(d[:args])) do i
        arg = d[:args][i]
        @match d[:args][i] begin
            :($_ :: $T) => :($(gensym("arg$i")) :: $T)
            :( :: $T) => :($(gensym("arg$i")) :: $T)
            Expr(:tuple, names...) => :($(gensym("arg$i")) :: Tuple)
            Expr(:vect, names...) => :($(gensym("arg$i")) :: Vector)
            Expr(:hcat, names...) => :($(gensym("arg$i")) :: Array)
            Expr(:vcat, names...) => :($(gensym("arg$i")) :: Array)
            Expr(:call, T, names...) => :($(gensym("arg$i")) :: $T)
            _ => :($(gensym("arg$i")) :: Any)
        end
    end 
    d[:body] = :($(@ __MODULE__ ).@match ($(d[:args]...),) begin ($(dargs...),) => $(d[:body]) end)
    out = esc(combinedef(d))
end

struct Foo
    x::Int
    y::String
end

@as_record Foo

```

```julia
@destruct function f([a, b], Dict("one" => Dict("two" => c)), Foo(d, e)) where {T}
    (a, b, c, d, e)
end

f([1, 2], Dict("one" => Dict("two" => "boo")), Foo(1, "hi"))

#+RESULTS:
: (1, 2, "boo", 1, "hi")

```

```julia
methods(f)

#+RESULTS:
: # 1 method for generic function "f":
: [1] f(arg1::Array{T,1} where T, arg2::Dict, arg3::Foo) where T in Main

```

---

<div class="post-metadata">

**Author:** ![pauljurczak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pauljurczak/32/921_2.png) [@pauljurczak](https://discourse.julialang.org/u/pauljurczak)\
**Post date:** [July 15, 2020, 5:36am UTC](https://discourse.julialang.org/t/function-type-signature/43101/17 "2020-07-15T05:36:38Z")

</div>

> [@Mason](#):
>
> We just use `foo(a)` to implicitly mean `foo(x::Any)`

This is a problem for a beginner like me, who knows very little about implicit behaviors. Here is the inconsistency of pretty printing method type signature, which added to my confusion:

```julia
julia> foo((a, b)) = print(a, "--", b)
foo (generic function with 1 method)

julia> methods(foo)
# 1 method for generic function "foo":
[1] foo(::Any) in Main at REPL[1]:1

julia> foo(a) = print("-", a)
foo (generic function with 1 method)

julia> methods(foo)
# 1 method for generic function "foo":
[1] foo(a) in Main at REPL[3]:1

```

The same type signature is printed as `foo(::Any)` (nice) and `foo(a)` (less nice).

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 15, 2020, 6:16am UTC](https://discourse.julialang.org/t/function-type-signature/43101/18 "2020-07-15T06:16:52Z")

</div>

> [@pauljurczak](#):
>
> The same type signature is printed as `foo(::Any)` (nice) and `foo(a)` (less nice).

I think that the algorithm is something like the following:

1. if the argument has a variable name, print that (for destructuring, that does not apply),
2. if no variable name was printed, or if the type is something other than `Any`, print the type

I find this nice because it leads to compact output.

---

<div class="post-metadata">

**Author:** ![pauljurczak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pauljurczak/32/921_2.png) [@pauljurczak](https://discourse.julialang.org/u/pauljurczak)\
**Post date:** [July 15, 2020, 6:28am UTC](https://discourse.julialang.org/t/function-type-signature/43101/19 "2020-07-15T06:28:29Z")

</div>

> [@Tamas\_Papp](#):
>
> it leads to compact output

I can only hope that with time I will find this rule worth more than initial confusion. Just offering beginner’s perspective here.

Perhaps it would make some sense to have `Julia for dummies` REPL setting, which would minimize implicit rules and irregularities at the cost of more verbose output. Experts could use `Julia for experts` settings to not get bothered by obvious (to them) info.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 15, 2020, 6:59am UTC](https://discourse.julialang.org/t/function-type-signature/43101/20 "2020-07-15T06:59:32Z")

</div>

I think it is just better to learn Julia as is. It happens quickly for most people.

Whenever people ask for “Julia with training wheels”, it is implicitly assumed that it would be written and maintained by some “experts”. But they may not be interested in working on this in their free time, and handle complaints about the training wheels being the wrong color. YMMV.

[Next page](https://discourse.julialang.org/t/function-type-signature/43101.md?page=2)
