Subtypes of concrete types in Julia

By: Blog by Bogumił Kamiński

Re-posted from: https://bkamins.github.io/julialang/2022/08/19/union.html

Introduction

Today my post is about subtypes of concrete types. It is mostly academic, but I
hope it will be useful for readers wanting to get a better understanding of
corner cases Julia’s type system.

The post was written under Julia 1.8.0 (with special thanks for all people
who contributed to this release!).

What is a concrete type in Julia?

In Julia a type is concrete it can have a direct instance, that is, some type
T is concrete if there exists at least one value v such that
typeof(v) === T.
For every type you can check whether it is concrete using the
isconcretetype function.

Today I want to discuss the following sentence from the section on
Types from the Julia Manual in relation to concrete types:

One particularly distinctive feature of Julia’s type system is that concrete
types may not subtype each other: all concrete types are final and may only
have abstract types as their supertypes.

From this sentence some readers conclude that concrete types cannot have
subtypes. However, it is not the case. Concrete types in Julia can have subtypes
as long as these subtypes are not concrete.

You might ask does this ever happen in practice? The answer is that it happens
and here are the examples when it does.

The first one is Union{} type. This type is not concrete and has no values.
However, it is a subtype of all types, including concrete types, for example:

julia> Union{} <: Int
true

julia> Union{} <: Vector{Missing}
true

The other case is Type{T} type, where T is a DataType (i.e. if T has
type DataType). All common concrete types are subtypes of DataType, e.g.
integers or vectors. So types like Int or Vector{Missing} have DataType
type:

julia> typeof(Int)
DataType

julia> typeof(Vector{Missing})
DataType

which means that DataType must be concrete, and indeed it is:

julia> isconcretetype(DataType)
true

Although DataType is concrete, it has Type{Int} and Type{Vector{Missing}}
as its subtypes (and these types must not, and are not, concrete as we
discussed above):

julia> Type{Int} <: DataType
true

julia> Type{Vector{Missing}} <: DataType
true

julia> isconcretetype(Type{Int})
false

julia> isconcretetype(Type{Vector{Int}})
false

Why these subtyping considerations matter?

The most important lesson learned here is that in your code you should
not assume that concrete type cannot have subtypes, as it can (although these
subtypes cannot be concrete themselves). This observation is mostly relevant
for package developers, who need to write generic code.

However, there are some practical situations when one can be affected by these
subtyping rules. The most common is when one is working with missing values.

Assume that I generate some random matrix containing either 1 or missing:

julia> using Random

julia> Random.seed!(1234);

julia> mat = rand([1, missing], 10, 3)
10×3 Matrix{Union{Missing, Int64}}:
 1          missing  1
  missing   missing  1
 1         1          missing
  missing  1         1
 1         1          missing
 1          missing  1
  missing   missing  1
  missing   missing   missing
 1          missing   missing
  missing   missing   missing

Now, I want to compute the sums of its rows, while skipping missing values.
Here is how you can do it:

julia> [sum(skipmissing(row)) for row in eachrow(mat)]
10-element Vector{Int64}:
 2
 1
 2
 2
 2
 2
 1
 0
 1
 0

However, a very similar codes that follow do not work:

julia> [sum(skipmissing(identity.(row))) for row in eachrow(mat)]
ERROR: ArgumentError: reducing with add_sum over an empty collection of element type Union{} is not allowed.

julia> [sum(skipmissing([x for x in row])) for row in eachrow(mat)]
ERROR: ArgumentError: reducing with add_sum over an empty collection of element type Union{} is not allowed.

What is the reason for the difference? In the skipmissing(row) case row
is a view and retains information about element type of the whole array, which
is Union{Missing, Int64}, so it is able to properly compute sum even in the
case when all values in a row are missing.

On the other hand both identity.(row) and [x for x in row] materialize the
row and perform type narrowing. This type narrowing means that in rows that
only contain missing values the information about Int64 is lost and we get
an error. Let us see it step by step:

julia> row = last(eachrow(mat))
3-element view(::Matrix{Union{Missing, Int64}}, 10, :) with eltype Union{Missing, Int64}:
 missing
 missing
 missing

julia> x = identity.(row)
3-element Vector{Missing}:
 missing
 missing
 missing

julia> eltype(skipmissing(x))
Union{}

As you can see, since skipmissing strips the Missing part from the source
vector element type, we are left with Union{}.

Unfortunately, such errors happen from time to time when one works with
data having missing values. For such cases in Julia many (but not all) common
reduction functions support the init keyword, so you can do:

julia> [sum(skipmissing(identity.(row)), init=0) for row in eachrow(mat)]
10-element Vector{Int64}:
 2
 1
 2
 2
 2
 2
 1
 0
 1
 0

and all is good even if type inference produces Union{}.

