It seems that string interpolation works differently depending on whether the string consists entirely of a single interpolation:
string(F::Foo) = F.a
F = Foo("bar")
"$F" # equals "bar"
"$F$F" # equals Foo("bar")Foo("bar")
"$(F)baz" # equals Foo("bar")baz
I have figured out from other threads that I can fix this issue by defining a
show method for my types, but both the behavior and the solution strike me as unexpected.
Seems like a bug to me. Can you file an issue?
No. It’s not a bug. You are overwriting function you shouldn’t have which hides the implementation. These case are impossible to eliminate for cases where we provide “dispatch functions” (functions that provide user API but dispatches to other overridable functions for custimization).
Ah, I missed that the example was overloading
string directly and thought it was overloading
show which is what you should do here.
Thanks for the clarification. I can say that the reason for my confusion is that the docs include the sentence “Both concatenation and string interpolation call
string to convert objects into string form.” Given that information, overloading
string seems like the right thing to do (or at least, it seems like it should work).
I thought so too at first, but once you know how output in Julia works, it makes perfect sense to overwrite
show. In short, there are different displays offering possibly different rendering of different MIME types with a fallback to plain-text stdout. That’s how for example a Julia Jupyter notebook can just inline display images after loading them, without explicit
show of the resulting object.
I’m familiar with the multimedia display system, but I don’t think of it as necessarily intertwined with string interpolation. In any case, there remains the question of how
"$F$F" can possibly give different results if the latter is simply calling
I investigated this just now, and here’s what I found:
string directly, while
print_to_string, which in turn calls
print, which in turn calls
show. This defaults to
show_default if no custom
show method is provided, and that’s where
Foo(3) comes from.
So I have two conclusions, unless I am overlooking something: (1) it still strikes me as unexpected that
"$F" is treated differently from
"$F$F"—though maybe this is unavoidable, and (2) the statement in the documentation about string interpolation calling
string seems to not be accurate.
It is not. You can just check
Meta.@lower. They are just
string(F, F). Unless you actually want them to return exactly the same value (I assume you don’t), this is as similar as you can get to.
string is the “dispatch” function I mentioned above and no there’s no way around this.
Or basically you are treating them differently by overloading
string for only one of them, not julia…
There’s no code bug here. PR to improve and/or correct docs are certainly always welcome.
Also the doc about "string interpolation calling
string" is correct that’s exactly what it use, just not on each argument individually. Since it mentions it with concatenation, there should also be little ambiguity but I can see how it could be misleading. Again, PR to improve docs are always welcome.
Ah, that makes perfect sense.
string is being called in its multi-argument form, and that does not call the single-argument method. The docs are fine, I just managed to misunderstand anyway. Thanks for explaining.
The help text for
Create a string from any values, except nothing, using the print function.
This is accurate. If you define
print (which falls back to
show), that method will be used by string interpolation. This is done so that for many-argument string interpolations (or calls to
string) the output can be allocated just once: we create an IOBuffer,
print each argument into it, then turn that into a String.