So I wanted to move all my common Julia code to a support dir. My filesystem has for 30+ years contained:
$HOME/
Code/
CodeC/
foo/
src/
bar.c
CodeJava/
foo/
src/
com/
mdh/
bar/
Quux.java
et fucking cetera
Build scripts for most languages expect something very like this, and it's easy to import one package's source into another, so I could put common code in a "Marklib" project, and get work done.
Making this happen in Julia was a lot more difficult. With a little help from Slack I made sense of the terrible package documentation for Julia and the incomprehensible errors, and wrote a script juliaMakePackage.zsh:
#!/bin/zsh
if [[ $# -ne 1 ]]; then
echo "Usage: juliaMakePackage.zsh NAME"
exit 1
fi
name=$1
devdir=$HOME/Code/CodeJulia
cd $devdir
julia -E "using Pkg; Pkg.activate(\".\"); Pkg.generate(\"${name}\")"
cd $name
git init
git add .
git commit -m "Initial commit"
cd ..
julia -E "using Pkg; Pkg.develop(PackageSpec(url=\"${devdir}/${name}\"))"
And then added the main dir and all packages I make to ~/.julia/config/startup.jl:
# startup.jl
push!(LOAD_PATH, pwd())
push!(LOAD_PATH, "$(homedir())/Code/CodeJulia")
push!(LOAD_PATH, "$(homedir())/Code/CodeJulia/Marklib")
println("READY $(pwd())")
Now finally I can:
% julia
READY /Users/mdh
julia> using Marklib
julia> Marklib.greet()
Hello World!
julia>
And from there start putting in my libs. Each one needs a package and a startup entry; I may have to automate that by walking my code dir. Waste of several hours figuring that out.
Comments are closed.
Mentions
I don't just drink coffee or booze, watch movies and Internet drama, and look cool. I code sometimes, too! Who knew?!
Carrying on with my experiment in Julia, packaging has another step needed to make references. For instance, Ansi uses Geometry, so:
Geometry/Project.toml:
authors = ["Mark Damon Hughes "]
name = "Geometry"
uuid = "e3172796-a620-11e8-2cbf-612649bb77f8"
version = "0.1.0"
[deps]
Ansi/Project.toml:
authors = ["Mark Damon Hughes "]
name = "Ansi"
uuid = "72992c94-a620-11e8-3d05-55611ea0dbd0"
version = "0.1.0"
[deps]
Geometry = "e3172796-a620-11e8-2cbf-612649bb77f8"
Ansi/Manifest.toml:
[[Geometry]]
repo-rev = "master"
repo-url = "/Users/mdh/Code/CodeJulia/Geometry"
uuid = "e3172796-a620-11e8-2cbf-612649bb77f8"
version = "0.1.0"
All the boldface code is what I wrote/copy-pasted, the rest is generated by
juliaMakePackage.zsh. I may go ahead and make a tool to link projects, because it's so error-prone. In fact, I cheated, and made a single Manifest.toml which I copy to all projects so far, and can replace whenever something updates.Anyway, this gets me to a nice state where I can write
using Ansiin my project and it'll just find it. IIUC, if I move all the libraries to a public repository, I can just change the repo-url and the packages are downloaded into ~/.julia cache somewhere.I still haven't followed up on making a binary application; the more I look into that, the jankier it seems, more like something to defer until there's an official solution. Putting a real UI on it is also something to work on, but that's much more doable.
Coding
I've written a lot more code, over 1000 LOC, not just screwing around with packages. Mostly this is enjoyable, it's a nice systems programming language. The ugly parts haven't yet driven me insane, they're just things to work around or ignore. Far less frustrating than almost any other new language; Rusty Nail In Your Head and Go Fuck Yourself Its Google aren't my favorites.
Strong typing really is a pain in the ass. Declare a variable or struct field
foo, and it takes anything. Type it withfoo::AbstractString, and you soon learnnothingis not a string;foo::Union{AbstractString,Nothing}is necessary to be nullable. Ick.Enumerations
Enumerated types
@enumare disappointing. They're a little smarter than C enums, but not as useful as Java enums. They just represent a value; but you have to cast them to Int every time you use them for their value, so too painful to use them as array indices. Or as characters, a thing I like a lot for debugging. And they're not easy to reflect on:julia> @enum Terrains begin
Ter_Floor = Int('.')
Ter_Wall = Int('#')
end
julia> Ter_Wall
Ter_Wall::Terrains = 35
julia> Int(Ter_Wall)
35
julia> Char(Int(Ter_Wall))
'#': ASCII/Unicode U+0023 (category Po: Punctuation, other)
julia> String(Char(Int(Ter_Wall)))
ERROR: MethodError: no method matching String(::Char)
julia> string(Char(Int(Ter_Wall)))
"#"
julia> # FFS
julia> string(Ter_Floor)
"Ter_Floor"
julia> # Surprisingly easy!
julia> instances(Terrains)
(Ter_Floor::Terrains = 46, Ter_Wall::Terrains = 35)
julia> # Shit, this is a named tuple, not a dictionary!
julia> useful_instances = Dict()
Dict{Any,Any} with 0 entries
julia> for v in values(instances(Terrains))
useful_instances[ string(v) ] = v
useful_instances[ string(Char(Int(v))) ] = v
end
julia> useful_instances
Dict{Any,Any} with 4 entries:
"Ter_Floor" => Ter_Floor
"Ter_Wall" => Ter_Wall
"#" => Ter_Wall
"." => Ter_Floor
julia> # JFHC
That was an annoying adventure to get a simple reverse lookup.