Conclusions

The post today was less practical than usual. However, I hope you will find it
useful when Julia tries to take you into a deep dark type system forest where
2+2=5, and the path leading out is only wide enough for one (Mikhail Tal).

Installing Julia 1.8 and VSCode

By: Uwe

Re-posted from: https://ufechner7.github.io/2022/08/18/installing-julia.html

Introduction

Installing Julia is easy, but perhaps you also want to install an integrated development environment (IDE) or a version control system (e.g. git), therefore I give some hints how to do that in this blog post.

Furthermore there are different ways to install multiple Julia versions in parallel and to keep your version up-to-date which are also explained in this blog post.

Highlights of version 1.8 of Julia are explained here .

Installation of Julia

Windows

Please download and install Julia as explained here .
Choose the “64-bit (installer)”. Make sure to check the option “Add Julia to path” when running the installer.
For advanced users it is suggested also to install git for Windows which also includes the bash command line interface, very useful for small automation tasks. The git version control system keeps track of the changes of your files and allows SW development in a team.

It is suggested to launch Julia from the command line, using either the “Windows command prompt” or “bash” by typing julia or julia --project (if you work with projects). If you never used a command prompt before, read the Beginners Guide.

Juliaup

An installer and version manager for Julia called juliaup is available in the Microsoft Store. It can be used to install specific Julia versions or update to the latest release. This package handles all PATH related aspects of Julia, and alerts users when new Julia versions are released.

Uninstallation

Uninstallation is preferably performed by using the Windows uninstaller. The directory in %HOME%/.julia can then be deleted if you want to remove all traces of Julia (this includes user installed packages).

Linux

Copy and past the following line to install the latest stable version of Julia:

bash -ci "$(curl -fsSL https://raw.githubusercontent.com/abelsiqueira/jill/master/jill.sh)"

If you want to be able to easily switch between different versions of Julia consider to install
the Python version of jill .

pip install jill --user -U
jill install 1.8

If you should later install version 1.9 with jill install 1.9 you can then switch between the versions with jill switch 1.8 etc.

It is suggested to add the following line to your .bashrc file:

alias jl='./bin/run_julia'

This makes it possible to run julia with the shortcut jl later, if you have a run_julia script in the bin folder of your projects. I suggest to use such a script, the most simple version of it would just contain the line julia --project .

Mac

Please download Julia here .

A julia-1.8.0-mac64.dmg file is provided, which contains Julia-1.8.app. Installation is the same as any other Mac software: drag the Julia-1.8.app to Applications Folder’s Shortcut. The Julia download runs on macOS 10.9 Mavericks and later releases.

You can launch Julia by opening the Julia app like any other application.

Add Julia to PATH

If you want to launch Julia from the command line, first open a new terminal window, then run the following snippet from your shell (e.g., using the Terminal app, not inside the Julia prompt).

sudo mkdir -p /usr/local/bin
sudo rm -f /usr/local/bin/julia
sudo ln -s /Applications/Julia-1.8.app/Contents/Resources/julia/bin/julia /usr/local/bin/julia

This code creates a symlink to a Julia version (here 1.8) of your choosing. To launch Julia, simply type julia inside your shell and press return. If you are working with projects, use the command julia --project.

Installing multiple versions in parallel

The jill installers will most likely also work on Mac and allow easy switching of different Julia versions (see Linux section).

Uninstallation

You can uninstall Julia by deleting Julia.app and the packages directory in ~/.julia . Multiple Julia.app binaries can co-exist without interfering with each other. If you would also like to remove your preferences files, remove ~/.julia/config/startup.jl and ~/.julia/logs/repl_history.jl .

Installation of the IDE VSCode

It is useful to install the integrated development environment VSCode, even though it is not
required. You can also use any editor of your choice.

VSCode provides syntax highlighting, but also the feature “goto definition” which can help to understand and explore the code.

You can download and install VSCode for all operating systems here .

For Ubuntu Linux the following ppa can be used to install vscode and to keep it up-to-date: https://www.ubuntuupdates.org/ppa/vscode .

Installing the Julia extension

  • Start or open Visual Studio Code.
  • Select View and then click Extensions to open Extension View.
  • Enter the term julia in the marketplace search box. Click the green Install button to download the extension.

Julia VSCode extension

You successfully downloaded the Julia extension for VS Code.

NOTE: It is recommended that you restart VS Code after installation.

Julia development with VSCode is well documented here: Julia Visual Studio Code Documentation

I would NOT use all the advanced features of julia-vscode, I prefer to just use the vscode terminal and launch julia from the terminal. This makes it easy to launch Julia with any command line options and also to start and restart Julia quickly.

Other useful VSCode extensions

  • Project Manager
  • Better TOML
  • Code Spell Checker

VScode supports git out-of-the box.