# How to write a program as a Julia package?

**URL:** <https://discourse.julialang.org/t/how-to-write-a-program-as-a-julia-package/80574>\
**Category:** General Usage\
**Tags:** code-organization\
**Created:** [May 5, 2022, 9:48pm UTC](https://discourse.julialang.org/t/how-to-write-a-program-as-a-julia-package/80574 "2022-05-05T21:48:04Z")\
**Posts on this page:** 10\
**Page:** 2

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [May 6, 2022, 8:36pm UTC](https://discourse.julialang.org/t/how-to-write-a-program-as-a-julia-package/80574/21 "2022-05-06T20:36:32Z")

</div>

> [@Nathan\_Boyer](#):
>
> `nclude("build.jl")` into `complicated_build_struct = build(input, complicated_read_struct)` ?

The latter will be easier to debug, because you will have smaller functions to check, test, etc.

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [May 6, 2022, 8:41pm UTC](https://discourse.julialang.org/t/how-to-write-a-program-as-a-julia-package/80574/22 "2022-05-06T20:41:46Z")

</div>

If not a GUI, perhaps tell them to edit an excel spreadsheet? To have them choose files, you can use [NativeFileDialogue.jl](https://github.com/Suavesito-Olimpiada/NativeFileDialog.jl).

---

<div class="post-metadata">

**Author:** ![Nathan\_Boyer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nathan_boyer/32/14825_2.png) [@Nathan\_Boyer](https://discourse.julialang.org/u/Nathan_Boyer)\
**Post date:** [May 6, 2022, 9:19pm UTC](https://discourse.julialang.org/t/how-to-write-a-program-as-a-julia-package/80574/23 "2022-05-06T21:19:09Z")

</div>

> [@Jeff\_Emanuel](#):
>
> Build a GUI?

> [@Nathan\_Boyer](#):
>
> I would eventually like to create a GUI for locating `input.toml` and running `process(input)` , but I don’t know how to do that yet.

> [@lmiq](#):
>
> I would suggest to exemplify with the full path to the file, otherwise if they start Julia by double clicking you are again in trouble.

Hmm, I thought I would be ok regardless of where they run the file from based on the documentation of `@ __dir__ `: _“Expand to a string with the absolute path to the directory of the file containing the macrocall.”_

> [@pdeffebach](#):
>
> If not a GUI, perhaps tell them to edit an excel spreadsheet? To have them choose files, you can use [NativeFileDialogue.jl](https://github.com/Suavesito-Olimpiada/NativeFileDialog.jl).

Yeah, most of the data files I am reading are already `.xlsx`. I wasn’t sure that `.xlsx` was a good medium for reading scalar inputs though. NativeFileDialog.jl seems really useful.

In any case, I can test out some different file types and helper packages (maybe ` __init__ ` too). I just wanted to make sure I wasn’t overlooking some obvious workflow. It sounds like I should still be using a package (and thus a module) but that it would be better to put function calls inside `process` rather than `include` statements, even if that means I need to define containers for everything.

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [May 6, 2022, 9:25pm UTC](https://discourse.julialang.org/t/how-to-write-a-program-as-a-julia-package/80574/24 "2022-05-06T21:25:24Z")

</div>

Give the name of the input file as argument? `julia script.jl arg1 arg2` ([Getting Started · The Julia Language](https://docs.julialang.org/en/v1/manual/getting-started/))

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [May 6, 2022, 9:37pm UTC](https://discourse.julialang.org/t/how-to-write-a-program-as-a-julia-package/80574/25 "2022-05-06T21:37:17Z")

</div>

I think OP’s audience is on Windows and probably doesn’t know how to use the command line.

---

<div class="post-metadata">

**Author:** ![MA\_Laforge](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ma_laforge/32/385_2.png) [@MA\_Laforge](https://discourse.julialang.org/u/MA_Laforge)\
**Post date:** [May 8, 2022, 6:45pm UTC](https://discourse.julialang.org/t/how-to-write-a-program-as-a-julia-package/80574/26 "2022-05-08T18:45:37Z")

</div>

### What if your users had to create this type of script file?

**`user_custom_script.jl_script`** :

```julia
#!JLScript -iq --startup-file=no --project=@GlobalScripting_ASME
using ASME_Materials

#raw"": Allows paths with "\" without escaping (ex: "S:\\Material..."):
data_root = raw"S:\Material Properties"

options = (
	input_file = joinpath(data_root, "Section II-D Tables.xlsx"),
	output_dir = joinpath(data_root, raw"Excel Material Data\AIP Q&T Steels"),
)

result = ASME_Materials.RunTheScript(options)
display(result) #Because: Why not?
:DONE

```

…and execute it from with a right-click in Windows Explorer?

 ![image](https://global.discourse-cdn.com/julialang/original/3X/a/8/a8ba273da46ac397347c5aaa3ca675f4bdc8b4ad.png)

### Example code

→ see: [GitHub - ma-laforge/JuliaScripting.jl](https://github.com/ma-laforge/JuliaScripting.jl)

You could provide (copy) the basic “Scripting interface” from `JuliaScripting.jl`:  
(copying mostly `JuliaScripting/src/install.jl`)

- Creates a sample “shared” Julia environment ( `GlobalScripting_ASME` ).
  - ( `GlobalScripting_ASME` environment is used by sample script [`sample_scripts/sample1.jl_script`](https://github.com/ma-laforge/JuliaScripting.jl/blob/main/sample_scripts/sample1.jl_script).)

- Copies a powershell script ( `launch_julia_script.ps1` ) to the active Julia directory.
  - This might require Windows admin privileges.

- Adds RMB “Execute with Julia” action for `.jl_script` files in Windows Explorer.
  - Also requires Windows admin privileges.

---

<div class="post-metadata">

**Author:** ![Nathan\_Boyer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nathan_boyer/32/14825_2.png) [@Nathan\_Boyer](https://discourse.julialang.org/u/Nathan_Boyer)\
**Post date:** [May 9, 2022, 1:08pm UTC](https://discourse.julialang.org/t/how-to-write-a-program-as-a-julia-package/80574/27 "2022-05-09T13:08:02Z")

</div>

That’s really cool, but admin privileges might be an issue.

---

<div class="post-metadata">

**Author:** ![MA\_Laforge](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ma_laforge/32/385_2.png) [@MA\_Laforge](https://discourse.julialang.org/u/MA_Laforge)\
**Post date:** [May 10, 2022, 2:31am UTC](https://discourse.julialang.org/t/how-to-write-a-program-as-a-julia-package/80574/28 "2022-05-10T02:31:06Z")

</div>

If admin privileges are an issue:

- ✅ You won’t need them to write the `.ps1 file` … since it gets copied to your Julia install directory (which presumably was installed without admin privileges either)
- ❗ You would only need them to execute/install the `.inf` file to register the RMB action item in Windows Explorer.

✅ But since the `.inf` file is relatively simple/easy to decode, you can probably convince someone in IT to install it for you:

```nohighlight
[version]
signature="$CHICAGO$"

[DefaultInstall]
AddReg = Explore.AddReg

[Strings]
ACTION_TEXT = "Execute with Julia v1.7.2"
ACTION_CMD = "powershell -WindowStyle hidden -ExecutionPolicy Bypass -Command "C:\APPS\Julia-1.7.2\bin\launch_julia_script.ps1" '%1'"

[Explore.AddReg]
HKCR,SystemFileAssociations\\.jl_script\\shell\\JLScript-v1.7.2,,,%ACTION_TEXT%
HKCR,SystemFileAssociations\\.jl_script\\shell\\JLScript-v1.7.2\\command,,,%ACTION_CMD%

```

(It gets installed by double-clicking on this file if it has a `.inf` extension!)

---

<div class="post-metadata">

**Author:** ![MA\_Laforge](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ma_laforge/32/385_2.png) [@MA\_Laforge](https://discourse.julialang.org/u/MA_Laforge)\
**Post date:** [May 10, 2022, 3:10am UTC](https://discourse.julialang.org/t/how-to-write-a-program-as-a-julia-package/80574/29 "2022-05-10T03:10:08Z")

</div>

### RE:

> [@Nathan\_Boyer](#):
>
> ```julia-auto
> function process(input)
> include(joinpath(@ __DIR__ , "read.jl"))
> include(joinpath(@ __DIR__ , "build.jl"))
> include(joinpath(@ __DIR__ , "write.jl"))
> include(joinpath(@ __DIR__ , "plot.jl"))
> end
> 
> ```

> [@Nathan\_Boyer](#):
>
> It is not working for me that way. It tries to read from the package directory rather than from the package/src directory if I do not include `@ __DIR__ ` .

That’s because you shouldn’t run `include()` from within a function (much in the same way you shouldn’t run `import`/`using` from within a function).

Doing so appears to run `include()` in the calling scope… and so you start getting strange behaviours. I am almost certain running `include()` from within a function is bad practice, and I would personally avoid it. `include()` isn’t _exactly_ the same as `#include` in C/C++.

### A small tweak to your methodology

What you should instead be doing is something more like:

```julia-auto
include("ReadTables.jl")
include("BuildTables.jl")
include("WriteTables.jl")
include("PlotTables.jl")

function process(options)
    read_input_tables(options) # defined in ReadTables.jl
    build_more_tables(options) # defined in BuildTables.jl
    write_some_tables(options) # defined in WriteTables.jl
    plot_important_tables(options) # defined in PlotTables.jl
    return results #written somewhere in the module's global namespace, I suppose
end

```

This coding shift requires encapsulating much of the code you wrote in the global namespace (of `*Tables.jl` files) inside these `read_input_tables()`/`build_more_tables()`/… functions. You can leave the code in their respective files - just wrap them inside one-or-more function call(s).

If you want to keep the data around inside the global namespace: just remember to declare/tag the variable as global:

```julia-auto
function readtable(...) #This low-level function is fine as it is. No need to change it.

function read_input_tables(options) #New encapsulating function
    #...
    global tableY = readtable(options.inputfilepath, "Table Y-1")
    #...
end

```

### ⚠ No scripting inside modules.

One of the consequences of what @mkitti mentioned:

> [@mkitti](#):
>
> This will then execute when you do `using Package` .

is that you shouldn’t write your `*Tables.jl` files as conventional scripts with code running in the global namespace (ie: “global” = not “inside” functions).

That only works for executing files in the REPL. As soon as you wrap files into modules, your non-static, “execution-mode” code should all be written inside one (or-more) functions.

I don’t think this is explicitly stated anywhere (I’m sort of sad to make this realization just now)… but it is a natural consequence of what @mkitti just said.

Only “static” code that can effectively be pre-compiled is allowed to exist outside functions.

### 😄 A more Julia-friendly solution

I have a few more relatively important suggestions for improving your code, but this particular issue seems to be your dominant problem - so I’ll refrain from giving you more confusing tips.

The JuilaScripting.jl sample I provided earlier shows a more Julian way to write your module (I modelled it closely after your `ASME_Materials.jl` module to help you better understand the Matlab-\>Julia transition)

→ 👓 take another look!: [GitHub - ma-laforge/JuliaScripting.jl](https://github.com/ma-laforge/JuliaScripting.jl)

I also tried to add useful comments to the global namespace & ` __init__ ()` functions so you can get a better idea of what should go where.

---

<div class="post-metadata">

**Author:** ![Nathan\_Boyer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nathan_boyer/32/14825_2.png) [@Nathan\_Boyer](https://discourse.julialang.org/u/Nathan_Boyer)\
**Post date:** [May 10, 2022, 1:26pm UTC](https://discourse.julialang.org/t/how-to-write-a-program-as-a-julia-package/80574/30 "2022-05-10T13:26:20Z")

</div>

Thank you so much! I am happy to hear all your suggestions. Give me a few days to try to update my package with the suggestions already provided (maybe longer to figure out the `jl_script`, `.inf`, `.ps1` stuff 😵‍💫). Then I will reach back out to you privately.

[Previous page](https://discourse.julialang.org/t/how-to-write-a-program-as-a-julia-package/80574.md?page=1)
