# How to convert \_\_source\_\_.file to string?

**URL:** <https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533>\
**Category:** General Usage\
**Created:** [August 14, 2019, 1:39pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533 "2019-08-14T13:39:22Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![epogrebnyak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/epogrebnyak/32/6287_2.png) [@epogrebnyak](https://discourse.julialang.org/u/epogrebnyak)\
**Post date:** [August 14, 2019, 1:39pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533/1 "2019-08-14T13:39:22Z")

</div>

I’m trying to extract filename as string from ` __source__.file`. When running code below everything works, `typeof(g)` is `String` and it contains path filename.

```julia
macro file1()
  return QuoteNode( __source__.file)
end

f = @file1
g = String(@file1)

```

When trying to put code above in single macro, conversion to string fails:

```julia
macro file2() # this is line 13
  x = QuoteNode( __source__.file)
  return String(x)
end

h = @file2 #this is line 16

```

Error stack

```julia
ERROR: LoadError: LoadError: MethodError: no method matching String(::QuoteNode)
Closest candidates are:
String(!Matched::String) at boot.jl:318
String(!Matched::Array{UInt8,1}) at strings/string.jl:39
String(!Matched::Base.CodeUnits{UInt8,String}) at strings/string.jl:77

Stacktrace:
[1] @file2(::LineNumberNode, ::Module) at trace.jl:13
in expression starting at trace.jl:16
in expression starting at trace.jl:16

```

How can one extact filename as string from ` __source__.file` in a single macro or function withtout arguements?

---

<div class="post-metadata">

**Author:** ![epogrebnyak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/epogrebnyak/32/6287_2.png) [@epogrebnyak](https://discourse.julialang.org/u/epogrebnyak)\
**Post date:** [August 14, 2019, 1:45pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533/2 "2019-08-14T13:45:54Z")

</div>

The closest I could get is code below. It works in the same script, but woudl point to a wrong file is caller froma different module though.

```julia
function file3() 
  return String(@file1)
end

h = file3()

```

So remaining part is - how `file2` can work as a single macro?

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [August 14, 2019, 2:14pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533/3 "2019-08-14T14:14:52Z")

</div>

Please understand the code, e.g. what each function does and why you need it, rather than blindly copying the code and trying things.

> [@epogrebnyak](#):
>
> `return QuoteNode( __source__.file)`

` __source__.file` is a `Symbol`. You basically want the macro to return it. For a normal value you’ll just return it directly but since macros handles a few syntax types (`Expr`, `Symbol`, etc) specially you need to stop it from doing that. That’s why you put it in a `QuoteNode`. In another word, that `QuoteNode` is there for the macro, not for the result.

That’s why you should not use `QuoteNode` before passing it to `String`. If anything, the `QuoteNode` should be on the `String` after you created it. It’s not necessary though since `String` isn’t a special syntax type.

AFAICT, what you want to do is exactly `@ __FILE__ ` so you can also find the answer by [reading the source code of the macro](https://github.com/JuliaLang/julia/blob/fe9de990d130cb9ac58cb66332fe95cc72853c05/base/loading.jl#L1469), which you can find by searching for ` __FILE__ ` on github. Again, please understand it before using the implementation. If you don’t, feel free to ask here again about the “why” part.

---

<div class="post-metadata">

**Author:** ![thautwarm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thautwarm/32/37760_2.png) [@thautwarm](https://discourse.julialang.org/u/thautwarm)\
**Post date:** [August 14, 2019, 2:16pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533/4 "2019-08-14T14:16:12Z")

</div>

Hi, this should work

```julia
macro file2() # this is line 13
  x = QuoteNode( __source__.file)
  return :($String($x))
end

```

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [August 14, 2019, 2:29pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533/5 "2019-08-14T14:29:24Z")

</div>

Yes it should work but is unnecessarily slow and complicated… You are just quoting and unquoting the result. This is useful in certain cases when you want to run the code (`String` in this example) but that’s not the case here.

---

<div class="post-metadata">

**Author:** ![thautwarm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thautwarm/32/37760_2.png) [@thautwarm](https://discourse.julialang.org/u/thautwarm)\
**Post date:** [August 14, 2019, 4:16pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533/6 "2019-08-14T16:16:52Z")

</div>

Dear chaoge, I was just answering his question literally.

---

<div class="post-metadata">

**Author:** ![epogrebnyak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/epogrebnyak/32/6287_2.png) [@epogrebnyak](https://discourse.julialang.org/u/epogrebnyak)\
**Post date:** [August 14, 2019, 10:31pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533/7 "2019-08-14T22:31:34Z")

</div>

I was under impression from documentation `QuoteNode` is needed to access the contents of ` __source__ `, while in fact I needed `String( __source__.line)` for usable filename as you tend to suggest in your helpful answer.

Here is what documentation says about accessing ` __source__.line`, while in fact as an uneducated user of ` __source__ ` I need to hear about `String( __source__.line)` and probably never know of `QuoteNode`:

> The location information can be accessed by referencing ` __source__.line` and ` __source__.file` :

```julia
julia> macro __LOCATION__ (); return QuoteNode( __source__ ); end
@ __LOCATION__ (macro with 1 method)

julia> dump(
            @ __LOCATION__ (
       ))
LineNumberNode
  line: Int64 2
  file: Symbol none

```

I was also caught by file equalling to `nothing` when using `include()` as well as a hint in the documentation that file name may not be recorded at all:

> Source location information is represented as `(line line_num file_name)` where the third component is optional (and omitted when the current line number, but not file name, changes).

Reading through this makes one a bit confused why exactly one not simply getting a filename.

> AFAICT, what you want to do is exactly `@ __FILE__ `

Not exactly, I needed a function or a macro without arguments that will trace the location on invocation in caller script, not location at point of definition at source. More [here](https://stackoverflow.com/a/57502717/1758363), if you are interested.

> so you can also find the answer by [reading the source code of the macro](https://github.com/JuliaLang/julia/blob/fe9de990d130cb9ac58cb66332fe95cc72853c05/base/loading.jl#L1469)

That’s single most useful point of reference on my question, wish it was in the docs:

```julia
macro __FILE__ ()
    __source__.file === nothing && return nothing
    return String( __source__.file)
end

```

Finally, `String( __source__.file)`! Genuine thanks for taking me to there.

---

<div class="post-metadata">

**Author:** ![epogrebnyak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/epogrebnyak/32/6287_2.png) [@epogrebnyak](https://discourse.julialang.org/u/epogrebnyak)\
**Post date:** [August 14, 2019, 10:43pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533/8 "2019-08-14T22:43:14Z")

</div>

> rather than blindly copying the code and trying things.

That’s what people do when lacking good reference or prior knowledge.

> Again, please understand it before using the implementation. If you don’t, feel free to ask here again about the “why” part.

I appreciate your time and effort in trying to explain. My remaining pain point is why ` __source__.file` is a `Symbol` to start with, not a `String`? ` __source__.line` is an integer, not a `Symbol`. What are the uses of ` __source__.file` as a `Symbol` other than converting it to a string?

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [August 14, 2019, 10:43pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533/9 "2019-08-14T22:43:55Z")

</div>

> [@epogrebnyak](#):
>
> Not exactly, I needed a function or a macro without arguments that will trace the location on invocation in caller script, not location at point of definition at source.

… I mean `@ __FILE__ ` is what you want `@file2` to do…

---

<div class="post-metadata">

**Author:** ![epogrebnyak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/epogrebnyak/32/6287_2.png) [@epogrebnyak](https://discourse.julialang.org/u/epogrebnyak)\
**Post date:** [August 14, 2019, 10:48pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533/10 "2019-08-14T22:48:35Z")

</div>

The result is exactly as `@ __FILE__ `, but the caller function/macro should not have arguments, so passing it explicitly as an argument was not an intended option.

In my scenario the user writes something like:

`loc = @trace`

instead of:

`loc = trace(file=@_FILE_, line=@_line__)`

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [August 14, 2019, 10:59pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533/11 "2019-08-14T22:59:40Z")

</div>

> [@epogrebnyak](#):
>
> That’s what people do when lacking good reference or prior knowledge

Yes, I know. It’s what a lot of people do and that’s bad. What I’m saying is that you should start from the basic questions, e.g. you can ask why is `QuoteNode` needed to access ` __source__ ` and you can expect a detailed explaination about why that’s not actually the case. I know it’s hard to resist but please try to understand every part of a code you use. That way you won’t get the very strange, yet somewhat informative, error you get from `@file2` to begin with. (I would also say that the question below about `Symbol` vs `String` is certainly on the right track)

> [@epogrebnyak](#):
>
> My remaining pain point is why ` __source__.file` is a `Symbol` to start with, not a `String` ?

It shouldn’t really be a problem for any user. `Symbol` is a pretty common type that is very easy to convert to `String` if needed. One question you should ask yourself here is whether you actually need a `String`. Functionwise, there isn’t a difference between the two here (both of them can store the same info) but `Symbol` saves memory in this case since the user of it will never be freed and it is referenced many time from the same file. (It is not common to have a similar usage pattern so don’t use that in your own code unless you understand the trade-off much better).

> [@epogrebnyak](#):
>
> The result is exactly as `@ __FILE__ ` , but the caller function/macro should not have arguments, so passing it explicitly as an argument was not an intended option.

… = = … Errr, I know the thing in your actual code is completely different. I also know that you want to know about the implementation rather than using the macro directly which is why I pointed you there… I know you already successfully identify your issue to be implementing `@file2` so I’m just saying that `@file2` is `@ __FILE__ `. By “you want `@ __FILE__ `” I never meant that you should use `@ __FILE__ ` in any way but what you wanted to implement in the simplified/minimized problem is actually `@ __FILE__ `… Hopefully that clears up what I meant, although it probably doesn’t matter…

---

<div class="post-metadata">

**Author:** ![epogrebnyak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/epogrebnyak/32/6287_2.png) [@epogrebnyak](https://discourse.julialang.org/u/epogrebnyak)\
**Post date:** [August 14, 2019, 11:12pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533/12 "2019-08-14T23:12:16Z")

</div>

> One question you should ask yourself here is whether you actually need a `String` .

I think I do for reading the file contents.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [August 14, 2019, 11:13pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533/13 "2019-08-14T23:13:05Z")

</div>

> [@yuyichao](#):
>
> Yes, I know. It’s what a lot of people do and that’s bad

I need to push back very strongly against this. Experimentation and parroting is a totally valid method of gaining knowledge. Perhaps it’s not how you work — and that’s fine! I find threads are much more successful when folks are actively trying things and posting what didn’t work. Further, you cannot expect someone just learning the language to always have a 100% thorough and accurate understanding of their code before running anything. They learn some bits, parrot some others, until they gain a more robust understanding of their knowledge and how things work.

_Please be a little more gracious_ — I do not want folks to be timid about posting things they tried.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [August 14, 2019, 11:33pm UTC](https://discourse.julialang.org/t/how-to-convert-source-file-to-string/27533/14 "2019-08-14T23:33:06Z")

</div>

> [@epogrebnyak](#):
>
> I think I do for reading the file contents.

That’s fair.

> [@mbauman](#):
>
> Experimentation and parroting is a totally valid method of gaining knowledge.

Not completely and that’s also why we get a lot of invalid code…  
By experiementing you collect data of what works and what not. It’s only when you know why you get the result you get that you get knowledge. Things that seems to work doesn’t really mean it works for the reason you think it works and I don’t think I need to give more examples about the undefined unsafe code that people have written.

To be clear, I have absolutely no problem with trying things around, but blinding trying things until something works is not acceptable (not what’s happening here) and when things work you should certainly have some understanding of why it works. In this case,

> I was under impression from documentation `QuoteNode` is needed to access the contents of ` __source__ `

is certainly the problem. If @epogrebnyak actually just get this impression by reading the text from the document, then I apologize and the doc text should be fixed instead. If this idea was concluded by reading the code (including the code examples in the doc), then that was exactly my point. Copying and pasting code without understanding is going to lead to problem like this in the future. For a complex case it might not be practical and you might not need to make any adjustment to the copied code so it’s probably fine to let it be and simply use it as a blackbox library. For a simple case like this, one should definately understand why something is needed before using the code.

> [@mbauman](#):
>
> I find threads are much more successful when folks are actively trying things and posting what didn’t work. Further, you cannot expect someone just learning the language to always have a 100% thorough and accurate understanding of their code before running anything.

Yes, I agree with this. In fact, given the previous assumption I had absolutely no issue with how this particular issue is tried out. As mentioned above, all my comments about how one should understand better is targeted to the original `@ __LOCATION__ `/`@file1` macro. Had that one be understood (or explained) better, this would not have been an issue to begin with.

I also just realize that by “understand every part of a code” I don’t mean to, well, every bit of the code, if that makes sense. I’m saying that in `macro file1() QuoteNode( __source__.file) end` one should know why `QuoteNode` is there but it’s certainly too much to require understanding the full semantics of macros and `QuoteNode` outside the context of the particular input type/usage pattern. I think this is very basic and I don’t think that’s too much to ask. I also don’t expect people to natually do that and I certainly expect beginners to not do that and run into problem because of it.

> [@mbauman](#):
>
> They learn some bits, parrot some others, until they gain a more robust understanding of their knowledge and how things work.

Exactly. Again, the way this question was asked was perfectly fine. More understanding should have been extracted from the original use of `QuoteNode`.

> [@mbauman](#):
>
> I do not want folks to be timid about posting things they tried.

Again, all tried things in this one is fair for the knowledge known at the time. I’m only commenting on the obvious gap in understanding revealed by it. If I was not clear enough yet, doing what was done in the top post is exactly how you should try things. The result is strange this time because of a missing piece in a prevous learning that could improve easily if you ask a little more everything you get a working code.
