# Specific function type

**URL:** <https://discourse.julialang.org/t/specific-function-type/117256>\
**Category:** New to Julia\
**Created:** [July 19, 2024, 9:45pm UTC](https://discourse.julialang.org/t/specific-function-type/117256 "2024-07-19T21:45:27Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![avetissargsian](https://avatars.discourse-cdn.com/v4/letter/a/c77e96/32.png) [@avetissargsian](https://discourse.julialang.org/u/avetissargsian)\
**Post date:** [July 19, 2024, 9:45pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/1 "2024-07-19T21:45:27Z")

</div>

Hello, I am coming from js/ts background. Can someone explain how this code would look like in Julia? Thanks 🙂

```julia
function sayHello(f: (s: string) => string): string {
  return f("Hello,");
}
sayHello((name: string) => name + "Julia!");

```

---

<div class="post-metadata">

**Author:** ![Satvik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/satvik/32/20486_2.png) [@Satvik](https://discourse.julialang.org/u/Satvik)\
**Post date:** [July 19, 2024, 10:22pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/2 "2024-07-19T22:22:15Z")

</div>

I don’t think you can generally get more specific than `Function` by default, because the output type and implementation of a function can depend on its input values. However, you can use callable structs to essentially append metadata to a function.

Example:

```julia
struct FunctionWrapper
  input_types::Vector{DataType}
  output_type::DataType
  f::Function
end

# Callable struct syntax
function (fw::FunctionWrapper)(args...)
  @assert all(isa.(args, fw.input_types)) 
  output = fw.f(args...)
  @assert output isa fw.output_type
  return output
end

foo(x::Int) = x + 1
foo2 = FunctionWrapper([Int], Int, foo)

julia> foo2(5)
6

julia> foo2(5.0)
ERROR: AssertionError: all(isa.(args, fw.input_types))

```

This is obviously a lot of extra code so you would only do it in a few cases where you really needed that extra metadata.

---

<div class="post-metadata">

**Author:** ![cpfiffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cpfiffer/32/208747_2.png) [@cpfiffer](https://discourse.julialang.org/u/cpfiffer)\
**Post date:** [July 19, 2024, 10:50pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/3 "2024-07-19T22:50:49Z")

</div>

I think the simpler, most direct translation is

```julia
function sayhello(f::Function)
    return f("Hello, ")
end

sayhello(name -> name * "Julia!")

```

The extra typing here isn’t something I’d think too hard about tbh

---

<div class="post-metadata">

**Author:** ![avetissargsian](https://avatars.discourse-cdn.com/v4/letter/a/c77e96/32.png) [@avetissargsian](https://discourse.julialang.org/u/avetissargsian)\
**Post date:** [July 20, 2024, 6:53am UTC](https://discourse.julialang.org/t/specific-function-type/117256/4 "2024-07-20T06:53:42Z")

</div>

thank you, this is very educational! 👍

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [July 20, 2024, 7:30am UTC](https://discourse.julialang.org/t/specific-function-type/117256/5 "2024-07-20T07:30:56Z")

</div>

> [@Satvik](#):
>
> I don’t think you can generally get more specific than `Function` by default, because the output type and implementation of a function can depend on its input values.

To elaborate, this is a fundamental design limitation/feature/tradeoff. A Julia function has many aspects that don’t lend to establishing even a generic return type. First, a Julia function can have multiple methods, and those do not need to return the same type at all:

```julia
foo() = 0
foo(x::Int) = 1.0
foo(x) = zero(x)

```

Second, each method can be compiled to different code called specializations, based on input type. `foo(x)` is compiled differently for `foo(1.0)` and `foo(1im)` for example. We don’t have direct access to specializations on the level of the language; what specializations are made is an implementation detail up to the compiler, though it’s been fairly consistent across all versions and we have reflection methods to check.

Third, each specialization does not need to have a specific return type. Julia is a dynamically typed language, so while we do like predictable types for the compiler to optimize over, that is something we can leave unknown until runtime.

So, functions don’t really have much going on in their type. Typical named functions will have a singleton type, but some functions like closures do not have singleton types; all of them subtype the abstract `Function`. If you want something that says a function taking `String` and outputting `String`, you need the function, the input type `String`, and an _enforced_ output type no matter what type the function call ends at. The above `FunctionWrapper` provides that but in field values, so it’s about as distinguishing as `Function` to the type system.

There is an existing package FunctionWrappers.jl that parameterizes over the input and output types, attempts type conversions instead of just assertions, and accesses specializations for efficiency. That does put input and output types into the type system so you can lump different function calls sharing those types together, but a downside of accessing specializations is that it won’t adapt to language-level edits like the above example can (you’d have to reinstantiate the wrapper manually) and can’t support all features of a Julia method.

---

<div class="post-metadata">

**Author:** ![avetissargsian](https://avatars.discourse-cdn.com/v4/letter/a/c77e96/32.png) [@avetissargsian](https://discourse.julialang.org/u/avetissargsian)\
**Post date:** [July 20, 2024, 7:46am UTC](https://discourse.julialang.org/t/specific-function-type/117256/6 "2024-07-20T07:46:58Z")

</div>

I do understand the dynamic nature of Julia, but my concern is  
How do you inform a user that my “function” accepts only arguments of certain types, without comments or additional documentation?  
In this particular case, `sayHello` takes not any Function but `(s: string) => string`  
But I guess this is a tradeoff of dynamic languages. `js` has the same issue 🙂

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [July 20, 2024, 7:54am UTC](https://discourse.julialang.org/t/specific-function-type/117256/7 "2024-07-20T07:54:04Z")

</div>

I can’t say with any certainty if it’s impossible for a dynamically typed language to have a function type that includes input and output types. But it’s definitely not a priority in the mainstream ones, and Julia in particular lacks them by design. In fact, its multiple dispatch completely divorces the function’s type from the types of the positional arguments (keyword arguments aren’t involved in multimethod dispatch, but the compiler does specialize over their types), considering them equally in a function call. That is why you need function _wrappers_ to add that information, with various shortcomings you wouldn’t find in some statically typed languages. The above `FunctionWrapper` type distinguishes input/output types in its fields, not the type system, so you can’t do something like `sayHello(f: (s: string) => string)`. FunctionWrappers.jl can provide a type like `FunctionWrapper{String, Tuple{String}}` to serve that purpose. To be clear, neither mentioned `FunctionWrapper`s are functions because they don’t subtype `Function`, but they _are_ callable.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [July 20, 2024, 11:07am UTC](https://discourse.julialang.org/t/specific-function-type/117256/8 "2024-07-20T11:07:20Z")

</div>

> [@avetissargsian](#):
>
> How do you inform a user that my “function” accepts only arguments of certain types, without comments or additional documentation?

A wrapper callable approach seems to be exactly what you’re asking for, putting the argument types and/or the return type into a type signature. Apparently there’s no package for this purpose currently registered, so wait a few hours until I create it.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [July 20, 2024, 12:20pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/9 "2024-07-20T12:20:50Z")

</div>

I suggest finding a very different name from `FunctionWrapper` even though the concept is somewhat the same. `CallSignature`?

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [July 20, 2024, 12:21pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/10 "2024-07-20T12:21:25Z")

</div>

> [@Benny](#):
>
> name

The working name is EnforcedTypeSignatureCallables.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [July 20, 2024, 12:23pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/11 "2024-07-20T12:23:06Z")

</div>

That’s a tad long. Wouldn’t mind writing such a package name once in an import, but not a type constructor, I’d rename that so fast. My suggestions were for the type, specifically, but even `CallSignature` seems a bit long. I just don’t know if it can be shorter without losing clarity. `CallTypes`?

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [July 20, 2024, 12:38pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/12 "2024-07-20T12:38:55Z")

</div>

> [@Benny](#):
>
> That’s a tad long.

The package naming [guidelines](https://pkgdocs.julialang.org/v1/creating-packages/#Package-naming-guidelines) seem pretty clear:

> Err on the side of clarity, even if clarity seems long-winded to you.
> 
> - `RandomMatrices` is a less ambiguous name than `RndMat` or `RMT`, even though the latter are shorter.

On the other hand, it seems like I get complaints about the length of my package names for each of my packages. There also seems to be a disconnect between the guidelines and the actual package registration practice, I feel like the names of many registered packages don’t conform to the guidelines. (Which is probably just a matter of no one enforcing the guidelines, even though anyone could do it.)

Personally, I think the guidelines are in the right, as it’s always possible to import with `as`, or just assign to a shorter `const` name, if necessary. The MathOptInterface.jl docs, for example, recommend importing the main module as `MOI`. There’s also this recent open PR: [loading: Don't assume a package is loaded by its own name by Keno · Pull Request #55162 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/55162)

Not sure how to proceed, TBH. On one side there’s the guidelines, which represent best practice as far as I see; on the other side there’s the community, which seems to strongly prefer short names.

EDIT: I guess I’ll keep the package name as is, but rename the type to `CallTypes`, as you suggest.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [July 20, 2024, 1:21pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/13 "2024-07-20T13:21:32Z")

</div>

v0 gives you the flexibility to rename, could even take suggestions in an announcement thread and make a poll. The more I look at it, the less I like `CallTypes` because it’s less about a collection of types, more a `TypedCallable`. But is that even clear enough, all callables are already typed…more people will probably arrive at something nicer.

---

<div class="post-metadata">

**Author:** ![avetissargsian](https://avatars.discourse-cdn.com/v4/letter/a/c77e96/32.png) [@avetissargsian](https://discourse.julialang.org/u/avetissargsian)\
**Post date:** [July 20, 2024, 2:04pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/14 "2024-07-20T14:04:21Z")

</div>

Maybe “TypeDecorator” ?

---

<div class="post-metadata">

**Author:** ![avetissargsian](https://avatars.discourse-cdn.com/v4/letter/a/c77e96/32.png) [@avetissargsian](https://discourse.julialang.org/u/avetissargsian)\
**Post date:** [July 20, 2024, 2:06pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/15 "2024-07-20T14:06:28Z")

</div>

I have another question, if

```julia
 function myFunc(f:: Function)
 end

```

will it accept callable struct ?

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [July 20, 2024, 2:10pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/16 "2024-07-20T14:10:48Z")

</div>

> [@avetissargsian](#):
>
> if
> 
> ```julia
> function myFunc(f:: Function)
> end
> 
> ```
> 
> will it accept callable struct ?

Only if that callable struct is declared as subtyping `Function`.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [July 20, 2024, 2:14pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/17 "2024-07-20T14:14:06Z")

</div>

Only if said callable struct subtypes `Function`. If not, you need an argument annotated with the callable struct type or a supertype (all types subtype `Any` so if the definition had no explicit supertype, that’s it). Named types exist in a tree, and we can’t make ad hoc named supertypes that crosslink branches. For example, it could be nice if every iterable had a supertype, but that’s not possible, so the typical method argument for iterables is simply `itr` (implicitly `itr::Any`). Union types can cross branches, but it’s not feasible to track down every iterable in advance to put it into a Union type, especially since Julia is interactive and you can define new iterables.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [July 20, 2024, 6:17pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/18 "2024-07-20T18:17:29Z")

</div>

> [@nsajko](#):
>
> A wrapper callable approach seems to be exactly what you’re asking for, putting the argument types and/or the return type into a type signature. Apparently there’s no package for this purpose currently registered, so wait a few hours until I create it.

> [@\[ANN\] EnforcedTypeSignatureCallables.jl](https://discourse.julialang.org/t/ann-enforcedtypesignaturecallables-jl/117280):
>
> The EnforcedTypeSignatureCallables package is being registered: [New package: EnforcedTypeSignatureCallables v1.0.0 by JuliaRegistrator · Pull Request #111416 · JuliaRegistries/General · GitHub](https://github.com/JuliaRegistries/General/pull/111416) Once it’s registered, this link will point to its page on JuliaHub: EnforcedTypeSignatureCallables.jl The Git repo is on Gitlab: The package was motivated by the frequent requests by Julia newbies for expressing the type signatures for “functions” in the type system. This doesn’t really make sense as …

---

<div class="post-metadata">

**Author:** ![avetissargsian](https://avatars.discourse-cdn.com/v4/letter/a/c77e96/32.png) [@avetissargsian](https://discourse.julialang.org/u/avetissargsian)\
**Post date:** [July 20, 2024, 7:39pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/19 "2024-07-20T19:39:14Z")

</div>

Nice job!  
But I feel like noobie was misunderstood 🙂

let me see if I get it right, the usage of this package would be the next

```julia
# Define a function with multiple arguments
function multiply(a::Int, b::Int)::Float64
    return a * b * 1.0
end

# Wrap the function with TypedCallable
typed_multiply = TypedCallable{Tuple{Int, Int}, Float64}(multiply)

# Call the wrapped function
result = typed_multiply(3, 4)

```

Basically, TypedCallable forces the user to pass a function with a certain signature, but there is no use case for that 🙂

Let’s imagine I am writing a code and I create a function, and I know which params it takes and what it might return, I don’t need a sophisticated wrapper to tell me exact same things I already know.

I was referring to a situation where I have a package/library with a function exposed/exported to user, let’s call it `sayHallo` now what I want to do is to provide a typed hit to a user, what kind of argument it takes.

for example (not real Julia code)

```julia
function sayHello(f:: TypedCallable{Tuple{Int}, String})
  println(f(100))
end

```

now the user of my package doesn’t see what is inside `sayHello` and it tries to call it with this function argument, `(s::String)::Bool -> length(s) > 5`

but Julia detects that `sayHello` does not have such a method for this type of argument and warns the user about that.  
Because I am a noob, I am not sure if `(f:: TypedCallable{Tuple{Int}, String})`  
is a valid type declaration for `f`, but something is telling me it is not 🙂

Now, this whole discussion is a rhetorical exercise, and in dynamic languages, it makes no sense I would not even bother asking it. Still, I saw a sentence somewhere in Julia’s documentation, that types are helping compiler with a performance.  
And after learning that Julia actually, possesses such a sophisticated type system with generics, I was surprised there is no more specific type declaration for function, rather than `Function` and naturally I wanted to ask about that.

Update::  
this is a valid type declaration - (f:: TypedCallable{Tuple{Int}, String})  
but it does not allow you to pass a simple function, you still need to wrap it with TypedCallable struct which is a bit overkill

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [July 20, 2024, 8:04pm UTC](https://discourse.julialang.org/t/specific-function-type/117256/20 "2024-07-20T20:04:51Z")

</div>

You could do this, for example:

```julia
function sayHello(f:: TypedCallable{Tuple{Int},String})
    println(f(100))
end

# fallback
function sayHello(f)
    g = TypedCallable{Tuple{Int},String}(f)
    sayHello(g)
end

```

This way you have both convenience and some of the safety.

```julia-repl
julia> sayHello(n -> string(n))
100

```

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