Is Julia 2.0 needed?

It depends on what the breaking release offers. Python had two, and now they’re stuck with a huge installed base so they can’t move easily anymore. The goal of breaking release would definitely not be to throw away the current users. That’s why a transition roadmap and support is very important.

Another issue is source of funding for development of a language. Once you get big institutions behind it then it has the potential to snowball. I’m not too sure what’s happening with Julia but it hasn’t really gotten out to other educational institutions.

My point about mindshare isn’t about it being a PR event, it’s what the release offers and the future roadmap it comes with.

This is such a key point. I don’t see how OOP dynamics and native compiled binaries addresses the needs of technical folks, researchers, scientists, and academics. In fact, on the other hand, I very much appreciate the massive amounts of work put in to ensure Julia’s reproducibility because this is essential for scientific reproducibility.

The time and effort spent on implementing OOP is better re-allocated to bolstering machine learning algorithms and bring it to parity with Tensorflow/Pytorch.

18 Likes

Just to respond to what you said about bolstering ML. ML is becoming worth of trillions of dollars. It will pay for software at massive scale. If a language isn’t scalable to large teams of developers, it will be squeezed out by competition, where it will increasingly miss the cool new features in its ecosystem.

And how does OOP, mixing data and methods in stateful objects, help with the scalability of the language, on your opinion?

In my experience, it’s the opposite. I use two languages at my company, Ruby and Julia. The mental model I need to keep in my head to understand things in Ruby it’s insane (and it goes beyond types, in case anyone wants to point that out).

The subtle differences and complexities that modules, class methods and method instances have can really slow things down.

Whenever I write Julia I feel like I am flying in comparison and I can understand pretty much any package I read. Far from the case with Ruby, that I know for many more years.

7 Likes

OOP is for when your components need to be safely used by 50 other developers working on the same task and same data model.

We’ve been using Julia for 4 years and compiled binaries would be really, really nice. Right now when we run our production data jobs we need to make a docker image that contains our entire environment, and this takes several minutes to rebuild and upload every time, plus it results in nontrivial storage costs. The option to just use a binary would save us a lot of time.

5 Likes

Can you be more specific? What features, in particular, do you claim Python or Java have that makes it easier for a large number of people to work on the same data model? I’ve worked at companies using OOP, FP, and now Julia (which isn’t really either), and my experience is that the Structs + Multiple Dispatch model actually makes coordination easier.

10 Likes

Just to make it clear to everyone, Julia follows Semantic Versioning.

Julia 2.0 is not “julia 1 with many new cool stuff” but “julia with some changes such that some old code will not work with it”

13 Likes

That’s the catch-22. People regularly come up with ideas about how Julia should be. Some are incompatible with or could not be automatically converted from the current syntax (if it could, it’d just be compilation). Nobody prioritizes changes that would set back everyone else’s work for years; that’s what the 2.0 milestone is for. As the language develops, many of those become obsolete. Can you guarantee you’ll get all the breaking changes done “early” (not really at this point) in the language’s development so not too many people’s lives are upended, or will the language’s further maturation justify different breaking ideas?

It’s also worth pointing out that Python 3 did not overhaul its design or change its strengths and tradeoffs. Many users at the time even questioned whether a major release was needed at all because much of the justification was removing obsolete features per Python’s “one way” philosophy; now Python is comfortable with removing deprecated API in minor releases, which is not SemVer-compliant but less-used features get fewer complaints. Most of your suggestions are things that Julia either fixed or avoided in the first place: absence of interactive invalidations (issue 265), concrete subtyping, class-based inheritance and interfaces. Your wants are reasonable, but they belong to another language with a different philosophy.

PackageCompiler already does executables, the problem is that it also contains everything. Trimmed binaries via juliac are due in v1.12. It’s worth pointing out it necessarily sacrifices some features the “everything” gave.

5 Likes

