# Using @sprintf inside a macro

**URL:** <https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275>\
**Category:** General Usage\
**Tags:** macros\
**Created:** [August 20, 2020, 4:37pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275 "2020-08-20T16:37:02Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![anj](https://avatars.discourse-cdn.com/v4/letter/a/779978/32.png) [@anj](https://discourse.julialang.org/u/anj)\
**Post date:** [August 20, 2020, 4:37pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/1 "2020-08-20T16:37:02Z")

</div>

I need to prefix my log lines with a timestamp. so I was thinking overloading @printf along those lines

```julia
import Printf.@printf
macro printf(args...)
    tmp_str = @sprintf(args...)
    return :(print(now(), " : ", tmp_str))
end

```

However @sprintf complains that it can’t take expression in. Wonder if there is a way to make it stop complaining.

Alternatively, maybe there are simpler ways to overload @printf so a desired timestamp is added?

---

<div class="post-metadata">

**Author:** ![chakravala](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chakravala/32/6832_2.png) [@chakravala](https://discourse.julialang.org/u/chakravala)\
**Post date:** [August 20, 2020, 4:46pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/2 "2020-08-20T16:46:14Z")

</div>

You are misunderstanding how macros actually work.

When you call a macro, it is an abstract syntax tree transformation, so the input is treated as an expression instead of as a value.

In your example, you are inputting the expression into the macro of `@sprintf` which will never work.

---

<div class="post-metadata">

**Author:** ![thofma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thofma/32/1691_2.png) [@thofma](https://discourse.julialang.org/u/thofma)\
**Post date:** [August 20, 2020, 5:07pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/3 "2020-08-20T17:07:44Z")

</div>

You can do it like this (edited) (and edited again 🙂)

```julia
julia> import Printf.@sprintf; import Dates.now;

julia> macro myprintf(x, y...)
         quote
           let tmp_str = @sprintf($x, $(esc(y))...)
           print(now(), " : ", tmp_str);
         end; end
       end

```

```julia
julia> @myprintf "%.2f" 1.111
2020-08-20T19:15:25.331 : 1.11

```

Edit: Thanks @chakravala. I could reproduce your error and then was really confused. I edited it again. Thanks @dlakelan for the hygiene help.

Edit: Still not quite right. See [Using @sprintf inside a macro - #17 by simeonschaub](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/17) for a correct solution by @simeonschaub.

---

<div class="post-metadata">

**Author:** ![chakravala](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chakravala/32/6832_2.png) [@chakravala](https://discourse.julialang.org/u/chakravala)\
**Post date:** [August 20, 2020, 5:11pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/4 "2020-08-20T17:11:56Z")

</div>

@thofma no that is incorrect (also you have an extra `begin` which needs to be taken out).

---

<div class="post-metadata">

**Author:** ![thofma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thofma/32/1691_2.png) [@thofma](https://discourse.julialang.org/u/thofma)\
**Post date:** [August 20, 2020, 5:17pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/5 "2020-08-20T17:17:08Z")

</div>

I edited my post. Seems to work. I don’t understand why this should not be possible. The call to `@printf` is just a transformation at parse time, so why not do the same with the additional `now()` call? Of course the new macro has the same restrictions as `@sprintf`.

---

<div class="post-metadata">

**Author:** ![chakravala](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chakravala/32/6832_2.png) [@chakravala](https://discourse.julialang.org/u/chakravala)\
**Post date:** [August 20, 2020, 5:17pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/6 "2020-08-20T17:17:57Z")

</div>

It doesn’t work for me, so I dont’t know?

```nohighlight
julia> @myprintf("%.2f",1/9)
ERROR: LoadError: ArgumentError: @sprintf: first argument must be a format string
Stacktrace:
 [1] @sprintf(::LineNumberNode, ::Module, ::Vararg{Any,N} where N) at /build/julia/src/julia-1.5.0/usr/share/julia/stdlib/v1.5/Printf/src/Printf.jl:1291
 [2] run_repl(::REPL.AbstractREPL, ::Any; backend_on_current_task::Bool) at /build/julia/src/julia-1.5.0/usr/share/julia/stdlib/v1.5/REPL/src/REPL.jl:292
 [3] run_repl(::REPL.AbstractREPL, ::Any) at /build/julia/src/julia-1.5.0/usr/share/julia/stdlib/v1.5/REPL/src/REPL.jl:288
in expression starting at REPL[42]:3

```

---

<div class="post-metadata">

**Author:** ![thofma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thofma/32/1691_2.png) [@thofma](https://discourse.julialang.org/u/thofma)\
**Post date:** [August 20, 2020, 5:19pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/7 "2020-08-20T17:19:33Z")

</div>

> [@chakravala](#):
>
> `@myprintf("%.2f",1/9)`

I edited it. Seems to work fine for me:

```julia
julia> @myprintf("%.2f",1/9)
2020-08-20T19:19:09.447 : 0.11

```

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [August 20, 2020, 5:29pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/9 "2020-08-20T17:29:31Z")

</div>

> [@thofma](#):
>
> ```julia
> quote
> tmp_str = @sprintf($x, $y...)
> print(now(), " : ", tmp_str);
> end
> 
> ```

I’d suggest

```julia
quote
   let tmp_str = ...
...
  end
end

```

Otherwise if a user uses this macro in the context where they already have a variable called tmp\_str it will be overwritten ! In my code it is bound to a new variable inside the let.

---

<div class="post-metadata">

**Author:** ![thofma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thofma/32/1691_2.png) [@thofma](https://discourse.julialang.org/u/thofma)\
**Post date:** [August 20, 2020, 5:34pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/10 "2020-08-20T17:34:02Z")

</div>

Thanks. I secretly hoped that the macro hygiene police would show up 🙂

---

<div class="post-metadata">

**Author:** ![anj](https://avatars.discourse-cdn.com/v4/letter/a/779978/32.png) [@anj](https://discourse.julialang.org/u/anj)\
**Post date:** [August 20, 2020, 8:13pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/11 "2020-08-20T20:13:11Z")

</div>

Thanks everyone! The solution works perfectly!

---

<div class="post-metadata">

**Author:** ![WschW](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wschw/32/6575_2.png) [@WschW](https://discourse.julialang.org/u/WschW)\
**Post date:** [August 20, 2020, 8:56pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/12 "2020-08-20T20:56:15Z")

</div>

Since `temp_str` is not escaped you do not need the `let`. Local variables get renamed by default, and since `temp_str` is assigned to and not explicitly marked as global it is a local variable.

[https://docs.julialang.org/en/v1/manual/metaprogramming/#Hygiene-1](https://docs.julialang.org/en/v1/manual/metaprogramming/#Hygiene-1)

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [August 20, 2020, 10:35pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/13 "2020-08-20T22:35:14Z")

</div>

Nice. I have to read more about metaprogramming!

---

<div class="post-metadata">

**Author:** ![chakravala](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chakravala/32/6832_2.png) [@chakravala](https://discourse.julialang.org/u/chakravala)\
**Post date:** [August 20, 2020, 10:41pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/14 "2020-08-20T22:41:39Z")

</div>

I would do it like this

```julia
macro myprintf(x, y...)
    :(print(now(),":",@sprintf($x, $(esc(y))...)))
end

```

having an extra variabl name is unecessary, and my preferred style is to not assign a variable unless it is needed more than once

---

<div class="post-metadata">

**Author:** ![anj](https://avatars.discourse-cdn.com/v4/letter/a/779978/32.png) [@anj](https://discourse.julialang.org/u/anj)\
**Post date:** [August 21, 2020, 8:59am UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/15 "2020-08-21T08:59:10Z")

</div>

@chakravala, thanks! In fact, this is exactly how I implemented it now in production code, for all the reasons you mentioned. Initially, I put a variable just to be more explicit where the problem is. Now it is of course time to clean up.

---

<div class="post-metadata">

**Author:** ![anj](https://avatars.discourse-cdn.com/v4/letter/a/779978/32.png) [@anj](https://discourse.julialang.org/u/anj)\
**Post date:** [August 21, 2020, 2:51pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/16 "2020-08-21T14:51:41Z")

</div>

Actually looks like I still run into a problem as above solution is not working in some very common scenario. Namely passing a variable into the macro (passing a number directly works)

```julia
import Printf.@sprintf; 
import Dates.now;
macro myprintf(x, y...)
    :(print(now(),":",@sprintf($x, $(esc(y))...)))
end

@myprintf("working %.f", 0.42)

#below fails with ERROR: MethodError: no method matching isfinite(::Symbol)
result = 0.43
@myprintf("failing %.f", result)

```

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [August 22, 2020, 5:38pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/17 "2020-08-22T17:38:25Z")

</div>

Splatting doesn’t quite work like this in macro calls. Try:

```julia
macro myprintf(x, y...)
    :(print(now(), ":", @sprintf($x, $(esc.(y)...))))
end

```

instead. You need to do the splatting inside the interpolation, for `y` to be spliced correctly into the expression.

~~Edit: I don’t think you even need the `esc`.~~

---

<div class="post-metadata">

**Author:** ![anj](https://avatars.discourse-cdn.com/v4/letter/a/779978/32.png) [@anj](https://discourse.julialang.org/u/anj)\
**Post date:** [August 23, 2020, 12:42pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/18 "2020-08-23T12:42:10Z")

</div>

Thanks @simeonschaub! that indeed works as expected.

I wish somebody with a deep knowledge of macros would have written a bit deeper on the topic with tips and tricks, going into tricky situations like those

---

<div class="post-metadata">

**Author:** ![anj](https://avatars.discourse-cdn.com/v4/letter/a/779978/32.png) [@anj](https://discourse.julialang.org/u/anj)\
**Post date:** [August 24, 2020, 2:36pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/19 "2020-08-24T14:36:08Z")

</div>

Yet, one more problem in this solution. using this macro inside a function seems to be not working

```julia
import Printf.@sprintf; 
import Dates.now;
macro myprintf(x, y...)
    :(print(now(), ":", @sprintf($x, $(esc.(y)...))))
end

function t()
    r = 21
    @myprintf("failing %.f\n", r * 2)
end

#calling function t is failing with unknown r
t()

```

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [August 24, 2020, 6:20pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/20 "2020-08-24T18:20:36Z")

</div>

I came up with this solution:

```julia
julia> macro myprintf(x,y...)
       :(print(now(),":",@sprintf($x,($(y...),)...)))
       end

```

after reading [this post](https://discourse.julialang.org/t/please-explain-fine-point-of-splatting-syntax-in-macros/16303)

But I don’t know why it works 🤣

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [August 24, 2020, 6:51pm UTC](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275/21 "2020-08-24T18:51:24Z")

</div>

Does it work for you, if you just leave out the `esc` in the above example? This might be a macro expansion issue in Julia.

[Next page](https://discourse.julialang.org/t/using-sprintf-inside-a-macro/45275.md?page=2)
