# Shorthand syntax for defining functors

**URL:** <https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380>\
**Category:** Internals & Design\
**Tags:** syntax, functions, functors\
**Created:** [October 6, 2022, 11:47pm UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380 "2022-10-06T23:47:50Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![dylanxyz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dylanxyz/32/36646_2.png) [@dylanxyz](https://discourse.julialang.org/u/dylanxyz)\
**Post date:** [October 6, 2022, 11:47pm UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/1 "2022-10-06T23:47:50Z")

</div>

Currently, to define a function with a custom type in julia, we use functors:

```julia
julia> struct MyType <: Function end

julia> (::MyType)() = println("Hello world!")

julia> (::MyType)(name) = println("Hello $(name)!")

julia> MyType()()
Hello world!

julia> MyType()("Steve")
Hello Steve!

```

But it would be cool if i could do something like:

```julia
julia> abstract type MyType <: Function end

julia> function foo <: MyType end
foo (generic function with 0 methods)

julia> foo() = println("Hello world!")
foo (generic function with 1 methods)

julia> foo(name) = println("Hello $(name)!")
foo (generic function with 2 methods)

julia> foo()
Hello world!

julia> foo("Steve")
Hello Steve!

julia> foo isa MyType
true

```

Which should be equivalent to:

```julia
abstract type MyType <: Function end

struct Foo <: MyType end

const foo = Foo()

(::Foo)() = println("Hello world!")

(::Foo)(name) = println("Hello $(name)!")

```

What do you think about this syntax?

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [October 7, 2022, 1:55am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/2 "2022-10-07T01:55:31Z")

</div>

The question to begin with is “why”?

---

<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:** [October 7, 2022, 1:56am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/3 "2022-10-07T01:56:08Z")

</div>

Considering that you’re making a singleton type with a `const` name for its only callable instance, it seems like you just want to declare a supertype of a function’s type. Such a declaration would be error-prone in multiple method definitions e.g. different methods that declare different supertypes, so we would need a dedicated singular block for it, a lot like a functor’s `struct` block.

---

<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:** [October 7, 2022, 2:06am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/4 "2022-10-07T02:06:55Z")

</div>

I can’t speak for OP, but I might use it for dispatch in higher-order methods, like a method that only considers the functions that subtype a particular supertype. I’ve done it for some functors, but never a singleton type like a function’s. `<:Function` had always been good enough for functions for me, since dispatching on arguments is necessary to narrow down to methods.

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [October 7, 2022, 2:11am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/5 "2022-10-07T02:11:32Z")

</div>

Right, wouldn’t then this be served equally well by:

```julia

struct MyType <: Function end

(::MyType)() = println("Hello world!")

(::MyType)(name) = println("Hello $(name)!")

foo = MyType()

foo()

foo("Steve")

```

---

<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:** [October 7, 2022, 2:55am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/6 "2022-10-07T02:55:05Z")

</div>

It’s what I’d do, but perhaps with an extra `const foo = MyType()`.

---

<div class="post-metadata">

**Author:** ![dylanxyz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dylanxyz/32/36646_2.png) [@dylanxyz](https://discourse.julialang.org/u/dylanxyz)\
**Post date:** [October 7, 2022, 2:58am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/7 "2022-10-07T02:58:15Z")

</div>

For my specific use case, i have some callable objects that acts as events that the application will dispatch (call) in specific situations, something like `configure`, `setup`, `dispose`, etc. I need to perform different actions based on the types of the event being fired. For example, for `setup`, i do some initialization and `dispose` cleaning up things. I also wanna group these events with specific types. For example, `configure`, `setup` and `dispose` should be subtype of `LifeCycleEvent`, and mouse events such as `mousepress` and `mousedrag` should be subtype of `MouseEvent`, and the same for the keyboard events and etc.

Of course, the solution is to define singleton functors:

```julia
abstract type Event <: Function end

abstract type LifeCycleEvent <: Event end
abstract type MouseEvent <: Event end
abstract type KeyboardEvent <: Event end

struct SetupEvent <: LifeCycleEvent end
struct ConfigureEvent <: LifeCycleEvent end
struct DisposeEvent <: LifeCycleEvent end

struct MousePressEvent <: MouseEvent end
struct MouseDragEvent <: MouseDrag end
struct KeyPressEvent <: KeyboardEvent end
struct KeyInputEvent <: KeyboardEvent end

const setup = SetupEvent()
const configure = ConfigureEvent()
const dispose = DisposeEvent()

```

Then, implementing each event:

```julia
function (::SetupEvent)()
    @info "Starting..."
end

function (::DisposeEvent)()
    @info "Closing..."
end

# ... etc

```

With this, i can create a function called `dispatch` that acts different based on the event  
that is being fired:

```julia
function dispatch(event::Event, args...)
    if applicable(event, args...)
        # fire the event
        event(args...)
    end
end

function dispatch(event::SetupEvent, args...)
    # do something before the app starts
end

function dispatch(event::DisposeEvent, args...)
    # do something before the app closes
end

```

I just think that the syntax `(::MyType)() = ...` or `function (::MyType)() end` is a little bit unintuitive, specially for people still learning julia. Instead, if i could just write:

```julia
function myfunction <: MyType end

```

And then defining the methods later could be more easier to understand.

But of course, that is specific to my use case. I don’t know how many people would actually use this.

---

<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:** [October 7, 2022, 3:10am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/8 "2022-10-07T03:10:19Z")

</div>

As I said, `function` blocks are just terrible alternatives for `struct` blocks because there can be multiple method definitions each with their own declared supertype.

> [@dylanxyz](#):
>
> I just think that the syntax `(::MyType)() = ...` or `function (::MyType)() end` is a little bit unintuitive, specially for people still learning julia.

That’s true, and it’s one of my criticisms of the documentation. Functors are written like it’s some weird minor feature, but it’s really how functions work and should be explained from the get-go. Really, `function` blocks are syntactic sugar that omits the type definition for a function: unannotated names e.g. `function foo end` are made `const` and are assigned the callable instance instead of the type `typeof(foo)`, which is always a singleton subtype of `Function`. A function call `foo(a, b)` dispatches on the types of `foo, a, b` just like functor calls.

---

<div class="post-metadata">

**Author:** ![dylanxyz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dylanxyz/32/36646_2.png) [@dylanxyz](https://discourse.julialang.org/u/dylanxyz)\
**Post date:** [October 7, 2022, 3:22am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/9 "2022-10-07T03:22:41Z")

</div>

Just to be clear, is not like want to change the syntax for defining functors, i just want an alternative way to define them.

---

<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:** [October 7, 2022, 3:31am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/10 "2022-10-07T03:31:43Z")

</div>

> [@dylanxyz](#):
>
> an alternative way to define them [functors].

That’s exactly what `function`-blocks with unannotated names are, and for good reason they are locked into an implicit `struct ___ <: Function end`. But if you really do want to risk declaring supertypes in `function`-blocks, maybe you can pull it off with a macro? That seems difficult though, and I’m not even sure if it’s possible to make one that works perfectly.

---

<div class="post-metadata">

**Author:** ![dylanxyz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dylanxyz/32/36646_2.png) [@dylanxyz](https://discourse.julialang.org/u/dylanxyz)\
**Post date:** [October 7, 2022, 4:11am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/11 "2022-10-07T04:11:40Z")

</div>

The macro is actually fairly simple to implement:

```julia
julia> macro singleton(expr)
           @assert Meta.isexpr(expr, :(<:))
           name, supertype = expr.args
           typename = gensym(name)
           quote
               struct $typename <: $(esc(supertype)) end
               const $(esc(name)) = $typename()
           end
       end
@singleton (macro with 1 method)

julia> abstract type MyType <: Function end

julia> @singleton foo <: MyType
(::var"##foo#312") (generic function with 0 methods)

julia> foo() = println("Hello world!")
(::var"##foo#312") (generic function with 1 method)

julia> foo(name) = println("Hello $(name)!")
(::var"##foo#312") (generic function with 2 methods)

julia> foo()
Hello world!

julia> foo("Steve")
Hello Steve!

julia> foo isa MyType
true

```

I just don’t know how to properly name it yet.

---

<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:** [October 7, 2022, 4:24am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/12 "2022-10-07T04:24:19Z")

</div>

Moving the supertype declaration out of the `function` blocks does solve the issue. Only suggestion I could have is defining `Base.show` for your hidden type to print the name directly, I think you can interpolate a `Quotenode(name)` into that. But how did you turn `foo` into a generic function name? I see it printed as such, but I can’t replicate it with `struct _Bar end; const bar = _Bar(); bar() = 0`. EDIT: nvm, `struct _Bar <: Function end` does it, there must be a `isa Function` check somewhere.

Also it appears that `const` doesn’t always make a name accept new methods. For example, `const x = 1.0im; x() = 0` throws a `ERROR: cannot define function x; it already has a value`, and I know complex numbers are `struct` types, not primitive types.

---

<div class="post-metadata">

**Author:** ![dylanxyz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dylanxyz/32/36646_2.png) [@dylanxyz](https://discourse.julialang.org/u/dylanxyz)\
**Post date:** [October 7, 2022, 4:41am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/13 "2022-10-07T04:41:09Z")

</div>

I honestly can’t figure out why this works:

```julia
julia> struct Foo end

julia> const foo = Foo()
Foo()

julia> foo() = 0
Foo()

julia> foo(n) = n - 2
Foo()

julia> foo()
0

julia> foo(3)
1

julia> foo isa Foo
true

```

And this doesn’t:

```julia
julia> const bar = Complex(0)
0 + 0im

julia> bar() = 0
ERROR: cannot define function bar; it already has a value
Stacktrace:
 [1] top-level scope
   @ none:0
 [2] top-level scope
   @ REPL[12]:1

```

---

<div class="post-metadata">

**Author:** ![dylanxyz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dylanxyz/32/36646_2.png) [@dylanxyz](https://discourse.julialang.org/u/dylanxyz)\
**Post date:** [October 7, 2022, 4:55am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/14 "2022-10-07T04:55:27Z")

</div>

Using your advice to define custom `Base.show` method for the hidden type, the macro is now:

```julia
julia> macro singleton(expr)
           @assert Meta.isexpr(expr, :(<:))
           name, supertype = expr.args
           typename = gensym(name)
           quote
               struct $typename <: $(esc(supertype)) end

               function Base.show(io::IO, f::$(typename))
                   name = $(QuoteNode(name))
                   type = supertype(typeof(f))
                   print(io, "singleton function $name (subtype of $type)")
               end

               const $(esc(name)) = $typename()
           end
       end
@singleton (macro with 1 method)

```

The problem is that if the supertype is subtype of `Function`, the printing doesn’t work:

```julia
ulia> abstract type MyType <: Function end

julia> @singleton foo <: MyType
(::var"##foo#312") (generic function with 0 methods)

julia> foo
(::var"##foo#312") (generic function with 0 methods)

```

But it works ortherwise:

```julia
julia> abstract type Bar end

julia> @singleton bar <: Bar
singleton function bar (subtype of Bar)

julia> bar
singleton function bar (subtype of Bar)

```

I’m not sure why. Maybe functions are printed differently?

---

<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:** [October 7, 2022, 6:51am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/15 "2022-10-07T06:51:59Z")

</div>

1. It works if you do `function Base.show(io::IO, ::MIME"text/plain", f::$(typename))` instead. I also still don’t understand the docs for `Base.show` saying what the difference is. I think it may have run into a preexisting method with such a signature for ::Function [like this one for AbstractArray](https://stackoverflow.com/questions/58962304/how-to-overload-base-show-for-custom-array-types), but the linked docs isn’t helpful at all.

2. Try to avoid lines like `name = $(QuoteNode(name))`, use a different name like `name2` so the later interpolation `$name2` is unambiguous.

3. I intended for you to interpolate a symbol into an expression so that it remains a symbol rather than become a variable, like `print(io, "singleton function ", $(QuoteNode(name)), " (subtype of $type)")`. You instead did the equivalent of `print(io, "singleton function $($(QuoteNode(name))) (subtype of $type)")`. I’m actually not sure how the latter even works, I was under the impression that interpolation in strings in expressions is unfeasible in macros, e.g. `:("This is $x")` is considered to be an expression containing a String interpolation, so it is evaluated as `"This is $x"` outside the macro and fails.

---

<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:** [October 9, 2022, 2:38am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/16 "2022-10-09T02:38:44Z")

</div>

> [@Benny](#):
>
> Also it appears that `const` doesn’t always make a name accept new methods. For example, `const x = 1.0im; x() = 0` throws a `ERROR: cannot define function x; it already has a value`, and I know complex numbers are `struct` types, not primitive types.

I tracked the error printout to a part of methods.c, and I can’t read C so I don’t really know how this works. But I did figure out that `struct _Bar x::Int end; const bar = _Bar(1); bar() = 0` throws the error, so that part probably does some check of whether the struct contains any data. After all, a multimethod-like instance can only be safely given the `const` name instead of the type if the type is singleton. So `struct Foo end; struct _Bar x::Nothing; y::Foo end; const bar = _Bar(nothing, Foo()); bar() = 0` works.

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [October 9, 2022, 3:30am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/17 "2022-10-09T03:30:06Z")

</div>

I have a hard time wrapping my head around this:

```julia
julia> struct _Bar x::Nothing; end; const bar = _Bar(nothing); bar() = 0                                    
_Bar(nothing)                                                                                               
                                                                                                            
julia> struct _Bar2 x::Int; end; const bar2 = _Bar2(13); bar2() = 0                                         
ERROR: cannot define function bar2; it already has a value                                                  
Stacktrace:                                                                                                 
 [1] top-level scope                                                                                        
   @ none:0                                                                                                 
 [2] top-level scope                                                                                        
   @ REPL[2]:1                                                                                              
                                                                                                            
julia> 

```

Why does it work in the first case?

---

<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:** [October 9, 2022, 4:11am UTC](https://discourse.julialang.org/t/shorthand-syntax-for-defining-functors/88380/18 "2022-10-09T04:11:21Z")

</div>

~~I think it’s because you don’t need any data for singleton fields like `Nothing`. `sizeof(_Bar)` returns 0.~~ I think it’s because it is a singleton type, specifically that `Base.issingletontype(_Bar)` is `true`; the current implementation also assigns the sole instance to `_Bar.instance`. It makes sense that a singleton type must be immutable (mutable type can have 2 different instances of same value) and have either no fields or only singleton fields like `::Nothing`. I think the methods.c code checks for that somehow, not sure because I can’t read C. Incidentally, I love how we’re just breaking down how functions are special cases of functors.