If you’re looking for a machine learning language with OOP, that’s probably Mojo. Julia isn’t gonna go that way. It’s also worth noting that there have been a lot of critiques of OOP over the years which mean the organizing principles of OOP aren’t totally in fashion anymore like they were 20 years ago. Functional programming seems to be more hip at the moment, and is closer to julia’s Scheme-based heritage.

3 Likes

Suppose the Python implementation of Vector2D has some defined operators within a class like

class Vector2D:

    def __init__(self, x, y): 
        self.x = x 
        self.y = y 

    def __add__(self, other):
        return Vector2D(self.x + other.x, self.y + other.y)

    
    def __sub__(self, other):
        return Vector2D(self.x - other.x, self.y - other.y)

    def __mul__(self, other) -> float:
        return self.x * other.x + self.y * other.y

    def __repr__(self):
        return f"Vector2D({self.x}, {self.y})"

u = Vector2D(1, 2)
v = Vector2D(2, 3)

mysum = u + v 
mydiff = u - v 
mymul = u * v 

print(mysum)

and the equvalent Julia code is

struct Vector2D
  x
  y
end 

Base.:+(u::Vector2D, v::Vector2D) = Vector2D(u.x + v.x, u.y + v.y)
Base.:-(u::Vector2D, v::Vector2D) = Vector2D(u.x - v.x, u.y - v.y)
Base.:*(u::Vector2D, v::Vector2D)::Float64 = Float64(u.x * v.x + u.y * v.y)

u = Vector2D(1, 2)
v = Vector2D(2, 3)

mysum = u + v 
mydiff = u - v 
mymul = u * v 

println(mysum)

and the part

u = Vector2D(1, 2)
v = Vector2D(2, 3)

mysum = u + v 
mydiff = u - v 
mymul = u * v 

is almost the same for both of two languages.

No gains, no losses, just some cosmetic differences. The Julia implementation is shorter. I think OOP was more of a GUI hype following the evolution of Windows, and there’s no real need for it in non-GUI contexts.

9 Likes

I think the Julia community could do other things besides introducing breaking language changes to improve adoption and mindshare. For example, improving the perception of Julia from members outside the Julia community. As an example, the author of a blog on radio frequency engineering believes that “[l]earning Julia is a challenge, but if you’re up for it, it’s lightning quick for technical tasks.”

I think Julia’s lack of mindshare is more due to lack of better promotion than lack of features.

4 Likes

The biggest thing for me in OOP is the object.method() syntax. The feedback you get from the lsp when hitting the . is my biggest wish in julia.

This doesn’t need to even be a ., just some piping syntax that the lsp could use to then do a methodswith() call that would be filtered by package, so I could see most relevant methods would be amazing. Calling methodswith myself does not compare.

14 Likes

Same here. But I’d add also that this syntax allows to easily “carry” data (and thus states) across method calling. I mean by that, not only the chaining possibility, but the fact that you know a given method will act on the object’s specific state.

I know this is sugar syntax that could be done virtually in a similar way in Julia (placing the object as first argument). But this doesn’t feel the same.

2 Likes

Really? It’s gotten over 10x faster for me since 1.0:

❯ hyperfine 'julia +1.0 --startup=no -e "using Plots; display(scatter(1:10, 1:10))"'
  Time (mean ± σ):     14.086 s ±  0.297 s    [User: 13.657 s, System: 0.782 s]
  Range (min … max):   13.609 s … 14.680 s    10 runs
❯ hyperfine 'julia +1.10 --startup=no -e "using Plots; display(scatter(1:10, 1:10))"'
  Time (mean ± σ):      1.219 s ±  0.045 s    [User: 1.200 s, System: 0.634 s]
  Range (min … max):    1.176 s …  1.287 s    10 runs
3 Likes

I agree, happily, and perhaps unexpectedly, I feel much less need of that since LLMs became integrated to my coding.

2 Likes

Julia 2.0 isn’t needed, as in braking changes, if you didn’t mean 2.0 just for publicity sake. Julia might need some improvements and/or just knowing what’s possible already with the ecosystem.

