I’ve seen a lot of protest on HN and Reddit from people who feel the currently popular language is being “shoved down their throat”. But if you’re not open to that we would be writing C forever, let alone C++ or Java (which had their own hype cycles).
> The world is often unkind to new talent, new creations. The new needs friends.
Granted, there are definitely cases out there where Julia users have been overzealous and undersensitive when trying to convince others to come try out the language, but my experience with these people is that they're almost always coming at it from a place of just being excited about finding a language that works well for them and solved so many of their issues, and so they want to share that with others.
____
D is a cool language and it's a shame it seems to get ignored so much. I hope D people continue to work at it.
> ... because of how little they care about increasing the safety in the language (like Rust or Ada).
I think it's a bit harsh to compare Julia to Rust on that front. Julia has completely different design goals. Compared to Rust's borrow checker and C++'s move semantics, Julia's immutability-by-default (+ clever compiler optimizations) gives a good trade off between performance, safety and ease of use. While Rust goes for safety + performance, Julia goes for performance + ease of use (respectively dynamicity).
Nevertheless, I miss some features related to type driven development in Julia, which would improve safety:
- A newtype idiom
- Sum types
- Explicit, type-checked interfaces : I actually would prefer something like C++20 concepts (a blacklist approach) to Rust's trait (or typeclasses, a whitelist approach), because it would be a better fit for Julia's design goals.JIT doesn't happen in Python because the community rather rewrites code in C, than support projects like PyPy.
NVidia and Microsoft had to come into play to change this.
In julia, there is no separation between generic functions and fast functions, and no separation between user defined types and inline allocated structs.
This is not the case with Python, Smalltalk, Common Lisp, etc.
To actually take hold and stop people from relying on C libraries for everything in Python, the Python JIT is going to have to be as fast as C, and it's also going to need to have a CPython compatible ABI because people are not going to abandon all these pre-existing libraries overnight.
Python's semantics make both of those prospects incredibly dubious.
Smalltalk, Lisp and SELF were used to write complete graphical workstations, where a debugger code change or dynamic code load across the network could impact JIT decisions across the whole OS stack.
At the same time though, because Python has such a tremendously big ecosystem, all written in C, and targeting specifically the CPython interpreter ABI, even if you make a JIT compiler that is as fast as C, it'd also need to support the CPython interpreter ABI, otherwise it'd never catch on because the JIT compiled implementation of the language would have to start fresh with almost no ecosystem support.
The situation is even worse if we take the realistic view that such a JIT compiler will make some serious performance compromises relative to the existing C code everywhere in the ecosystem, and the fact that the CPython interpreter ABI is so entangled with the internal implementation details that it's impossible to support in a way that's even approaching being performant.
They are as much Python as they could be Tcl.
Ironically it sufficed to Microsoft and CUDA step in, followed by Facebook as well, Guido gets out of his Python retirement, and JIT, GIL-removal are suddenly issues that matter.
Me too.
Do you wish to suggest that Smalltalk implementations had "C performance" ?
Do you wish to suggest that some Smalltalk programs should still be a little faster than corresponding Ruby +YJIT programs ? (But then NodeJS.)
Do you wish to suggest that Ruby +YJIT programs should be faster than corresponding CPython programs ?
Calling out to C libraries doesn't count for CPython performance, that is C code, not Python, and any language with FFI can call into C libraries.
(Name dropping ancient language implementations was confusing to me, and I'm ancient.)
There's little reason to think these new JITs will fare any better.
I am also curious how Mojo will turn out, from the last LLVM developers conference talk, it is quite interesting after all.
At best it needs an AOT compiler, to accelerate final scripts, and that's where projects like Mojo start to become interesting
Julia still have a sucess story and is a lot bigger compared to D.
This was Rust for a decade. It was really annoying. But now we have a wonderful new language with tons of support that could legitimately challenge C++ some day. So I tend to agree.
``` func toUpperCase(s: string) <IMPLEMENTATION>
a = "hello world" echo toUpperCase(a) # HELLO WORLD echo a.toUpperCase # HELLO WORLD echo toUpperCase a # HELLO WORLD echo a.toUpperCase # HELLO WORLD ```
With the dot syntax, the first argument is the one indicated by the dot, and the rest of the arguments are in the parentheses. In nim, you can leave out the parentheses too, which makes `echo` statements cleaner.
It's a shame more mainstream languages don't have this feature.
I really like the option to "semantically scope" a function to its main subject, like in kotlin extension methods. But I fail to see why I'd ever want to have both options. Is it just a compatibility thing, to be able to call code written for conventional languages? Or from developers who don't like that approach?
let letters = word.chars().filter(|ch| ch.is_alphabetic());
you can just write let letters = word.chars().filter(is_alphabetic);
since the difference between "methods" and "functions" is purely syntactic.Yes, it would be great to have a way to turn a method into a function. That doesn't necessarily mean that they have to be unified---an explicit conversion is enough.
[1] https://doc.rust-lang.org/reference/expressions/call-expr.ht...
I've done a little langdev and I've found that UFCS interferes with stuff like field access (person.name) or things like interfaces. Let's say you have a person struct like { name: str } but then also a Label interface like Label { name: fn () -> str }.
It's kind of a broader problem of being able to extend things in any place you might imagine, like I'll implement a trait on this struct here, I'll implement a function on this struct here, etc. etc. and before you know it your code is extremely nonlocal. There are ways to temper this, e.g. Rust combats this a little by having to have traits in scope for them to apply, but that's annoying in its own way.
I'm just saying it's not a free lunch, I think anyway.
For the function-field interference, I'd probably just work it based on situation. And usually naming functions clearly as actions with verbs and fields/variables with nouns.
``` func toUpperCase(s: string) <IMPLEMENTATION>
a = "hello world"
echo toUpperCase(a)
# HELLO WORLD
echo a.toUpperCase
# HELLO WORLD
echo toUpperCase a
# HELLO WORLD
echo a.toUpperCase
# HELLO WORLD ```