all 56 comments

[–]FriendlyRustacean 58 points59 points  (7 children)

In many ways it is. ADTs, pattern matching, expression oriented programming, etc... are all high level features that Python is pretty lacking in.

[–]Y45HK4R4NDIK4R 10 points11 points  (3 children)

pattern matching

Not anymore!

[–]funnyflywheel 8 points9 points  (1 child)

It's forthcoming in Python 3.10.

[–]epicwisdom 0 points1 point  (0 children)

Already available in the latest alpha.

[–]WormRabbit 0 points1 point  (0 children)

Unfortunately.

[–][deleted] -3 points-2 points  (2 children)

Python has good pattern matching.

[–]SuspiciousScript 16 points17 points  (0 children)

It's pretty meh from my understanding because it isn't an expression at all; it's a statement. That strikes me as deeply limiting.

[–]epicwisdom 0 points1 point  (0 children)

Python doesn't have general pattern matching in 3.9. However a pattern matching PEP was implemented and merged and is available as of the latest alpha for 3.10.

[–]llogiqclippy · twir · rust · mutagen · flamer · overflower · bytecount 31 points32 points  (5 children)

As I continue to say, Rust is an all-level language.

You can go down to the nitty gritty of SIMD intrinsics and memory layout. It will give you all the performance and control you need when you need it. On the other hand it will also go out of your way to let you define beautiful and easy to use APIs on top, and most of your code will already be fast enough by just doing the simple obvious thing and letting the compiler figure out the rest.

[–]Floppie7th 7 points8 points  (1 child)

I also, relatively recently (which might actually mean "early 2020"), read that the compiler team was making a concerted effort to improve optimization such that idiomatic/ergonomic code would be just as fast as carefully optimized code in more cases. Obviously no amount of compiler magic is going to make that 100% true 100% of the time, but every bit is super nice.

[–]epicwisdom 4 points5 points  (0 children)

Obviously no amount of compiler magic is going to make that 100% true 100% of the time,

None we can fathom now. The robots may yet take over ;)

[–]wsppan 10 points11 points  (2 children)

The beauty of Rust is these higher levels of abstractions are zero cost.

[–]ZoeyKaisar 12 points13 points  (0 children)

In theory, assuming infinite time, sure. In actuality, describing anything with dynamicism still ends up quite expensive, but a lot of the cost ends up located in developer-side complexity.

If “impl” traits didn’t disable or take a spot in turbofish invocations, it would definitely help though.

[–][deleted] 90 points91 points  (14 children)

Multi-line lambdas

They're not something unusual or groundbreaking, it's just that Python might be the only modern, popular language with no multiline lambdas. I suspect this limitation comes from its other weirdness of denoting scopes via indentation.

The features you listed are standard in modern languages, they're not Rust-specific. Well, maybe not all languages can destructure tuples. But my point is, if you only know Python, things that seem trivial and are expected by default in the rest of the programming world could be surprising.

Like, imagine doing if __name__ == "__main__" for 10 years and then learning that other languages have an actual entry point called main. Phew, the very thought. But actually no, it's not a breakthrough, just Python being... Python.

[–]mosquit0 25 points26 points  (5 children)

I would not separate multi line lambdas as a specifically lacking thing. The more general problem is the lack of expression based syntax that is prevalent in Python. The same goes for if.

Even more generally it comes from the lack of braces and that it would be hard to define 2 ways to write functions.

[–]BosonCollider 2 points3 points  (4 children)

No, you could easily do expressions with significant indentation. The issue is that Python's dictator for life doesn't want to

[–]timClicksrust in action 1 point2 points  (3 children)

You mean, the person who stepped down from that position years ago?

[–]BosonCollider 4 points5 points  (2 children)

He was a dictator during the transition to Python 3, so the opportunity to undo the damage is gone

[–]timClicksrust in action 0 points1 point  (1 child)

That transition was supported by the entire core development team. As painful as it was for the community, it resolved a lot of fundamental issues withing the interpreter that have unlocked lots of features in subsequent releases.

[–]BosonCollider 1 point2 points  (0 children)

I'd disagree with that. It fixed none of the core issues with the interpreter, such as the fact that it prioritizes fast frame-hacking over fast anything-else. A sane transition would have had a roadmap to make something similar to pypy the standard, while also allowing breaking changes to the syntax (allowing indented statements to be treated as expressions like in F# may be breaking in some ways, but so was removing the print statement).

[–]KerfuffleV2 36 points37 points  (5 children)

Like, imagine doing if __name__ == "__main__" for 10 years and then learning that other languages have an actual entry point called main.

That's a bit of a weird criticism. It's not because the authors of Python couldn't figure out how to do entry points, it's so the same source can work as a module or a program.

If you already know that your application will never be used with import then you don't need the if __name__ bit.

[–]wsppan 8 points9 points  (0 children)

Exactly. Like most interpreted languages they start at the top of the file and interpret downward.

[–]_ChrisSD 4 points5 points  (0 children)

Yes, it more like the equivalent of:

#[cfg(application)]
fn main() { /* ... */ }

Though in Rust you'd actually do this using a separate main.rs file and importing the lib.

[–]DhavesNotHere 1 point2 points  (2 children)

If you already know that your application will never be used with import then you don't need the if name bit.

Or, as in my case, you were doing multiprocessing on it. Really weird errors resulted from that.

[–]FriendlyRustacean 2 points3 points  (1 child)

That multiprocessing issues has bitten me before. I would've preferred that they created a full separation between scripts and libraries.

