What are common mistakes in julia that beginners should aware of?

This book seems quite nice:

https://benlauwens.github.io/ThinkJulia.jl/latest/book.html

1 Like

I 100% support what @Tamas_Papp suggested. Also I think it is good to make a distinction between: “common mistakes junior programmers make” and “common mistakes senior programmers make”.

I would say that the most common beginner problem (especially when working with data read in from external sources) is making sure that your collections have a right element type for your use case (if this is not clear what I mean by this please let me know and I can expand with some examples).

3 Likes

Related though not the same thing.
I wrote a blog post on things that seem at first like good ideas but actually are not

https://www.oxinabox.net/2020/04/19/Julia-Antipatterns.html

17 Likes

I will just slightly disagree with Tamas here. Although I think that reading the manual makes no harm, of course, I do not think that is a very good neither pleasant way to start learning programming, in Julia or otherwise. Up to the “Complex and Rational Numbers” section it is a nice introduction that can be followed by someone new to programming in general. After that it becomes (not always, of course) difficult to follow. It is a great source of information for referencing, but I do not believe that one can benefit a lot of reading that without having played with Julia for a while.

Of course the exception being if one is experienced in some other programming language that shares most of the Julia features (as C++, Lisp, Java…). In that case one can read the manual as being the translation guide from one language to the other, with its specificities which will be immediately clear to the experienced user.

Everyone has its own learning experience. But I would bet that most people, reading the manual or not, will have to make their own errors on variable scoping, assignment, type stability, before actually understanding what the manual was saying. At least this is how it has been for me.

14 Likes

Thank you @lmiq :slight_smile: , I agree your point and i was also wanted get answer like that.
Thank you @Tamas_Papp :slight_smile: , After finishing answers I will look to improve performance, but as begineer it codes there looks scared :slight_smile: .
Thank you all guys. :slight_smile:
I am learning from those links :slight_smile:

2 Likes

One very common beginner error is being surprised when fill() creates an array in which every element is the same value. This can cause unexpected behavior when that value is some mutable object (like an Array), since modifying that value once modifies every entry in the fill result. For example: Initialization of array of arrays with `fill(ones(1),2,2)`: only one vector is created or fill(anArray,2) behaviour

At its heart, this is just about the fact that Julia does not implicitly copy things like C++ or Matlab would.

12 Likes

Yes, clearly I’ve been there already. I wander if anyone uses fill with arrays expecting that, or if fill should have a method specific to arrays or mutable values and copy in those cases. An array of arrays where the elements are references to the same array seems a very unlikely use case.

1 Like

I remember things like sqrt(x::Float64) | x < 0 DomainError and the automatic: WTF, why? But, in fact, it was a good start to find out that type-stability is important in julia and why.

3 Likes

Confusing | with || and & with && is another common beginner mistake, I have a good sample of that within my students. And, to be honest, I still cannot understand were | and & can be useful.

(Also I do not understand what you would expect from that example, why it has to do with type-stability, and in which situation that syntax may appear).

2 Likes

How many people do you honestly think read all 1335 pages of the manual?

To answer the original question: one mistake I’ve seen new users make is to copy & paste awkward vectorized code from Matlab into Julia. Julia is not afraid of loops.

8 Likes

Here’s a few from my long list of annoyances/notes/tips I keep track of, as I’m a Julia beginner compared to my usual Python and C++ development:

  • Array/vector indices start at 1 instead of 0, while the range operator : includes the last index in Julia, so a[0:4] in Python would be a[1:4] in Julia. You get used to it, but I madeplenty of mistakes as the zero-based indexing I’m from Python/C++ needs to be filtered +/-1 to apply to Julia.
  • String concatenation uses * instead of +
  • Not being able to use ' for string literals, as that produces a character and not a string. Again, this one happens all the time, as in Python I only use ' quotes as it saves an extra keystroke compared to "
  • A weird combination of include files and modules for structuring code, instead of having a Julia file define a module in a predictable way as in Python
  • It’s easy to forget return in functions (as there is no warning when you do), leading to the last expression being returned. In Python not using return always causes None to be returned
  • As a lot of Julia itself, even basic operations, is written in Julia stack traces usually contain several levels of “Julia” that are not related to your own code (C++ has comparable errors when using STL templates). Even things like the include() statement end up in the stack trace as something like include at ./Base.jl:368 [inlined]. It takes some time to learn to filter that.
  • Stack traces are ordered in reverse compared to Python, meaning the innermost function causing the error is at the top of the trace in Julia, meaning you have to scan back to find it, compared to always having it on the last few lines as in Python
  • Lack of a compact dict literal as in Python
  • Vectors of Bool show 0 and 1 elements values when printed instead of true and false , leading you to believe that the values are of type integer
  • You need to write for (key, value) in array (i.e. parentheses are needed)
  • Float32 literals are written 2.0f0 and not 2.0f
  • The built-in help system in the REPL is nice, but seems to be lacking Python-style functionality of simply dumping all docs for a given class or even module (e.g. in Python import re; help(re))
  • No explicit support for object-oriented programming, although it can be emulated to some extent, but you’re still faced with a mix of OO (struct field access) and non-OO syntax (method calls). Also wacky constructor definition with both inner and outer variants.

