String interpolation error


#1

I expected the following is equivalent to AssertionError("1 == 1"). But I was thrown an error.

julia> AssertionError($(string(:(1 == 1))))
ERROR: unsupported or misplaced expression $

Why am I wrong? Thanks!


#2

AssertionError takes a String argument (so not sure what is intention of $ interpolation)

Julia-0.6.0> AssertionError(string(:(1 == 1)))
AssertionError("1 == 1")

#3

Thanks, @greg_plowman. In fact, I was trying to reproduce/mimick step by step part of the second line in the first example of the section “Building an advanced macro” on this page. The example is about the macro @assert:

julia> macro assert(ex)
           return :( $ex ? nothing : throw(AssertionError($(string(ex)))) )
       end
@assert (macro with 1 method)

Still confused why a dollar sign is needed in the above example.


#4

The dollar sign is used because the macro returns an Expr. Dollar sign means expression interpolation, so it is used inside of a :(...) quote block. Outside of a quote block, it is misplaced.


#5

To make it more clear, In the example ex is interpolated into the the return expression of the macro. In your use case, you are not interpolating any expression.


#6

Thanks, @chakravala. I understand your explanation - $ is needed because the macro returns an Expr.

I also tried the following:

julia> ex = :(1 == 1)
:(1 == 1)

julia> ex1 = :(AssertionError($(string(ex))))
:(AssertionError("1 == 1"))

julia> eval(ex1)
AssertionError("1 == 1")

julia> ex2 = :(AssertionError(string(ex)))
:(AssertionError(string(ex)))

julia> eval(ex2)
AssertionError("1 == 1")

Since eval(ex1) and eval(ex2) are identical, can I remove the dollar sign in the macro above? Thanks!!


#7

They are only identical because you defined ex in the REPL, so evaluating them gives the same result. However, ex1 can always be evaluated even if ex is not defined in your current scope, while ex2 could not be evaluated if you do not have ex defined in your current scope. So whether you want to use the dollar sign depends on what context you need it for.

Also, what you posted is not a macro, it is an Expr.


#8

Yes, I see. Thanks for the hints. In fact, I’m talking about this in the context of the macro example I posted above:

julia> macro assert(ex)
           return :( $ex ? nothing : throw(AssertionError($(string(ex)))) )
       end
@assert (macro with 1 method)

I can’t remove $ here, can I? Because? Thanks.


#9

It wouldn’t work without the $ there because ex is undefined when the macro evaluates its returned expression. The point of the $ is to insert or “splice” the expression ex into the code that the macro evaluates.


#10

Thanks! So, without $, ex will be expected to be a variable, which, of course, is undefined, right? With $, Julia knows that ex is a placeholder which will be interpolated/spliced at a later time? Am I right?


#11

That is correct, the variable ex is only defined within the macro itself, but is not defined in the evaluation scope of the macro. So you need to insert the value of ex into the expression before it is evaluated, otherwise it will try to look for the value of ex when it is evaluting.


#12

Thank you so much for your help and the patience, buddy!!