# Something(a, b) not shortcutting

**URL:** <https://discourse.julialang.org/t/something-a-b-not-shortcutting/27746>\
**Category:** Performance\
**Tags:** suggestions\
**Created:** [August 20, 2019, 8:04am UTC](https://discourse.julialang.org/t/something-a-b-not-shortcutting/27746 "2019-08-20T08:04:34Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Charlie\_He](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/charlie_he/32/9465_2.png) [@Charlie\_He](https://discourse.julialang.org/u/Charlie_He)\
**Post date:** [August 20, 2019, 8:04am UTC](https://discourse.julialang.org/t/something-a-b-not-shortcutting/27746/1 "2019-08-20T08:04:34Z")

</div>

Assuming we have:

```julia
function do_work(x) 
    sleep(2)
    x
end

```

It turns out `something(Some(2), do_work(3))` still invoke do\_work, which returns 2 seconds later.  
It would be better to define it as a macro, which retains the arguments as AST and only evaluate them when necessary.

---

<div class="post-metadata">

**Author:** ![Syx\_Pek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/syx_pek/32/6364_2.png) [@Syx\_Pek](https://discourse.julialang.org/u/Syx_Pek)\
**Post date:** [August 20, 2019, 8:27am UTC](https://discourse.julialang.org/t/something-a-b-not-shortcutting/27746/2 "2019-08-20T08:27:21Z")

</div>

This is simply eager evaluation. If you really need `something` to behave like this, you need to use a macro. Alternatively, `&&` and `||` already short-circuits, so if it does no side effects, you can consider using those too.

---

<div class="post-metadata">

**Author:** ![Charlie\_He](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/charlie_he/32/9465_2.png) [@Charlie\_He](https://discourse.julialang.org/u/Charlie_He)\
**Post date:** [August 20, 2019, 12:53pm UTC](https://discourse.julialang.org/t/something-a-b-not-shortcutting/27746/3 "2019-08-20T12:53:56Z")

</div>

This is harder than I thought.

```julia
macro something()
    return :(throw(ArgumentError("No value arguments present")))
end
macro something(head, rest...)
    expr = quote
        if $head isa Nothing
            return # somehow insert expansion of @something($(rest...)) at this position
        else
            return $head
        end
    end
    return expr
end

```

I wonder if it is even possible to make such a macro.

---

<div class="post-metadata">

**Author:** ![c42f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/c42f/32/52842_2.png) [@c42f](https://discourse.julialang.org/u/c42f)\
**Post date:** [August 20, 2019, 2:00pm UTC](https://discourse.julialang.org/t/something-a-b-not-shortcutting/27746/4 "2019-08-20T14:00:03Z")

</div>

It’s possible: macros are arbitrary functions which transform syntax into syntax. One fairly direct way to write it could be as follows (there’s shorter ways but this should be relatively easy to understand):

```julia
function something_expr(ex, exs...)
    quote
        s = $(esc(ex))
        if isnothing(s)
            $(something_expr(exs...))
        else
            s
        end
    end
end
something_expr(ex) = :(something(ex))

macro something(exs...)
    something_expr(exs...)
end

```

---

<div class="post-metadata">

**Author:** ![Charlie\_He](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/charlie_he/32/9465_2.png) [@Charlie\_He](https://discourse.julialang.org/u/Charlie_He)\
**Post date:** [September 6, 2019, 9:18am UTC](https://discourse.julialang.org/t/something-a-b-not-shortcutting/27746/5 "2019-09-06T09:18:56Z")

</div>

Thank you very much! There is a error in the base case. Here is the complete code:

```julia
# https://discourse.julialang.org/t/something-a-b-not-shortcutting/27746/4.
# All credits to Chris Foster
function something_expr(head, rest...)
    quote
        head_val = $(esc(head))
        if head_val isa Some
            head_val.value
        elseif isnothing(head_val)
            $(something_expr(rest...))
        else
            head_val
        end
    end
end

function something_expr(head)
    quote
        something($(head))
    end
end

macro something(args...)
    something_expr(args...)
end

# test
function f(x)
    sleep(1)
    x
end

@something 1 2 # 1
@something 1 f(2) # 1, without delay
@something Some(1) 2 # 1
@something nothing 2 # 2
@something sleep(1) 2 # 2, 1s delay

```