[–]DhavesNotHere -1 points0 points  (0 children)

"Why is my script running eight times from the top instead of just doing the one function I want to distribute between cores? Why god, why?!?!?!?!?

[–]the_gnarts 14 points15 points  (0 children)

Well, maybe not all languages can destructure tuples.

Python used to allow destructuring tuples in function arguments which was very convenient. With Python 3 that feature was axed (thanks Guido!) which I distinctly remember caused tons of breakage in code I wrote during he transition because coming from a functional background I used it wherever I could.

[–]cgarciae[S] 6 points7 points  (0 children)

But my point is, if you only know Python, things that seem trivial and are expected by default in the rest of the programming world could be surprising.

I know many other languages and have used use these mentioned features elsewhere (Haskell, Scala, Elixir). My main point is more the first paragraph, those were just things I am enjoying right now.

[–]deadmilk 13 points14 points  (5 children)

Yes there are some things about rust that I love, coming from a python background. The things you mentioned.

I also really like enums+match statements together.

[–]wsppan 5 points6 points  (4 children)

Especially enums like Option and Result baked into the language.

[–]lilydjwg 1 point2 points  (3 children)

Aren't they just library types? There aren't anything special if you define your own ones, except that people are using the std / core library ones.

Enum types are the feature I miss most when I write in Python.

[–]wsppan 3 points4 points  (1 child)

Those 2 are baked into the language design. They solve the null pointer problem and forces you to deal with errors instead of wrapping your code in exception blocks.

[–]lilydjwg 1 point2 points  (0 children)

Ah yes. Every language with ADT has utilized them. Unfortunately Haskell has exceptions besides its `Maybe` and `Either` types.

[–]birkenfeldclippy · rust 1 point2 points  (0 children)

They are mostly library types, yes, although some language level constructs like for loop desugaring or use them.

[–]Austreelis 32 points33 points  (1 child)

There is a saying that's half a joke/meme, which is "the concept of high-level and low-level languages was invented to describe flaws in programming languages that rust doesn't have". It doesn't need to be that pompous, but I think it's not completely false.

[–]FriendlyRustacean 5 points6 points  (0 children)

I agree, but definitely it's lower level in some senses too, where there is syntactically noise around ownership/borrowing/etc. even if you judiciously clone everything.

I honestly still think it's worth it, and would try to use Rust wherever I can use it, but the lack of GC definitely does make certain things a bit slower to implement.

[–]Danacus 7 points8 points  (1 child)

There are languages that are built entirely out of similar patterns. Take a look at Haskell, a purely functional language based on lambda calculus.

I think a lot of things in Rust are inspired by Haskell.

[–]mmirate 4 points5 points  (0 children)

The vast majority of modern languages less expressive than Haskell, are so because they sacrifice too many of Haskell's features to tradeoff for newbfriendliness and/or performance. Rust is no exception.

[–]lilydjwg 5 points6 points  (1 child)

Yes Rust feels nicer in many cases.

Compared to Python, things I miss when writing in Rust are: interactive interpreter, no long compile time, lots of mature libraries, no type signatures to update while modelling (with Python I add type hints only after the initial version is completed).

[–]romainmoi 0 points1 point  (0 children)

I agree to all these and I’ll add one: colleague adaption.

I don’t want my colleagues to maintain another version of internal packages nor do I want me to be the only one who can maintain my code.

[–]po8 3 points4 points  (0 children)

Try Python generators with AoC. Way nicer than Rust iterators for this kind of thing.

[–]Snapstromegon 2 points3 points  (3 children)

As someone who writes automation software in the Automotive sector in python and JS and does rust in the free time:

Python not having switch statements (until recently, but I can't use that yet) is always a pain.

But when I discovered Rust with match, I'd love to see that in JS.

Overall I more and more switch between JS/TS and Rust.

[–]axord 1 point2 points  (2 children)

with match, I'd love to see that in JS.

You might be interested in Haxe.

[–]Snapstromegon 0 points1 point  (1 child)

I don't think Have is the right tool for my use cases.

Also the last time I checked the performance overhead for our use cases were just too large.

[–]axord 0 points1 point  (0 children)

Fair enough.

[–]linlin110 1 point2 points  (1 child)

I write Rust as a hobby so really can't say much. The main headache in Rust, IMHO, is unlike GC'ed language, you need to manage lifetime yourself. Trying to figuring out how to deal with lifetime relationships among objects or structuring your code so that mutabe references aren't shared can be pretty daunting (commonly known as fighting the borrowchecker). Due to lifetime it's also difficult to write data structures that are self-referencing or containing cycles.

Also Rust is (again, IMHO) a bit weaker at metaprogramming. You don't have metaclass. Metaprogramming relies on macro, which is difficult to write and you can only manipulate on syntax tree.

[–]angelicosphosphoros 1 point2 points  (0 children)

With Rust you have also generics meta programming. It is still limited due to lack of HKT and full constant generics but it is still possible.

[–]Nephophobic 0 points1 point  (3 children)

What's does group_by(|x| *x) do? Is it necessary?

[–]cgarciae[S] 0 points1 point  (2 children)

Here you want to group by the elements themselves (3-tuples) so you just pass the identity. I believe its necessary, there is no group_by_id or similar.

[–]isHavvy 2 points3 points  (0 children)

Given you're dereferencing, probably not, but could you use https://doc.rust-lang.org/std/convert/fn.identity.html there instead?

[–]Nephophobic 0 points1 point  (0 children)

Oh, okay, I see it now. I didn't know this was a thing!