Julia 1.8
julialang.org
julialang.org
`status --outdated` is something I've wished for many times, nice!
Typed globals will, at the least, make life easier for people new to Julia (and those teaching them).
I never thought I'd move away from Vim, but the ease of use and polish here make it worth switching (with maybe Neovim as the backend at some point), rather than try to recreate it in Vim.
I don't like the ergonomics of `mutable struct` vs (immutable) `struct`. Adding `const` seems like another step in the wrong direction. Right now, there's `struct` + `Ref{T}` fields for having a immutable struct with fields that can be mutated VS `mutable struct` + `const` fields for a mutable struct with fields that can't be mutated. And defining mutability at the `struct` level is kind of painful.
Sometimes I want to accept user input in a type checked manner (i.e. not storing them in dictionaries and using typed struct fields) and then pass that struct into a core algorithm where execution needs to be fast (i.e. aligned memory, immutable structs etc). Rust does this by making the mutability declared at an individual function level or during access to the struct value. In Julia, I have to decide ahead of time and that changes how users would use a library of mine.
I also dislike that syntax `a.b += 1` is not allowed for fields in immutable structs. I would love it if `@immutable_mutate a.b += 1` de-sugared to `a = A(b = a.b + 1, a...)` or the equivalent. If this existed I think I would just use immutable structs ALL the time. If a macro for that existed in Base Julia that would be amazing. (I don't want to use third party libraries for this.)
I'm (cautiously?) optimistic that Julia will be absolutely awesome in like 5 years. Currently, 90% of my work in Julia is painful because of poor developer workflow / tools. But when I need to do the remaining 10% (performance / optimization of code), Julia is amazing. Right now, it is probably easier to write code in Python (with type hints) and drop down to Rust or Go whenever performance is needed, than to start with Julia in the first place.
The 'typed non-const globals' are a welcome syntax update for the sake of consistency with the rest of the language ... but it's worth pointing out that const globals effectively had the same effect, since you actually were allowed to redefine a const-labelled variable, and you were only prohibited from changing their type. Earlier versions of Julia silently ignored such redefinitions, but a warning was added later on whenever a redefinition of a const variable was detected. So I guess the only difference between the two now is that one will issue a warning and the other will not? I don't know if the two also have some hidden performance differences that are not obvious from this post. Regardless, still a small but welcome change nonetheless.
That doesn't sound like an improvement to the dependencies loading... Which for me happens every time I change a struct and must reload Julia (which happens a lot when I'm prototyping code, which is what I do 90% of the time)...
Is Julia "doomed" on this issue or is it just that they prefer to work on other use cases first ?
But there is a project to cache native code (without needing to build a sysimage) that may make a huge difference...
* It's been reduced by like 75% (roughly, not sure about the real number) since Julia 1.0, so material progress has been made.
* In the future (I'm guessing 1-2 years, of course uncertain), native code caching could make a huge difference.
* On a similar timescale, Julia could allow compilation into static binaries. This could possibly be done for some dependencies that does not need to be generic, which would take another chunk of the compilation need off.
ReplMaker.jl can make this process more convenient, but in version 1.9, there’ll be a facility for that built into the regular REPL.
```
struct MyClass1
...
endMyClass = MyClass1
```
Then, whenever you need to change MyClass, just add 1 to the version number of MyClass in those two or three instances, and the repl will just compile MyClass2 as a new class to be used for all future calls in the repl.
module X struct etc... end end #module
Change without reloading.
About your issue, things you can do: - Put the struct inside another module. - Use this package: https://github.com/BeastyBlacksmith/ProtoStructs.jl . It gives you a simple @proto macro that you can prepend to the struct definition and makes all changes immediate.
If it was stackoverflow, I would have accepted this answer with a kind comment :-) Thanks !
This gives the package authors a tool to basically "profile" the loading time of their package, which will help them optimize the loading time. So there _will_ be downstream improvement to package loading for us users too.
> Which for me happens every time I change a struct and must reload Julia (which happens a lot when I'm prototyping code, which is what I do 90% of the time)
The workaround involving `MyClass = MyClass1` that a sibling comment mentions comes from [this Revise.jl manual page](https://timholy.github.io/Revise.jl/stable/limitations/). Revise in general enables a few different ways to work around this, and it's useful to integrate into your workflow (as much as it feels weird at first to go from full REPL to half REPL-half editor).
and ProtoStructs: https://github.com/BeastyBlacksmith/ProtoStructs.jl
I’ve never tried them, but they’re advertised as doing the job.
Addendum for those who are new to this, the idea is to use these macros during development, and then get rid of them once the types stabilize (since they tend to have a performance cost).
https://julialang.org/blog/2022/08/julia-1.8-highlights/#imp...
The core devs also said that they are aiming to cache native code in the next year or so.
It lead to https://github.com/SciML/RecursiveArrayTools.jl/pull/217 . 6228.5 ms to 292.7 ms isn't too shabby.
There's a well-known concept in Julia, [time-to-first-plot](https://discourse.julialang.org/t/time-to-first-plot-clarifi...), which encapsulates the large lag the first time you call a function. But there is no such thing as time-to-second-plot — the second plot is always fast.
Also, I would say actual best practices would be to have CI, not to be rerunning your code manually.
Writing .jl files in VSCode and sending code to the integrated REPL with shift-return for playing around is great and then when I want to run code properly I just comment out my testing code, wrap my important code in a main() function (which is sometimes everything apart from the imports) and then just make sure that I'm not referring to any variables or function methods defined that are now commented. This is made relatively easy as VSCode will immediately complain about possible method errors.
It's not a perfect substitution for having fast startup and when I go back to Python or R for things like the holy grail called Tidyverse then it feels like a weight off my back, but the benefit of doing things the Julia way is that your code has a clear starting point and it helps readability as you can see what every script is supposed to do.
Even so, Julia is a good tool for intensive computation, and I think it will continue to replace Fortran for some such work.
Balance is the key. I use R all day long for data analysis, and don't really see Julia as competitive for such work. However, when it comes to numerical modelling, Julia competes well with Fortran and C/C++.
I think Julia should be thought of as a Fortran replacement for overnight/overweek jobs, not an R replacement for interactive work.
Julia idioms: Multimethods and multiple dispatch instead of python/java style OOP; Loops are fast, with zero-cost-abstractions and automatic SIMD, unlike python's need for vectorized libraries; "type-inferability" is incredibly important for good performance, which is quite different from python's duck typing (but the language is dynamic, so it is still an option); measuring how often your code allocates is the most trivial way to increase its performance by an order of magnitude.
Julia workflow: you *have* to change your workflow, compared to coming from python, otherwise the latency of the compiler would cause you deep enraging frustration: e.g. use Revise.jl/Pluto.jl/REPL, organize your code so that small pieces can be recompiled without having to restart your session; keep your workspace clean and your computational pipeline organized, so that reproducibility testing is easy.
I write machine learning code, so anything compute intensive is done with specialized libraries and the Python glue code usually has little overhead. Sometimes when writing complicated pipelines I spend a lot of effort on optimizing data transfers (between CPU and GPUs, between GPUs on the same server, between GPUs on different servers in a cluster, etc), but that effort has little to do with Python limitations (or so I think).
- I actually like vectorized code, I find it easier to read, but especially in python, vectorized code still has some fixed overhead that can be prohibitive for smallish vectors.
- Some of the numerical code I run is not easy to batch, so tools like tensorflow are cumbersome. With Julia it is easy to make fast non-allocating code while writing in easy to read style like in Python. In Python you need to use C/Cython/Numba to achieve this, but then you lose interoperability with other Python packages. E.g. auto-diff through fast cython code does not work, while autodiff through my equally fast non-batched Julia code is trivial.
- Ecosystem: I work with differential equations a lot. Julia's SciML library (and its DifferentialEquations.jl sub-library) is light years ahead compared to any other tool in Python/R/Mathematica/Matlab/Maple. Speaking of python, solving differential equations in python feels like I am using technology that is quarter of a century old.
- In python I might write a nice and legible slowish implementation of something and then piece by piece I will start replacing it with cython. That requires a lot of boilerplate. In Julia I just write the slowish implementation with the same ease with which I would do it in python, but then I need to perform extremely minimal profile-guided changes with zero boilerplate to achieve the cython/numba type of performance. And again, I do not lose interoperability with other parts of the ecosystem when I do that.
- It is trivial to inspect the actual machine code that was generated for every single function you write. It is trivial to inspect exactly where allocations happen. Most of the ecosystem is in pure Julia, so it is trivial to edit fairly foundational pieces of the ecosystem and submit patches. On the other hand, the levels of abstraction in something like Jax/Tensorflow/Numba makes it relatively difficult to contribute.
- It is wild how much code reuse you can have with the multiple dispatch paradigm. Say I find someone's pet project on performing a complicated linear algebra algorithm. That code was probably written just to work with Float64, but thanks to multiple dispatch the compiler can generate specializations for esoteric higher-precision real number representations, or real numbers with error bars, or unitful numbers. I still need to do some sanity checks, because hidden assumptions might be problematic, but this level of interoperability is possible only with multiple dispatch (thinking of it as one of the "standard solutions" for the Expression Problem[1] really helped; [2] was also informative). I think the GPU libraries for Julia are a good example of multiple dispatch working well in that sense.
[1]: https://en.wikipedia.org/wiki/Expression_problem [2]: https://www.youtube.com/watch?v=kc9HwsxE1OY
I find Julia to be pretty good for interactive work, but there definitely are some rough edges that still need smoothing.
However, once a new very fast algorithm has been discovered and tested and everyone agrees it is good, someone will probably implement it in Fortran or C or even assembly and optimize the shit out of it.
One thing that supports this view is that there are several Julia packages that are wrappers around existing C/Fortran/C++ libraries, and basically no examples (that I know) of people porting existing libraries to Julia.
This is totally off-base :-) There’s even discussion of implementing a lot of linear algebra stuff in Julia, instead of just falling back to BLAS (for very good reasons), see eg https://youtu.be/KQ8nvlURX4M
Those wrappers are just to bootstrap the ecosystem for immediate usefulness.
So, over time, I expect Julia to become better and better for everything from exploratory development to workhorse numerical computing infrastructure. Once compiled binaries are feasible, I wouldn’t be surprised if other languages start wrapping algorithms implemented in Julia.
- ITensors.jl : They started moving from a C++ to Julia a couple years ago and now their webpage doesn't even mention their original C++ implementation on its homepage anymore https://itensor.org/
- DifferentialEquations.jl : This has many state of the art differentiatial equation solving facilities in it, many of which are improvements over old Fortran libraries.
- SpecialFunctions.jl, Julia's own libm, Bessels.jl, SLEEFPirates.jl : Many core math functions have ancient Fortran or C implementations from OpenLibm or whatever, and they're being progressively replaced with better, faster versions written in pure julia that outperform the old versions.
That's an understandable misconception. But the reason these packages use C/Fortran libraries is because they're already there, and writing a wrapper is much easier than rewriting the library in Julia. It's not a performance thing, it's a person-hours thing and wanting to use the libraries right now.
On the one hand, this means you have binary dependencies and FFI you have to manage.
On the other hand, it saves you a lot of niggly optimization work and dealing with edge cases, which the C/Fortran libraries have already gone through and done for you.
Once the former starts to outweight the latter and/or more person-hours become available, the libraries start to get ported to be fully in Julia. And the tools available in the ecosystem and the compiler codegen are good enough that there's no artifical performance ceiling due to being in Julia i.e. you do get performance equivalent to being in C or Fortran.
Recent releases have had longer cycles with more thorough testing. Julia's CI has expanded. Static analysis is improving. The linter is improving. That all adds together to a more stable Julia with fewer bugs.
However, there has been made little progress on actually improving Julia's tests, or documenting abstract types, or on formalizing interfaces, nor have there been a big dedicated "fix bugs" push.
So yes: It's getting better, but slowly and not yet by leaps and bounds.
Don't get me wrong, I love multiple dispatch and Julia's composability + speed make it a no brainer for science/quant econ teams to adopt (and using it to train models on TPUs is a actually a sneaky way to save time + $), but they've lost the "culture" war and I can't see the entrenched masses here or elsewhere changing their minds on it. Not sure whether it's for job security sake or they got sick of all the "Julia is faster than/will replace X" evangelism or Plots loaded too slowly the one time they tried it years ago or a combination.
The discussion was further evidence of the reality that I'd already come to terms with; the lack of inroads in building a larger community and general ecosystem is partly because of a lack of focus on things like tooling, linting, documentation standards, etc and partly because of a weird amount of disdain for the language. I can help with the former, but I don't have the time or energy for the latter because it's actually a set of large, long-term marketing, organizational, and psychological problems to overcome. Maybe someday down the road I'll be back, but I've given it a shot for about 8-9 years now.
Which situation exactly? The linked article lacks a salient point, so there's really no way to know what you're referring to.
“My conclusion after using Julia for many years is that there are too many correctness and composability bugs throughout the ecosystem to justify using it in just about any context where correctness matters.”
I’m impressed with all that they’ve done, but for finding new talent and dealing with such a strange tool and with multiple dispatch being such an awkward paradigm compared to traditional OOP, I still don’t think it’s worth the trouble yet.
Additionally, everybody I’ve met thus far for interviews who knew Julia, also knew either Python or R, so it’s sort of a “why bother?” scenario.
Multiple dispatch is odd. It took me a while to get used to it, but it turns out to be pretty useful for a lot of math-y things where there are speed-ups for special cases (symmetric matrix, etc) or you need to wrangle data into a common structure first (one variance, list of variances, covariance matrix, etc).
> Additionally, everybody I’ve met thus far for interviews who knew Julia, also knew either Python or R, so it’s sort of a “why bother?” scenario.
Well, if it isn’t substantially improving on a pain point that makes you really want to switch, then why bother? :-)
Eg: For a problem I happened to be working on yesterday, I probably could have reduced ~1000 lines of Python code to ~100 lines of Julia code (all because of multiple dispatch… not just by calling some library) and cut through a lot of the not just tedious but also error-prone boilerplate (lots of little indexing details).
It's just that unlearning things like this is a hard process that not a lot of people have experience with, especially compared with learning things in a purely additive sense.
If you're suggesting Smalltalk is not class-based then what do you mean by "class-based" ?
Smalltalk language implementations provide a prototype program and we make our software by making changes to that prototype — by sending messages to instantiated objects — not by writing definitions.
You might not even need to do that. This package was released recently, implementing OOP: https://github.com/Suzhou-Tongyuan/ObjectOriented.jl
1. Instead of operating sequentially as you type, maybe one could type out the variable(s) one wants to use, select them and then have the ask the language analyzer to suggest functions?
2. Another change (possibly more effective) is to stop thinking in terms of data (and completing with functions) and instead start thinking in terms of functions (and completing with data). Just thinking out loud what might be a different thought process… The language (and types/classes) are not there to constrain you; write down the code/functionality you would like, and then find/construct the types you need to have that code be true :-?
This wasn't mentioned in this blog post, but the NEWS.md with a more complete changelog mentions a new feature in the REPL
> ?(x, y followed by TAB displays all methods that can be called with arguments x, y, .... (The space at the beginning prevents entering help-mode.) MyModule.?(x, y limits the search to MyModule.
There's long been discussion of this kind of redesigned autocomplete UI that's suitable for this paradigm, in the Julia community. I really like this solution that they ultimately went with.
Not related to this but I think Julia is too ambitious too succeed, at least in a normal timeframe. Languages like Rust and even Python managed to improve a lot more compared to their goals than Julia compared to the goal "a modern language, a modern top edge research level scientific library rewritten from scratch".
I enjoy the community that is backing it, really, but there is still no solid core. A lot of research level cool functions and algorithms, yes. But you still suffer from lagginess, inexact calculations and language idiosyncrasies. In short too much dispersion and divergence in this project. It's almost like this language was designed by academics...
But is it not better to both achieve you mediocre goals and also have extremely ambitious goals that may still be achieved, than merely having mediocre goals?
I don't really agree that Julia right now doesn't have anything to show for its huge amibitions. In my opinion it's already the best language for science by quite a large margin. I understand it still lacks some tooling, reliability and deployment options to be attractive for many industrial clients (though Julia is already making inroads in industry - I have an old friend from college who uses Julia in production). It's also understandable that some people used it and found the latency unacceptable. The thing is - there is no reason to believe that tooling, reliability and deployment options won't come around. The stuff is being built. It's just happening "too" slowly right now.
Maybe I'm being pedantic here, but surely you can't "just write C++". If you could, why would you ever use R, which is way slower, less backwards compatible and can't be shipped as a binary?
I'm guessing you use R because it's easier to use than C++, interactive, and quicker to get stuff done in. That sounds to me like a list of criteria where Julia should aspire to beating R - if we can.
This is called "the two language problem", and it is not just about ergonomics (e.g. you do not seem to have issues with the ergonomics of this approach). Rather the issue is that now I can not have a library that introspects my R code and performs automatic differentiation or some other advanced compile pass over my code, because not all of the code is written in R. This is also why most of the advanced SciPy functionality can not be used with Tensorflow, or use Jax's autodiff feature with Pandas dataframes or Pillow images.
In many cases this might not matter, but when creating sophisticated large computational packages, the level of interoperability that Julia provides is both incredibly empowering and as of yet unsurpassed.
It's difficult for outsiders to know what to think when confronted with so divergent opinions:
"I would hit bugs of this severity often enough to make me question the correctness of any moderately complex computation in Julia.
This was particularly true when trying a novel combination of packages or functions — composing together functionality from multiple sources was a significant source of bugs."
On the other hand, though, I have not encountered more bugs in the Julia ecosystem than in the Sympy or Theano (deprecated now) or Tensorflow or Pytorch systems when I was using them to build "sophisticated large computational packages".
Maybe the happy users are just not as vocal, but that is a silly excuse.
Julia allows packages to interoperate in a way most other mainstream languages simply don't, due to the combination of its multiple dispatch and the type hierarchy. The fact that the language allows this interoperability to such level is very useful and empowering. But making proper use of this interoperablity means writing careful generic code that doesn't make narrow assumptions based only on currently known uses of it.
Different parts of the ecosystem do this with different degress of care and success, with newer ones being better at it as lessons are learned and implemented. Yuri happened to work on parts of the ecosystem that were not-so-new, and made combinations that hadn't been commonly attempted. That doesn't mean that these weren't issues that need fixing and preventing in the future, for sure. But hitting bugs of this severity often isn't the typical experience for the average user - if it was, Julia would hardly have as many users, much less ones like NASA.
Before making a claim like this you better define what you mean by "succeed" and what you mean by "normal timeframe".
Julia has been around since 2010-ish. The equivalent timeframe for python was late-90s.
The federal reserve bank uses (used?) Julia to model economics... Jokes about whether that is a succeed or fail for society at large, aside, it's hard to argue that adoption by at least one very significant player doesn't constitute success for a PL.
Without defining more precisely what succeeding and the timeframe means it is difficult to know what OP was after but the fed example stands well on its own.
So you either promote Arm Mac as tier 1, but now every PR takes extra hours to get merged, or you keep it at tier 2 for now and only build on Arm, say, once a day. Rust developers choose the later, because with their commit traffic they can’t afford such delays.
As the build machines capacity increases arm macOS will be promoted to Tier 1. Don’t read too much into tiers. Tier 2 is still pretty well supported from a language user perspective. Julia situation is pretty much the same.