PyFormattedStrings performance is better: my cursory testing with @btime shows that it is 2-10 times faster than Strs.jl. Loading time is also shorter.
Do you have some benchmark code?
I’d like to see where I could improve the performance of Strs.jl.
That difference might no longer be there, I rewrote Format.jl to use the same code as Printf.jl, but incorporated so that I could handle extensions (and also because of the change from Grisu to Ryu in Base Julia)
I’m also interested in seeing the loading time for just StrFormat.jl compared to PyFormattedStrings.jl, which would be a more apples to apples comparison.
Not completely sure what you mean by keyword arguments here, but I do see (from the docs) that Strs.jl is designed to be extensible.
In StrFormat.jl, if you have f"\%(...)", that ends up calling fmt(...), and any argments, positional and keywords, are passed on to that. Same thing with f"\%<c format string>(...)", it calls cfmt(<c format string>, ...), and f"\{<python format string>}(...)" calls pyfmt(<python format string>, ...).
That’s just one way that StrLiterals.jl is designed to be extensible. It sets up the framework, so that other packages such as StrFormat and StrEntities can add new characters to be handled after the \ which otherwise would be errors. I’ve been planning on adding color sequences as well, I just need to decide on the syntax and then have a new StrColors.jl that would add that capability.
Normal Julia strings already can have executable code within the string, via interpolation, such as "Length of a is $(length(a))", so I don’t think that really holds.
The syntax I chose allows for new features to be added, simply by using other packages that use the StrLiterals framework, without breaking any other string syntax (so you can code generate these, just as you’d do for a normal Julia literal string, without worrying about having to now specially quote {, for example.
Longer example also show a similar difference, sometimes more sometimes less.
Doesn’t look like StrFormat.jl is enough to use this interpolation, I get @f_str not defined. But I agree that loading just the required packages instead of all Strs.jl will likely give close loading times.
Sounds conceptually intersting. Do you have any neat usecases, examples that utilize this power? Outside of supporting different interpolation syntaxes.
As you could tell, PyFormattedStrings’ follows a very different design direction: just provide a familiar formatted interpolation syntax, nothing more nothing less. This makes the package very lightweight, and I don’t foresee it needing any significant maintenance while julia is at 1.x. There aren’t any major features missing, so I personally consider PyFormattedStrings stable/effectively frozen at this point.
Sure, and this is something I don’t really like. It would be cleaner to just have opt-in interpolation, such as the f-prefix.
As for escaping in Strs.jl, as I said above I could really understand how to do it. E.g., what goes instead of question marks so that f"???" == "\\(1)" ?
Yes, I’ve got a one-line fix for that I need to merge in. I’d always used using StrLiterals, StrFormat, StrEntitites, and StrLiterals exports the macros, but it doesn’t hurt to have any packages that use StrLiterals to also export them as well.
I use it all the time to pass the width and/or precision for things like f"\%f(foo, wid, pre)" (in C, that would be sprintf(“%*.*f”, foo, wid, pre), as well as adding options that aren’t part of the C formatting syntax.
Yes, recently, there has been another package trying to do the same thing (Fmt.jl), but that didn’t really match the Python syntax as well as your package does, and I didn’t feel it had all of the capabilities that StrFormat.jl has either.
I do very much like yours - do you have a list of things that are needed to fully match Python syntax?
If I understand what you want here, same as for a normal string, "\\(1)" (backslashes needs to be quoted with a backslash).
As far as loading time, I got the following:
“”“julia
julia> @time using PyFormattedStrings
0.192073 seconds (324.86 k allocations: 21.305 MiB, 1.97% compilation time)
“””
almost twice as slow loading, and twice as much memory, as StrFormat. This is with nightly.
“”“julia
julia> @time using StrLiterals,StrFormat
0.104242 seconds (182.17 k allocations: 11.804 MiB, 3.54% compilation time)
“””
Thanks! I see that = isn’t implemented, that’s one of the things that I like to use, for centering the output in the field.
What I really find useful is the f"\%(...) formatting, which is based on Tom Breloff’s PR from 5 years or so ago to Formatting.jl, which was never merged in - which was one of the major reasons I created Format.jl (also, Formatting.jl at that point was not being maintained, for a couple years IIRC).
That allows you do set up defaults based on the type of the argument - as well as override the defaults with keyword arguments, so you don’t need to specify “e” for floating point, “d” for integer, “s” for string, it will pick those up based on the type, and you can easily control all of the parameters for how things are formatted.
I do think that’s the most convenient formatted output capability that I’ve seen in any language that I’ve worked with.
That’s interesting. I reproduced that with 1.6.1 as well on my laptop, but for 1.7, I still get better with StrFormat:
While I totally agree, that for these subsecond times, it doesn’t matter that much, but I am intrigued by what might have slowed down using PyFormattedStrings by 3.6x between Julia 1.6.1 and today’d build of 1.7.
No, I think I must have! Thanks for pointing that out to me! Definitely a bug somewhere in my parsing code, I’ll have to fix that!
Which is why I wouldn’t want to depend on Printf - I can fix any issues in Format.jl, and also not have it depend on a particular version of Julia (important for having all of the capabilities working for people who are sticking to the LTS version).
Indeed, there are both pros and cons. PyFormattedStrings used Formatting.jl when I first published it, but later switched to Printf. Main advantages were better compatibility for features I care about, and performance.
Formatting templates/deferred formatting, with the ff"" macro to create a formatting function:
julia> tmpl = ff"age {age: 3d}, wt {weight:05.1f}, curyear {yr:d}"
# values are taken from the properties of the passed struct:
julia> tmpl((age=56, weight=87.5, yr=2023))
"age 56, wt 087.5, curyear 2023"
# or from the scope of tmpl definition:
julia> yr = 2023
julia> tmpl((age=56, weight=87.5))
"age 56, wt 087.5, curyear 2023"
Support variable width and precision on Julia 1.10+, with the same syntax as Python does:
julia> x = 12
julia> w = 10
julia> p = 4
julia> f"{x:{w}.{p}d}"
" 0012"
PyFormattedStrings uses stdlib Printf, it just prepares the formatting string in the printf format and passes it.
This approach makes it automatically benefit from reliability of Printf and any improvements/bugfixes there!