There’s also plenty I like about Julia, e.g.

  • A much larger potential for high-performing code, if you’re willing to do the work to type-annotate/optimize the code where needed. Also, you need to understand how the compiler does its job before you can meaningfully work on performance.
  • Most standard data types work well, including generics and also includes more exotic things like enums. The type system is well-designed, but will take some time to getting used to as it is so different
  • Package management is also well-designed and well-integrated
  • Regular expressions are built into the language
  • Macros are used throughout and are really powerful (but haven’t had the need to write them myself)
  • There’s lots of packages available for a variety of subjects. These might not all be as mature as Python equivalents, but this is improving all the time.

One of the biggest hurdles I personally had (and still have) when learning Julia initially is the documentation system at https://docs.julialang.org. Although it is very extensive and contains quite a few examples the search function is almost useless as it doesn’t provide context of search hits, but only a (usually very short and general) section title and the type of page. So you can’t really judge what hit to check out, and there’s usually many hits when searching for basic concepts when learning. Plus the navigation/layout using the scrolling outline pane on the left is a pain (it contains too much detail, when following links you don’t really see what’s going on and the scrolling frame doesn’t help). I think the layout, navigation and search (and therefore overall accessibility of the docs) could be greatly improved if it would use Material for MkDocs. This for me is turning into the gold standard for technical documentation, as it uses a clean and functional layout, uses modern web technology to provide interactivity and layout and provides excellent client-side search. It also looks gorgeous.

I could go on, but wanted to end on a more positive note :wink:. One of the best things about learning Julia is this forum, I got plenty of useful (and quick) responses to questions I had!

17 Likes

Nice list. Thanks.

This drives me crazy in python. It so so unnatural! (and my background is mostly on Fortran).

This one I don’t get. What is the alternative? To have everything of each module in a single file? Sounds inconvenient (or at least inflexible).

Uhm. Either you want to return something and you assign that to a variable in the function call (you mean forget return in these cases? Never happened to me :grinning_face_with_smiling_eyes: ), or the return value is not assigned, and I do not see any reason for concern.

Functional programming is, imo, more natural than OO. For someone new to programming it is easier. Of course, with backgrounds that is other story.

Here I think that the manual fails a little bit. The inner variant is for very specific cases.* I still never used one. But from reading the manual for the first time it is not obvious that outer constructors are by far the most common ones, and particularly people used to OO programming tend to start writing inner ones and get confused.

*This is clearly written in the manual, but it is of those concepts that I only really understood after a while making my own mistakes. The section on constructors is too technical.

4 Likes

In Python, every .py file is a module and every subdirectory a package (just a group of modules, not package in Julia sense).
In Python, modules are used more extensively than in Julia (probably due to the lack of multiple dispatch), therefore I do not see this as problematic.
The Julia include way is also fine for Julia imho because Julia modules are often larger than in Python and therefore it often makes sense to split them to multiple source files.

2 Likes

Oops, I shouldn’t have quote the whole expression. It is not all julia code, I meant sqrt(x) such that x is a float and non positive. Sorry

2 Likes

Je, I imagined all the time the mirror answer in a python forum :wink:

1 Like

What I found really confusing at first is that Vector{Real} is not an appropriate supertype for dispatching on Vector{Float64} and Vector{Int}, and you need Vector{<:Real} instead.

Or better yet, don’t constrain to Vector and use AbstractVector{<:Real}.

Or better yet, don’t constrain at all if not really necessary and just see if the generic code can handle what you throw at it.

I also got very frustrated in the beginning when I used Julia in Jupyter and often created specific methods, which I later deleted and replaced with less specific ones. But the earlier ones were still active and couldn’t be removed, which caused all sorts of weird bugs. Then I had to restart Julia everytime and wait for compilation again. I almost dropped the language due to that because I thought how can it be so hostile to minor mistakes and iterative development. Now there are better workflow tools in most cases.

9 Likes

Obviously splitting up large source files into smaller logical pieces is a good thing. My issue with the Julia way compared to Python is that included source files do not (in general) explicitly contain all of their dependencies, as Python modules do, as the code in a Julia source file included in a top-level module file depends on the files included before it. While Python modules can always be tested standalone by using an if __name__ == '__main__' block included Julia files usually cannot, as its dependencies are frequently declared outside of the file. It also makes it a bit harder to figure out how a module is organized as you need to search where definitions in an included file making up a module come from.

3 Likes

It’s not a concern, more of an annoyance. The point is that if you do not explicitly use areturn statement in Python your function returns None, which is almost guaranteed to cause an error somewhere downstream where the function return value is used. In Julia I’ve had multiple times that the last statement evaluated implicitly returned a number (as I screwed up the return or logic somewhere), which would then happily cause weird behaviour downstream, for reasons unclear at first sight.

2 Likes

I don’t know if this count as a beginner situation, but this is the most obscure one that I had have till today
Race condition with local variable in @threads for loop

1 Like

Once I got used to the Python way it became more natural to me :slight_smile:

Well, let’s not open that can of worms (too far) here :wink:

Right, I think that’s because the OO way is to put structure and code in the same class, so it’s natural to want to write the constructur within the struct definition.

2 Likes