Good source for a deepdive on the type system?


#1

Hi. I understand the basics of types in Julia, but there are some things I don’t quite get, especially with relation to traits and generics and stuff.

For example, I know what this is:

struct Foo{T} where T <: Real end

But I don’t get the difference between these three things:

foo(thing::Vector{T}) where T <: Real = ...
foo(thing::Vector{T} where T <: Real) = ...
foo(thing::Vector{T where T <: Real}) = ...

or these two things:

foo(thing::Vector{T}) where {T} = ...
foo(thing::Vector{T}) where T = ...

but both are in the documentation.

I also don’t really get what can be inside the where clause. Like, you can do some kinds of tests about types, but something like this fails:

foo(thing::T) where IteratorSize(T) == HasLength() = ...

I guess I just don’t understand the semantics of where very well, except that lets you declare a type variable and make some assertions about it (but I don’t understand what those are.

I see that the way to do traits is like:

foo(iterable) = foo(IteratorSize(iterable), iterable)
foo(::HasLength, iter) = ...
foo(::SizeUnknown, iter) = ...

That seems. Hm… weird. Is there a way to implement a method for any generic iterable? It seems like there must be a way to dispatch based on the availability of certain methods.

Anyway, If anyone has answers to things, that’s good, but I’m really looking for a resource that sets it all out clearly. I can’t seem to find (or perhaps understand?) the answers to these questions from the official docs.


#2

FWIW, there are some JuliaCon talks on parts of this which I found very instructive:

JuliaCon 2017 | The State of the Type System | Jeff Bezanson

JuliaCon 2018 | Subtyping made friendly | Francesco Zappa Nardelli


#3

To get you started with something,

foo(thing::Vector{T}) where T <: Real and foo(thing::Vector{T} where T <: Real) are, AFAIK, equivalent.

foo(thing::Vector{T}) where T <: Real makes foo accept any vector that contains real numbers of a single type, like Vector{Int} or Vector{Float64}. It won’t accept, for example, Vector{Union{Int, Float64}}. Every element in the container must be of the same type.

foo(thing::Vector{T where T <: Real}) on the other hand would accept Vector{Union{Int, Float64}} as well. The element type can be different for each element of the container.


#4

Thanks so much for the reply! I finally got through both videos. The first one was super helpful in explaining the syntax! The second one explained things I mostly understood from the docs, but in a more difficult way.

I don’t have any background in higher maths or computer science, but I do love programming with sets, so I kind of understand what set theory is about, even if I don’t understand things like ∈, ∀ and ∃–obviously I’ve looked them up now, but I don’t have any training with that kind of thing. I still don’t know what t′ (t prime?) means.

The more I learn about formal proofs, the more convinced I am that they are really useful when designing a programming language (and type systems in particular), but I still can’t read them at all. I’m thinking about writing some kind of post or article about my experience learning Julia as a humanist-turned-professional-programmer. I’m thinking about calling it “∈ is more readable than in, and other **** scientists say.”


#5

Also see https://docs.julialang.org/en/v1/devdocs/types/ if you haven’t found that already.


#6

Very interesting videos !
Thinking about Francesco’s presentation, I wonder if the presented compatibility subtype system written in C could be re-written in Julia (e.g. starting on the presented simulator)? At the end of the video Francesco’s replied to this question saying that it would be very slow. Would it be true once it is compiled ?


#7

If I were to take a complete stab in the dark at this question, I would suspect that it’s less a matter of C vs. Julia (though C is almost always faster, of course), and more that his algorithm is slow. The algorithms which are most aesthetically appealing are seldom the fastest. He mentioned that there is at least one function that’s doing recursion on two explicit stacks. My guess is that Julia implementation with performance that approaches the current implementation isn’t going to be much prettier.

The question is, if someone tried to re-implement this in Julia with performance in mind, is it possible that the flexibility of the language could suggest a faster algorithm than what is there in C? There is a story about Facebook switching from Git to Mercurial internally because they have some kind of enormous repo that git was too slow with. Mercurial wasn’t faster to start out with, but it was easier for them to implement the changes they needed because it was written in Python. (note that Mercurial is still slower than Git for the normal usecase, though it is certainly fast enough)

I’m not sure how well that scenario maps to this one, but it’s something to think about.


#8

Interesting guess.
The bootstrap issue may also be considered.
I must confess that this question is quite far from my area of expertise (if such thing exists), but this was what I liked in the video: as a scientific software developer it is nice (and of little stake) to get some insight into the language implementation. I think that Julia have this dangerous property to gather people previously isolated in separate fields (scientists, mathematicians, matlab users, HPC specialist, and true computer scientists,…). Of course this may cause some friction too :wink:


#9

We’ll manage somehow. :kissing_heart:


#10

There is also Julia Subtyping: a Rational Reconstruction
https://www.di.ens.fr/~zappa/projects/lambdajulia/