Thanks for reporting this. We should fix this. We introduce type parameters immediately after that, so we should either
Reorganize the lecture a little bit or
Be less general about the set of AR(1)s that get considered and restrict a, b, and sigmato Float64 or another concrete type or
Explain that this isn’t the most performant version of this type and let them know that we will explain why in the next section.
I am a little torn on 3, though I think I prefer it. I like the idea of having an example to discourage people from these types of performance issues (type inference problems), but don’t want people who skim over this and develop bad habits (though I guess this is their own fault…).
@ChrisRackauckas Thanks a lot for the comment. It’s really much appreciated. I’m a long way from an authority on Julia but many of the useful bits of knowledge I’ve collected in my head so far are thanks to reading your excellent blog.
So, just to be sure I understand, in the example in question, when you rewrite AR1_explicit as parametrically typed, instances are concretely typed at the time of creation, and that concrete type information is available at runtime to methods that take this instance as an argument. Hence there is no problem with type inference.
@cc7768 Assuming my understanding is correct, I think the right thing to do here is to use concrete types as in your option 2. Then, in the section below where parametric types are introduced, revisit this example and explain how we can loosen up the type restrictions without affecting performance. It’s actually a nice example of how parametric types are useful.
I think the right thing to do here is to use concrete types as in your option 2. Then, in the section below where parametric types are introduced, revisit this example and explain how we can loosen up the type restrictions without affecting performance. It’s actually a nice example of how parametric types are useful.
That is a very good idea. I’ll probably steal this idea .
FYI, I’ve been going through your stuff because I have been planning a workshop and am updating my notes to be more “beginner friendly”. I think your tutorials do a good job at it, but I am a stickler for making sure people are lead to “proper performant and generic Julia code”… so I’ve always had type parameters very early on. This suggestion is definitely a good compromise: starting with simpler and performant but not yet non-generic code, and generalizing it later.
This might be complexity creep, but I think you should add something on dynamic dispatch, explaining what it is, why it’s costly (and how much it costs), and why it shows up in these cases. I think it makes the “compiler information” idea more concrete.
I don’t know enough about dynamic dispatch to do that right now (I thought all dispatch in Julia was dynamic…?) and I’m trying to finish off some research and not get distracted, so I doubt I’ll edit again in the short term. But thanks for the suggestion, I appreciate it.
The reason why type inference makes things fast is because if everything is inferred, then inside the function the local variables become statically typed and the dispatches all become static dispatch. When something is not inferred, that’s when you have dynamic dispatch, i.e. at runtime it has to find out what type it is, check the methods table, and use that to find out what method to call (~100ns). But it’s easy to see that if all of the types are known at compile-time, the compiler can check the methods table and simply insert the correct dispatches, making them all static. That, plus variable boxing, is why lack of type inference and type stability makes code slow.