# Best way to specify a filename inside a function

**URL:** <https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263>\
**Category:** New to Julia\
**Created:** [April 29, 2022, 5:05pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263 "2022-04-29T17:05:02Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![chadagreene](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chadagreene/32/34924_2.png) [@chadagreene](https://discourse.julialang.org/u/chadagreene)\
**Post date:** [April 29, 2022, 5:05pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/1 "2022-04-29T17:05:02Z")

</div>

I’m writing a package containing a function that will load a data file, let’s call it `data.txt`. I’m assuming the user has already obtained `data.txt` from some other source, and the file exists _somewhere_ on their computer.

What’s the best way to tell `myfunction()` where on the user’s computer to find `data.txt`?

Here’s how I would do it if I knew where users put their data:

```julia
function myfunction(input1,input2)

    filename = "path/to/dataset/data.txt"; 

    f = open(filename); 
    # Do some cool stuff...
    close(f)
end

```

I could alternatively make `filename` one of the inputs to `myfunction`; however, I don’t want to force the user to type a long and difficult-to-remember filename every time they use my function.

Is there an elegant solution that would allow users to point `myfunction()` to the correct `filename` one time, then never have to think about it again?

---

<div class="post-metadata">

**Author:** ![mbaz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbaz/32/17295_2.png) [@mbaz](https://discourse.julialang.org/u/mbaz)\
**Post date:** [April 29, 2022, 5:22pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/2 "2022-04-29T17:22:44Z")

</div>

I don’t think it’s very elegant, but a simple solution would be to have the user declare the file path in an environmental variable. See [Environment Variables · The Julia Language](https://docs.julialang.org/en/v1.7/manual/environment-variables/)

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [April 29, 2022, 5:24pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/3 "2022-04-29T17:24:22Z")

</div>

[Preferences.jl](https://github.com/JuliaPackaging/Preferences.jl) allows something like this:

```julia
function set_datapath(path::String)
    @set_preferences!("datapath" => path)
end

function get_datapath()
    return @load_preference("datapath")
end

```

If `data.txt` can be downloaded from a fixed location over https, [DataDeps](https://github.com/oxinabox/DataDeps.jl) offers a more robust & elegant solution.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [April 29, 2022, 5:28pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/4 "2022-04-29T17:28:40Z")

</div>

> [@chadagreene](#):
>
> Is there an elegant solution that would allow users to point `myfunction()` to the correct `filename` one time, then never have to think about it again?

Tell your users to define a variable `filename = ...` and then pass this to `myfunction(input1, inputs2, filename)`. That way, they only have to type it once. (You could even put this in a TOML file or similar and load a whole dictionary of preferences at once, ala Preferences.jl as suggested above … but I would still recommend passing that preference dictionary explicitly rather than using globals.)

Of course, you _could_ alternatively use global state, e.g. an environment variable as suggested above, or better yet:

```julia
default_filename = nothing
function myfunction(input1,input2; filename=default_filename)
    global default_filename = filename # remember it for next time
    # ... do stuff
end

```

so that you only have to pass the filename once and it “remembers” it on future calls. Or the user could even just set `default_filename` directly.

But this style, while tempting, leads to fragile software. It means that the behavior of `myfunction` can be unexpectedly altered by changes in hidden global state. It makes it hard to _compose_ different pieces of code because they can suddenly interfere with one another. Google _“global variables bad”_ for lots of discussions of why you should be cautious about using global state in _any_ language.

This is not to say that you should _never_ use global state. There are situations where it is impossible to avoid, e.g. system-configuration details that can only have one set of values in a given Julia run. But it is good to be wary of globals, and it is good to have an “escape hatch” where the user can pass an explicit parameter to override the global default (as in my example above; see also the `rng` parameter to Julia’s random-number routines).

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [April 29, 2022, 8:41pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/5 "2022-04-29T20:41:04Z")

</div>

Have you thought about using a pop-up window to navigate and choose the file? For example:

```julia
using NativeFileDialog

function myfunction(input1, input2)
    # code
    filename = pick_file(filterlist = "txt, TXT")
    # more code
end

myfunction(1, 2)

```

---

<div class="post-metadata">

**Author:** ![chadagreene](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chadagreene/32/34924_2.png) [@chadagreene](https://discourse.julialang.org/u/chadagreene)\
**Post date:** [May 3, 2022, 10:23pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/6 "2022-05-03T22:23:48Z")

</div>

> [@stevengj](#):
>
> Tell your users to define a variable `filename = ...` and then pass this to `myfunction(input1, inputs2, filename)` . That way, they only have to type it once.

Thanks for the suggestions, but as I understand it, users would then need to manually enter `"path/to/dataset/data.txt"` every time they call `myfunction`. The goal is to let users enter this file path just once, and store that information somewhere, even if the user restarts their computer, or if the package repo gets updated.

If I could, I would simply tell users to “Edit the filename on line XX of `myfunction.jl`”, but Julia functions are read-only, and I don’t entirely understand how future changes I make to the package might (or might not) overwrite any manual changes the user makes.

If I add a line to Project.toml like:

```julia
filename_for_myfunction = "path/to/dataset.txt"

```

1. Can users manually edit the path?
2. Will users’ manual edits be overwritten if the package repo gets updated?
3. How do I get `f = open(filename)` to point to `filename_for_myfunction` in Project.toml?

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [May 3, 2022, 11:15pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/7 "2022-05-03T23:15:55Z")

</div>

> [@chadagreene](#):
>
> The goal is to let users enter this file path just once, and store that information somewhere, even if the user restarts their computer, or if the package repo gets updated.

This sounds like a configuration file. [Reddit - Dive into anything](https://www.reddit.com/r/Julia/comments/mrzxmq/question_write_a_configuration_file/) If there’s not enough state to justify saving to a file, perhaps the user can set an environment variable.

---

<div class="post-metadata">

**Author:** ![chadagreene](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chadagreene/32/34924_2.png) [@chadagreene](https://discourse.julialang.org/u/chadagreene)\
**Post date:** [May 3, 2022, 11:46pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/8 "2022-05-03T23:46:31Z")

</div>

The environment variable solution _seems_ like it’s the way to go. I could easily tell the user to type this into the REPL:

```julia
ENV["MyFilename"] = "path/to/dataset/data.txt"

```

and when I do it, it works beautifully at first:

```julia
julia> ENV["MyFilename"]
"path/to/dataset/data.txt"

```

but when I restart VS Code and try to access MyFilename, it has now vanished:

```julia
julia> ENV["MyFilename"]
ERROR: KeyError: key "MyFilename" not found
Stacktrace:
 [1] (::Base.var"#623#624")(k::String)
   @ Base ./env.jl:79
 [2] access_env
   @ ./env.jl:43 [inlined]
 [3] getindex(#unused#::Base.EnvDict, k::String)
   @ Base ./env.jl:79
 [4] top-level scope
   @ REPL[6]:1

```

Is there a simple way to make an environment variable permanent?

---

<div class="post-metadata">

**Author:** ![mbaz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbaz/32/17295_2.png) [@mbaz](https://discourse.julialang.org/u/mbaz)\
**Post date:** [May 4, 2022, 12:26am UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/9 "2022-05-04T00:26:02Z")

</div>

Put it in Julia’s startup file maybe? On Linux, it is `~/.julia/config/startup.jl`.

You can also set the variable in the shell when invoking Julia:

```julia
$ MyFilename="path/to/dataset/data.txt" julia

```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [May 4, 2022, 12:34am UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/10 "2022-05-04T00:34:10Z")

</div>

> [@chadagreene](#):
>
> The goal is to let users enter this file path just once, and store that information somewhere, even if the user restarts their computer, or if the package repo gets updated.

Sounds like you want a to set a global package preference? See [GitHub - JuliaPackaging/Preferences.jl: Project Preferences Package](https://github.com/JuliaPackaging/Preferences.jl)

Basically, the question is whether you want this file path to be globally set for every time they use your package in any context, or globally set per project environment, or whether it is local to some script, or …

---

<div class="post-metadata">

**Author:** ![chadagreene](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chadagreene/32/34924_2.png) [@chadagreene](https://discourse.julialang.org/u/chadagreene)\
**Post date:** [May 4, 2022, 12:43am UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/11 "2022-05-04T00:43:35Z")

</div>

> [@mbaz](#):
>
> Put it in Julia’s startup file maybe? On Linux, it is `~/.julia/config/startup.jl` .

I’m excited because this seems like a very simple and straightforward solution, which won’t add the clutter or potential breakpoints of extra packages like Preferences.jl. The only hangup now, is how do I actually open startup.jl? I feel like I’m missing something obvious.

```julia
julia> @edit("~/.julia/config/startup.jl")
ERROR: expression is not a function call or symbol
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] top-level scope
   @ REPL[13]:1

julia> @edit startup
ERROR: expression is not a function call or symbol
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] top-level scope
   @ REPL[14]:1

julia> @edit startup.jl
ERROR: UndefVarError: startup not defined
Stacktrace:
 [1] top-level scope
   @ /Applications/Julia-1.7.app/Contents/Resources/julia/share/julia/stdlib/v1.7/InteractiveUtils/src/macros.jl:72

```

---

<div class="post-metadata">

**Author:** ![mbaz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbaz/32/17295_2.png) [@mbaz](https://discourse.julialang.org/u/mbaz)\
**Post date:** [May 4, 2022, 12:51am UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/12 "2022-05-04T00:51:14Z")

</div>

Use `edit` instead of `@edit`. Also, it seems that `edit` does not map `~` to your home directory, so you may have to run `edit("/home/<username>/.julia/config/startup.jl")`.

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [May 4, 2022, 2:37pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/13 "2022-05-04T14:37:59Z")

</div>

> [@chadagreene](#):
>
> when I restart VS Code and try to access MyFilename, it has now vanished

Someone has suggested changing the julia startup file, but in general (ie., independent of Julia) persistent environment variable settings must be made somewhere like .profile on Unix-like systems or in system properties in Windows.

---

<div class="post-metadata">

**Author:** ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)\
**Post date:** [May 4, 2022, 2:45pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/14 "2022-05-04T14:45:12Z")

</div>

I’m not sure from your question whether `data.txt` is the same for everyone or different for each user? If it’s the same maybe you could just distribute it with the package as an artifact?

[https://pkgdocs.julialang.org/v1/artifacts/](https://pkgdocs.julialang.org/v1/artifacts/)

---

<div class="post-metadata">

**Author:** ![alex-s-gardner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alex-s-gardner/32/30210_2.png) [@alex-s-gardner](https://discourse.julialang.org/u/alex-s-gardner)\
**Post date:** [May 5, 2022, 2:39pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/15 "2022-05-05T14:39:22Z")

</div>

@chadagreene if you don’t want to mess with environmental variables, what about having a function that reads in a dependencies txt file from the package location with all of the unique paths that are needed from the user. If the path is not found -or- the path is to the wrong file then the function prompts the user to input the correct path which the function then saves to the dependencies txt file? Maybe this already exists somewhere or is simply duplicating suggestions from above.

---

<div class="post-metadata">

**Author:** ![chadagreene](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chadagreene/32/34924_2.png) [@chadagreene](https://discourse.julialang.org/u/chadagreene)\
**Post date:** [May 5, 2022, 2:44pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/16 "2022-05-05T14:44:10Z")

</div>

> [@alex-s-gardner](#):
>
> what about having a function that reads in a dependencies txt file from the package location

That was my first line of thinking, but aren’t files in Julia packages read-only? Also, the location of files in a Julia package is pretty opaque (kept in hidden folders), which adds an extra layer of burden that I don’t want to put on users.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [May 5, 2022, 3:34pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/17 "2022-05-05T15:34:15Z")

</div>

This is why you should use Preferences.jl, which is the official solution for package-wide preferences.

> [@chadagreene](#):
>
> which won’t add the clutter or potential breakpoints of extra packages like Preferences.jl.

Having a dependency on an additional package is extremely easy in Julia and is mostly transparent to users. I’m not sure what you mean by “clutter” … it doesn’t even appear in the package status listing if you only list something as an internal dependency of your package. (Indeed, since Preferences.jl is [currently required by 4376 packages](https://juliahub.com/ui/Packages/Preferences/pWSk8/1.3.0?page=2) it is probably already installed on most people’s machines.)

As a centrally supported solution (Preferences.jl is by a [core Julia developer](https://github.com/staticfloat) and is used by thousands of packages), it’s _much_ less likely to lead to breakage than something you cobble together yourself in your first few weeks of using Julia.

---

<div class="post-metadata">

**Author:** ![cgeoga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cgeoga/32/216186_2.png) [@cgeoga](https://discourse.julialang.org/u/cgeoga)\
**Post date:** [May 5, 2022, 4:01pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/18 "2022-05-05T16:01:50Z")

</div>

If you expect users to call the function a bunch of times for the same file input but potentially expect users to also want to do this with multiple files (and really don’t want to add a dependency), you could have an inner function that returns a closure:

```julia
function myfunction_forfile(filename)
  return (args...)->begin # this should probably be in a let-block
    f = open(filename)
    # do some cool stuff...
    close(f)
    return #something
  end
end

myfunction_f1 = myfunction_forfile(filename)
# now call like normal:
myfunction_f1(args...)

```

Or you could create a struct that carries the information of the file and has the appropriate methods:

```julia
struct FileForThing
  # fields
end

function FileForThing(filename)
  # open that filename, parse it or whatever, put what you need into a struct
end

function (F::FileForThing)(args...)
  # do your cool stuff
end
 
# now like this:
struct_with_file1 = FileForThing(filename)
# call like normal:
struct_with_file1(args...)

```

In both of these cases, your user just needs to put the file name in once and then they don’t have to deal with it again.

But depending on how often you expect that file to change or how often the function that depends on it gets called or whatever, this would probably make more or less sense. Unless you expect users to depend on several different files dynamically, it’s probably better to just use `Preferences.jl` as suggested above.

---

<div class="post-metadata">

**Author:** ![chadagreene](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chadagreene/32/34924_2.png) [@chadagreene](https://discourse.julialang.org/u/chadagreene)\
**Post date:** [May 5, 2022, 5:04pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/19 "2022-05-05T17:04:16Z")

</div>

> [@stevengj](#):
>
> you should use Preferences.jl, which is the official solution for package-wide preferences.

I appreciate you pressing this, as I’m trying to learn how to think in a more Julian way. I suspect that Preferences.jl might ultimately be the best way to solve this problem, but I’m trying to understand why such a complicated solution is necessary for such an incredibly simple task.

I’ll also note that part of my reluctance to using Preferences.jl is that I don’t totally understand how it works. It’s sort of a black box to me, so I’m just a little unsure about depending on it.

> [@stevengj](#):
>
> I’m not sure what you mean by “clutter”

More stuff. More dependencies. More moving parts. More things to go wrong. More packages to load. More code to maintain. More questions about how different users of my package might experience different issues, depending on their setup.

It’s the [KISS Principle](https://en.wikipedia.org/wiki/KISS_principle) or [Occam’s razor](https://en.wikipedia.org/wiki/Occam%27s_razor): I have a _very simple_ task to accomplish, and dependence on extra packages that I don’t understand feels like I’m violating the “keep it simple” rule.

> [@stevengj](#):
>
> it’s _much_ less likely to lead to breakage than something you cobble together yourself in your first few weeks of using Julia.

No doubt! But even incorporating Preferences.jl feels like one extra thing I could screw up. That’s why I was hoping for a simple solution that wouldn’t require extra packages for such a simple task.

The solution to this exact problem in Matlab has always been straightforward and robust: I tell users to type `open myfunction` into the command window, and I say “edit Line XX of the function to indicate the correct file path to the data file.” And that’s it–it’s easy for users and doesn’t require installing extra packages or anything overcomplexificated. I guess I’m a little bit confused about why such a simple task would require any extra packages or “cobbling together” _anything_ in Julia.

So again, I will probably end up using Preferences.jl thanks to your suggestion. It’s probably the best solution available, but getting comfortable with it require a learning curve.

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [May 5, 2022, 5:15pm UTC](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263/20 "2022-05-05T17:15:20Z")

</div>

> [@chadagreene](#):
>
> robust: I tell users to … edit … the function

😲 In my 30+ years of commercial software development, robust and telling users to edit source code have never gone together. But then again, I’ve never worked with Matlab.

[Next page](https://discourse.julialang.org/t/best-way-to-specify-a-filename-inside-a-function/80263.md?page=2)
