Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Julia does not appear to be using string to perform interpolation

The official docs state:

Both concatenation and string interpolation call string() to convert objects into string form

However, the following minimum working example seems to demonstrate otherwise:

type MyType
    x::Int
end
import Base.string
Base.string(m::MyType) = "world"
m = MyType(4)
println("hello $m")
println("hello " * string(m))

The second last line evaluates to hello MyType(4) at the REPL, while the last line evaluates (as expected) to hello world.

So what am I doing wrong?

(I am still on v0.4 but the official doc versions indicate that shouldn't make any difference.)

like image 596
Colin T Bowers Avatar asked Oct 16 '16 02:10

Colin T Bowers


1 Answers

The documentation is perfectly correct:

julia> expand(:(println("hello $m")))
:(println((Base.string)("hello ",m)))

That is to say, println("hello $m") is equivalent to println(string("hello", m)). By the time the code is compiled or interpreted, they are the same thing.

However, your overload

Base.string(m::MyType) = "world"

is not the correct way to overload string. This method only covers the case with a single argument of type MyType. (This is why, incidentally, your code seemed to work for concatenation: that particular example involved calling string on a single argument. The results would have been the same if you had written "$m".) The correct way to overload it is

Base.show(io::IO, m::MyType) = print(io, "world")

which may seem weird at first. The reason this must be overloaded is because string delegates to print which delegates to show.

After updating your minimum working example to

type MyType
    x::Int
end
Base.show(io::IO, m::MyType) = print(io, "world")
m = MyType(4)
println("hello $m")
println("hello " * string(m))

the result is as expected.


As a footnote, note that your example can be more performantly written as

println("hello ", m)

which avoids the creation of intermediate strings. This illustrates why the system is set up so that string calls print which calls show: the IO method is more generic and can print to various forms of IO directly, whereas if it went the other way around, one would have to convert things into strings (requiring temporary allocation and thus poor performance) before sending to IO.

like image 199
Fengyang Wang Avatar answered Oct 23 '22 21:10

Fengyang Wang