Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@printf() constant format string is not allowed #4248

Closed
goszlanyi opened this issue Sep 10, 2013 · 19 comments
Closed

@printf() constant format string is not allowed #4248

goszlanyi opened this issue Sep 10, 2013 · 19 comments

Comments

@goszlanyi
Copy link

The following code is invalid:

julia> const fmt="%4d%4d%4d\n"
"%4d%4d%4d\n"

julia> @printf(fmt,1,2,3)
ERROR: first or second argument must be a format string

Is there a reason why a constant format string is not allowed ?

@StefanKarpinski
Copy link
Sponsor Member

Our "constants" are still run-time values – they are write-once rather than compile-time constants like in C.

@kmsquire
Copy link
Member

As a hack until julia gets real support for runtime format strings, this works:

julia> const fmt="%4d%4d%4d\n"
"%4d%4d%4d\n"

julia> @eval @printf($fmt,1,2,3)
   1   2   3

@pao
Copy link
Member

pao commented Sep 10, 2013

You could also hack in a quoted string and avoid the @eval, I think?

@kmsquire
Copy link
Member

@pao , how's that?

@kmsquire
Copy link
Member

Poor man's function to do the above:

julia> printf(fmt::String,args...) = @eval @printf($fmt,$(args...))
# methods for generic function printf
printf(fmt::String,args...) at none:1

julia> printf(fmt, 1,2,3)
   1   2   3

@pao
Copy link
Member

pao commented Sep 10, 2013

@pao , how's that?

I'll have to check with a Julia console. Let me get back to you.

@pao
Copy link
Member

pao commented Sep 10, 2013

...but the idea is to splice in an expression containing a literal string.

@JeffBezanson
Copy link
Sponsor Member

If you define printf that way using @eval it will be unbelievably slow.

@kmsquire
Copy link
Member

Hence the description as a "poor man's printf".

What do you suggest? AFAIK, right now there's no other way to handle format strings generated on the fly.

(I was looking for this myself yesterday...)

@StefanKarpinski
Copy link
Sponsor Member

You can use @eval to define a function that has a string literal in it:

julia> const fmt = "%4d%4d%4d\n"
"%4d%4d%4d\n"

julia> @eval f(x,y,z) = @printf($fmt,x,y,z)
# methods for generic function f
f(x,y,z) at none:1

julia> f(1,2,3)
   1   2   3

The function f will be fast. If you just want to call @printf once, then use @eval as @kmsquire suggested.

@pao
Copy link
Member

pao commented Sep 11, 2013

@StefanKarpinski's approach is basically what I was thinking.

@goszlanyi
Copy link
Author

Thanks for all your answers!
But is this really a closed issue?

@StefanKarpinski
Copy link
Sponsor Member

Julia's @printf doesn't handle dynamic formats. That was a decision when we designed it. If you want to create a fully dynamic printf implementation that's as fast as C's and handles all of Julia's various types correctly, you are welcome to go for it and submit a pull request.

In the meantime, you can handle all scenarios with our current @printf. If the format is run-time configurable, but doesn't change, use @eval to generate a function that does the formatting you want. If you don't need to print much data, then just wrap @eval around the @printf call. If you need to print a lot of data with constantly changing formatting, then do the printing more programmatically – with calls to print and pad, etc. – instead of using generated formats passed to printf.

@kmsquire
Copy link
Member

I would actually suggest rewording this issue or creating a separate issue requesting runtime string formatting. In particular, other than @printf, I can't seem to find a way to format numbers (number of decimal places, leading zeros, etc.)--is there one?

I was wanting runtime formatting for the Logging package I'm working on. The Datetime package would also probably find it useful, as there's little chance it will predefine every possible way of formatting dates/times, etc.

then do the printing more programmatically – with calls to print and pad, etc.

I can't seem to find pad.

@goszlanyi
Copy link
Author

Stefan, thanks for summarizing all these options.

A nice thing about @eval f(x,y,z) = @printf($fmt,x,y,z)
that it does not require fmt to be a const.

@StefanKarpinski
Copy link
Sponsor Member

Right, we have lpad and rpad, not pad. But yes, we should definitely have better facilities for programmatic formatting that can match those of @printf. The @eval f(x,y,z) = @printf($fmt,x,y,z) trick is quite powerful – you're doing JIT compilation of a runtime format, generating completely custom code on the fly.

@StefanKarpinski
Copy link
Sponsor Member

Let's create a new issue for programmatic formatting. I'm not entirely sure what needs to go in there so I'll let someone else open it.

@goszlanyi
Copy link
Author

I am not the right person to do this.
@kmsquire, please also consider issue #4209.

@kmsquire
Copy link
Member

The @eval f(x,y,z) = @printf($fmt,x,y,z) trick is quite powerful – you're doing JIT compilation of a runtime format, generating completely custom code on the fly.

I agree that it's quite powerful. I'm probably going to use something like it Logging.jl.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants