A Poor
A Poor

Reputation: 1064

In Julia, can you specify the parameters and return value of a callable function argument?

In Python, you can specify the arguments and return value for a callable being passed to another function (reference). For example:

def foo(
    bar: Callable[[str],int], # a function that takes a string as an argument and returns an int 
    baz: List[str] # a list of strings
    ) -> List[int]: # returns a list of ints
    return [bar(s) for s in baz]

foo(len,["hello","world!"]) # apply the len function to the list of strings
# [5, 6]

How can I write the equivalent to Callable[[str],int] in Julia?

Upvotes: 2

Views: 756

Answers (1)

Cameron Bieganek
Cameron Bieganek

Reputation: 7674

There is no mechanism to do that in Julia. Neither Julia nor Python statically enforce the type signature of functions. In Julia the preference is to leave your function arguments as generic as possible, so most of the time you might as well leave generic the argument that excepts a function, like this:

foo(f, s) = map(f, s)

Although sometimes people annotate the f argument like this:

foo(f::Union{Function, Type}, s) = map(f, s)

Type is included in the union because not all callable objects are a subtype of Function, e.g. take a look at Function-like objects in the manual.

It is possible to annotate the output type of a function, but all this really does is attempt to convert the return value to the specified output type, so you might get a runtime conversion error if your function does not return the type that you've annotated it with.

Annotations of output types are often superfluous. Consider this code:

bar(x::Int)::Int = 2x

If we look at the lowered code, we can see the extra type conversion that has been added to the code:

julia> @code_lowered bar(42)
CodeInfo(
1 ─ %1 = Main.Int
│   %2 = 2 * x
│   %3 = Base.convert(%1, %2)
│   %4 = Core.typeassert(%3, %1)
└──      return %4
)

However, in this case the compiler is smart enough to figure out that when the input is an integer the output will be an integer and does not need to be converted:

julia> @code_llvm bar(42)

;  @ REPL[1]:1 within `bar'
define i64 @julia_bar_788(i64) {
top:
; ┌ @ int.jl:87 within `*'
   %1 = shl i64 %0, 1
; └
  ret i64 %1
}

In fact, we see that bar has been reduced to the left bit shift operation.

julia> bar(42)
84

julia> 42 << 1
84

Upvotes: 4

Related Questions