Unless you have good suggestions that actually really need 2.0, i.e. breaking changes (still thanks for good-faith suggestions), then maybe move this out of internals (to community?) and maybe even lock this thread later/soon?

I think you can opt into using interface, gradually, doesn’t require breaking changes.

Is type piracy overblown? Most packages don’t do it (i.e. pirate Julia, but possibly other packages, less of an issue, it’s not a problem when upgrading Julia itself)? But may depend on few that do pirate Julia (and thus a large part of the ecosystem is dependent of those), and I think you have in mind, the few, that pirate Julia’s internals. I think it’s not really a very practical problem, and even if, can be solved easily? I’m not very up-to-speed on similar in Python, but I can’t see it more disciplined, and unclear it’s been held back by such issues.

The new public keyword is to help with this right?

Yes, and that’s good thing! You get fast to working code. You could say it’s a downside if it’s not as optimized as it could be, but it’s really easy to get to phase 2, optimized code, to superoptimized, phase 3, maybe a bit harder.

FYI: It actually works (and see its doc, it emulates Python’s OOP; I just got a strange install error, because of my messy environment I think):

$ julia +1.11 --project=.
julia> @time using ObjectOriented
  0.194931 seconds (107.07 k allocations: 8.266 MiB)

some essential differences between OOP and multiple dispatch under the hood, they are not that different. In fact, Julia’s multiple dispatch definitely steps further and can fully express OOP, although certain translation (very rare) is so far never efficient (I mean, fast in execution time).

This article aims at telling people how to translate serious OOP code into idiomatic Julia.
[…]

Julia representation of inheritance

Many smart programmers from the OOP world have already found the technique described above, but it seems that many of them give up in handling inheritance.

However, a general solution to inheritance in Julia is still easy until we need syntactic sugar support.

I believe Julia is already general purpose, I view it as “casual C++”, but like D language with a garbage collector, an improvement on C++, most C++ users will stay away from Julia and D for wrong and right reasons. Sometimes you need a language without GC, like Zig, Rust or Mojo. The latter two with an ownership model, and I think Julia could add such, and should, in an opt in way, in 1.x.

https://siml.earth/scratchpad/genai_tips_finetuning_cheater/

2 Likes

Python 2 was huge and in a lot of production systems already when the push for 2->3 happened. The 5 year plan was TOO ambitious but 15 years is more like it. But the time is correlated with the number of production systems running it. Julia hasn’t reached the same critical mass yet. So 1->2 won’t be as painful.

3 Likes

methodswith can make massive lists of multimethods; class-based single dispatch’s limitation is exactly what makes this simpler and usable.

On the flip side, .-chaining makes for limited piping. Unsurprisingly for OOP, input.method1(others1...).method2(others2...) works well for methods inside classes. Thing is, custom functions won’t belong to a preexisting class. Monkeypatching the class is easy in Python, but it risks a name conflict with a preexisting method and can’t use 2 functions with the same name qualified with different modules. Pandas dataframes implement a pipe method so .-chaining can be used for custom functions without the mess of monkeypatching, but this isn’t standard boilerplate for Python classes and you can’t monkeypatch pipe into the top superclass object. (The equivalent in Julia can be done with (|>)(arg1, (f, others...)) = f(arg1, others...).) The simpler approach to piping syntax is the metaprogramming in Pipe.jl or R’s |>.

These sort of tradeoffs are why I can’t say my preferred programming paradigms are just “better”.

4 Likes

If you don’t include base and only show specific methods for a custom struct (and maybe methods specific to its custom abstract type) from the packages you are using, what is the most massive list you can find? I am truly curious.

Then let’s say you do want this functionality from all types in base. What is the biggest list you can find? I really would like an example for me to test with.

That list can’t be bigger than the list of all available functions and structs and variables, which is something that the lsp already filters for when you start typing anything.

1 Like