Live data from Hacker News

Rust's Ugly Syntax (2023)

matklad.github.io

131–140 of 171 posts

Re: Rust's Ugly Syntax (2023)

#131
post #46
post #40

Earlier quoted context omitted.

IMHO the mentioned examples of complexity like multiple type variables and lifetimes with bounds are for who "really" wants compile-time contracts. These are mostly opt-in so higher level use cases(like writing backend business logics) should not care about that, just wrapping everything with Boxes and Arcs. Of course Rust is not perfect; there is some 'leakages' of low level aspects to high level like async caveats(…

I do remember the compiler constantly suggesting lifetimes to me as a newcomer to the language, so it didn't really feel that opt-in. Quite a lot of the suggestions also started to look like someone poured alphabet soup all over the code.

If you encounter compiler errors that are misleading in their suggestions, or have proposals for better output in specific cases, please file a ticket: https://github.com/rust-lang/rust/issues?q=is%3Aissue+label%...

Re: Rust's Ugly Syntax (2023)

#132
post #2

I think the article makes a good point, but the actual example isn’t Rust’s worst, not even close. It gets really hard to follow code when multiple generic types are combined with lifetime markers. Then it truly becomes a mess.

I always, always forget what `'a: 'b` means, because I remember it always being the opposite of what I think it is, but memorizing that obviously doesn't work because then it will just flip again the next time. It's so annoying.

I am reminded of many instances over my life of:

1) Every time I go through a particular door I try to push it when it's a pull door.

2) I notice this and ensconce in my brain that it's the opposite of what I think it is.

3) After a while, my brain actually starts to remember it the correct way around to start with.

4) But my brain doesn't then drop the 'opposite' rule so now I remember it the correct way around, then invert it, thus recreating step 1.

I don't claim this says anything about rust, but I think it does say something about human brains (or at least mine and apparently yours).

My sympathies.

Re: Rust's Ugly Syntax (2023)

#133
post #60

Kinda disingenuous, you don't reskin one language in another to make an argument about syntax -- you develop a clear syntax for a given semantics. That's what rust did not do -- it copied c++/java-ish, and that style did not support the weight. When type signatures are so complex it makes vastly more sense to separate them out, Consider, read :: AsRef(Path) -> IO.Result(Vec(U8)) pub fn read(path): inner :: &Path -> I…

I strongly support your point, but the example is still sand-in-the-eyes for me. I hold that one symbol should not alter the semantics of a program and there should never ever be sequences of one-symbol syntactic elements. In an Ada-like language, it would be something like generic type Path_Type implements As_Path_Ref; type Reader implements IO.File_Reader; function Read(Path: Path_Type) return Reader.Result_Vector_…

Huh. My brain says logically I should find that better, but the -lack- of punctuation is making it really tricky to skim read the way I do most languages.

I'm not arguing the example you found sand-in-the-eyes is necessarily good but my mental skim reading algorithm copes with it much better.

Re: Rust's Ugly Syntax (2023)

#134

Earlier quoted context omitted.

Which isn't even needed anymore; now the compiler accepts it without any macros.

Well, you can't use the `async` keyword version if you need the `Send` bound. Imo, Rust should introduce some syntax like `async(dyn+Send)` that desugars to `Box + Send>`. This solves most of the async wards if you don't care about heap allocation and perfect performance.

That's partially not true. You can use a non-async form in the trait definition to require the Send bound and then the trait impls can use the async form. See https://play.rust-lang.org/?version=nightly&mode=debug&editi...

Re: Rust's Ugly Syntax (2023)

#135

Earlier quoted context omitted.

Well, you can't use the `async` keyword version if you need the `Send` bound. Imo, Rust should introduce some syntax like `async(dyn+Send)` that desugars to `Box + Send>`. This solves most of the async wards if you don't care about heap allocation and perfect performance.

That's partially not true. You can use a non-async form in the trait definition to require the Send bound and then the trait impls can use the async form. See https://play.rust-lang.org/?version=nightly&mode=debug&editi...

Fair point. Though, the code in question was a trait definition.

Re: Rust's Ugly Syntax (2023)

#136

Here's the cleaned up version of Rust from the OP: pub fn read(path: Path) -> Bytes { let file = File::open(path); let bytes = Bytes::new(); file.read_to_end(bytes); bytes } Here is is in raku ( https://raku.org ): sub read(Str:D $path --> Buf:D) { $path.IO.slurp: :bin } [the `--> Buf:D` is the raku alternative to monads]

Then it’s just this with C#:

  public byte[] Read(string path) => File.ReadAllBytes(path);
I think the article’s trying to explain a concept using an arbitrary piece of code from stdlib, not necessarily that specific scenario (opening and reading all bytes from a file).

Re: Rust's Ugly Syntax (2023)

#138
post #15

Earlier quoted context omitted.

How to return an error in your example?

Throw an exception proving the point of the article even further

You would actually use a Result type:

  use std::io;
  
  pub fn read(path: Path) -> io::Result {
    File::open(path)?.read_to_end()
  }

Re: Rust's Ugly Syntax (2023)

#139
post #2

I think the article makes a good point, but the actual example isn’t Rust’s worst, not even close. It gets really hard to follow code when multiple generic types are combined with lifetime markers. Then it truly becomes a mess.

That's why I am a huge fan of Rust but at the same time at the end of the day all I want is the features of the language that Rust has minus the memory management and a GC. That would be my dream language. If only ReasonML/Rescript were more popular... Or I guess Elixir

Re: Rust's Ugly Syntax (2023)

#140
post #136

Here's the cleaned up version of Rust from the OP: pub fn read(path: Path) -> Bytes { let file = File::open(path); let bytes = Bytes::new(); file.read_to_end(bytes); bytes } Here is is in raku ( https://raku.org ): sub read(Str:D $path --> Buf:D) { $path.IO.slurp: :bin } [the `--> Buf:D` is the raku alternative to monads]

Then it’s just this with C#: public byte[] Read(string path) => File.ReadAllBytes(path); I think the article’s trying to explain a concept using an arbitrary piece of code from stdlib, not necessarily that specific scenario (opening and reading all bytes from a file).

This. In general, standard library is a poor example as it has to serve very wide range of scenarios, be robust to many environmental conditions when IO is involved and perform optimally. If it's terse enough while doing so, it's good enough already.
Post reply on HN