That’s done with font = :bold_italic for the default font face, mentioned here Fonts · Makie (you have to pick font faces, not layer bold + italic, because many fonts have multiple weights anyway).
And I’m not sure about the line spacing problem you mention, in principle that should be adjustable. Although could be that rich text doesn’t do this right now, I don’t remember
Hence the suggestion to integrate Pluto into your workflow at the prototyping stage of a module or type, rather than moving your entire project into a notebook. Place import Pkg; Pkg.activate(Base.current_project()) at the top of the notebook to make it run in the environment you’re developing in such that you can easily prototype on top of existing project code. And with Pluto.run(auto_reload_from_file=true), you don’t even have to leave your editor, Pluto can just be a monitor for the state of your code.
Just throwing this out as one possible way of working around the struct redefinition limitation. Of course, you may find that other workarounds suit you better, such as your suggestion of wrapping a module around each new type.
You see, every single parameter of every type is written in, you guess it, (args...; kwargs...), so I had a lot of trouble navigating Makie’s code base. Now that you mention the existence of GlyphCollection, I found the entry point (plot!, I suppose) immediately at the top of the file lol.
I’ll address one of your sections as a sort of jumping-off point to responding to the spirit of the whole.
Julia enums are much like C enums: they’re numbers which you can refer to by name. They are nothing like Rust or Java enums at all, so if you expect them to be, you’re going to have a bad time.
Julia has one namespacing mechanism: modules. Anything in the top scope of a given module shares a single namespace, enums included. For enums, I tend to do what we do in C, and use a prefix, so a VM I’m working on, the enums for instructions are all IAny, IReturn, and so on.
Is that ideal? It depends on what you’re working on, I suppose, or what you’re used to, or both. If you want a namespaced enum, EnumX.jl provides this. It uses a module, in fact.
You can use enums for dispatch, although how to do it isn’t at all obvious. Using the example enum from the documentation, here’s how.
julia> @enum Fruit apple=1 orange=2 kiwi=3
julia> f(::Val{apple}) = "I'm an apple"
f (generic function with 1 method)
julia> f(::Val{orange}) = "I'm an orange"
f (generic function with 2 methods)
julia> f(::Val{kiwi}) = "I'm a kiwi"
f (generic function with 3 methods)
julia> f(fruit::Fruit) = f(Val(fruit))
f (generic function with 4 methods)
julia> f(apple)
"I'm an apple"
julia> f(kiwi)
"I'm a kiwi"
If you’re using enums in the common fashion, where they get written as constants, directly into the text file, then this will be fast. If the enums are being passed around in variables, you’re better off dispatching in a different way. Using a collection of zero-width subtypes is another option, and it might be a better one, depending on what you’re doing.
At least, I think that using an enum by name is treated like a constant, not a variable, by the compiler. It’s difficult to be sure of these things.
Pattern matching: there are a few packages, the obvious one is named Match.jl, and it works fine with enums. It is not exhaustive, you won’t get an error if you don’t match all branches. That’s pretty normal with Julia, but for enums specifically, which can’t be extended, it would be possible to write an exhaustive pattern-matching macro which threw an error if you didn’t handle all cases. I’m not aware of any, however.
The point of my answer here, however, is that this is a pervasive problem with the ecosystem. How is a beginner supposed to know you can dispatch on enums using the Val pattern? There are breadcrumbs in the manual, but that’s it.
I think it’s great that someone who wants namespaced enums can write a macro and make it a package, and that there several competing implementations of pattern matching based on macros as well. I think less things should be in stdlib, not more.
But discoverability is really rather bad. And it isn’t great that something as basic as pattern matching doesn’t have a clear winner which everyone uses.
This is a combination of the size of the user base and the essential complexity of the language. The only way out is much better supporting documentation, and more of it, and the way to get that is to keep growing and stimulate enthusiasm in the user base. There aren’t easy answers here.
Meanwhile, getting to know Julia requires some determination to trawl through juliahub and old Discourse threads. It is simply harder to figure things out than it is in many other languages, and that needs to change.
@enum SkillRarity begin
SkillNormal
SkillRare
SkillEvolved
SkillSpecial
end
And didn’t find out there was no pattern matching until I implemented 20 skills in ~800 LoC, finished the whole simulation, and finally needed these enums for visualization. So in the future I will treat them like C enums.
This is my first time seeing a Val pattern. I have thought about if it could be done because some other lisps could do it, but I never found it despite actively searching for it in the official documentation, especially through the methods and dispatching docs.
Co-creator of ModernJuliaWorkflows here: contributions are always welcome!
The initial goal was to contribute the posts to the Julia blog, but instead maybe our website deserves a life of its own? I could definitely see it becoming a less formal, more hand-holding companion to the detailed documentation. Of course, putting a link to MoJuWo in the important links section would make it seem more official than it is… but in Julia world there really isn’t such a thing as “official”, there is only “useful to the community”.
If you’re wondering why all this stuff is not already in the docs, see this previous discussion:
Well, and that’s the thing: there is pattern matching, but it uses Julia’s excellent metaprogramming facility, so it’s a library. Several, in fact. But everywhere else, it’s a core part of the language. This isn’t quite the dreaded Lisp Curse, but it’s related.
There is a section on value types, but it doesn’t connect them with enums in any way.
In larger languages you’d search for “Julia enums” and find a blog post called, like, “Julia enums: more than you ever wanted to know” which lays it all down on the table for you. That search does yield some interesting stuff, including a sum-types project SumTypes.jl, which I’d completely forgotten about, and uses the macro system to make Rust-style enum types.
But there isn’t an exhaustive treatise. It’s the size of the community, more than anything.
(The type annotations for the arguments are necessary because otherwise the argument would be typed Any and each definition would overwrite the previous one.)
This doesn’t really help with reading other people’s code, but for your own code, it sounds like you might like my ExplicitImports.jl package. It helps convert using Foo into using Foo: x, y, z, based on whatever names x, y, z, you are actually using in your code.
This is not good for research code, because I am refactoring so frequently that I cannot imagine myself maintaining not only an export list, but also an import list.
If Julia’s LSP is as good as rust-analyzer or IntelliJ Java, then we are talking.
Well, i personally find that it is more convenient to mix different conventions, and julia makes that easy:
Dot case? no problem
julia> var"foo.bar"() = println("_ are overrated, use . instead")
foo.bar (generic function with 1 method)
julia> var"foo.bar"()
_ are overrated, use . instead
For people who prefer the _ to be centered with the text:
julia> var"foo-bar"() = println("like snake_case, but aligned with the text")
foo-bar (generic function with 1 method)
julia> var"foo-bar"()
like snake_case, but aligned with the text
This is also a good one:
julia> var"foo bar"() = println("use ' ' as separator, because why not?")
foo bar (generic function with 1 method)
julia> var"foo bar"()
use ' ' as separator, because why not?
And my personal favorite, for when i started learning programming with CSS, and had to use double-dash naming convention for classes:
Sevi’s next post has this. I think you mean something like poetry specifying dev dependencies for python packages, for example I use the ptpython repl in my development workflow in python but dont want this as part of my package dependency.
So yes, this is easy in the Julia REPL as Sevi’s post shows.
I like to keep several named ‘global’ environments, these are stored by default in the ~/.julia/environments folder. For example mine looks like this: