# Your big function has specific types
function my_function(x::UInt, y::UInt)
[ ... ]
end
# Wrapper function to minimize monomorph. cost
my_function(x::Integer, y::Integer) = my_function(UInt(x), UInt(y))I don't believe Julia or Python is "best practice" over Rust. I even empathize with the opinion that explicitness may be preferential sometimes. But you _must_ be able to see how Rust's syntax overload obfuscates the core business logic, right?
Sure, business logic is more readable in something like OCaml than in Rust. On the other hand, Rust isn't really worse than something like Java, and I like having more information than what you have in Python. I'll also add that Rust is often chosen for speed and reliability, and that part of that syntax is here to guarantee that. It's not directly business logic in the traditional sense, but it's something you expect from your code.
All in all, Rust is still not at the level of the "platonic ideal for syntaxes", especially not for most of the code I write (business logic for web apps, which wouldn't need Rust's speed). Still, in the realms of programming languages that are used, it's one of the best.
FWIW `__` doesn't mean "this is part of the implementation", it means "I'm designing a class for inheritance and I don't want child classes to stop on my attributes".
No. Python certainly does not have a concept of private code[0]. The Python community has a suggestion of things being implementation details.
Surely you can see that absolutely would not be good enough for a language which strives for static correctness? And even more so as the soundness of `unsafe` blocks often relies on the invariants of the type it's used in?
[0] well that's not entirely true, I guess there's native code.
fn f(x: impl Test) { ... }
Is basically the same as fn f<T: Test>(x: T) { ... }
Having to annotate the return value of functions is partly to make sure don't break semver accidentally, but it also constrains type inference to a local search rather than global search, avoiding spooky action at distance (when modifying a function changes the signature of another function). It seems that semver hazards are more important in languages with static types.That pub? It's punching waaay above its weight! Having things private by default protects against semver hazards too, but it's also the major tool that enable writing safe code that uses unsafe { .. } blocks underneath. That's because a single unsafe block typically taints the whole module it's contained (such that even safe code needs a safety review). Being able to write safe abstractions of unsafe code is the pull of Rust so people need to get it right.
For example, setting the field len of a Vec to a value larger than what's initialized in its buffer will cause UB when accessing that memory; if this field weren't private, making a safe Vec would be impossible (likewise, a function that could set the len to any value must be private, etc).
So pub can only be used for things that are safe to export, and people should be careful with that.
Here's my least favorite syntax from there: that damn Ok(..). Ok-wrapping sucks. There were proposals to remove it, but they were rejected. There's a library that removes it [0], and people should use it. It also makes the Result<..> return type implicit in the function signature too.
[0] https://boats.gitlab.io/blog/post/failure-to-fehler/#but-abo...
* The output type must be explicitly named instead of inferred
* The let keyword for creation of variables instead of merely assignment
* The mut keyword to distinguish between mutable/immutable variables
* The pub keyword, instead of another mechanism
* Semicolons needed after every expression
And more. Again, for every one of them, you can argue that it's _good_ for it to be there, because it serves a function. But you end up with a language with a hugely bloated syntax where the business logic is sort of swamped in these accessory keywords.That isn't syntax. It's a decision about analysis.
> The pub keyword, instead of another mechanism
The "other mechanisms" discussed are in fact not providing this feature, but pretending you needn't care, and I'd argue Rust shows that in fact you should care and pretending otherwise is a problem.
> Semicolons needed after every expression
On the contrary, semicolons are at the end of Rust's statements. If what you've got is an expression you don't need a semicolon. For example here's how log is defined on an f64 (a double precision floating point number)
pub fn log(self, base: f64) -> f64 {
self.ln() / base.ln()
}
Notice there's no semicolon there because that function is an expression, we want the value of this division as the result of the function.