Live data from Hacker News

Rust's Ugly Syntax (2023)

matklad.github.io

11–20 of 171 posts

Re: Rust's Ugly Syntax (2023)

#11
post #4
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.

Agree about the example! I can't tell if this article is tongue-in-cheek or earnest. I'm unclear on the point the author is trying to make.

The author explains it in the first sentence, i.e. not the syntax of lifetimes may be your problem, but the feature itself

Re: Rust's Ugly Syntax (2023)

#12

The final version is still ugly. Why `pub fn'? Why is public not the default and why do you have to specify that it's a function? Why `: type' and `-> type', why can't type go before the identifier? Why do you need `File::' and `Bytes::'? What is that question mark? Why does the last statement not need a semicolon? It's like the opposite of everything people are used to.

Short answer for the type ordering and `fn`: because C/C++/Java tried that type of syntax and the result was an ambiguous grammar that is way too hard to parse, not to mention C's overly complicated pointer syntax.

Re: Rust's Ugly Syntax (2023)

#14

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…

To me this example is not more clear than normal Rust

Re: Rust's Ugly Syntax (2023)

#16
post #4
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.

Agree about the example! I can't tell if this article is tongue-in-cheek or earnest. I'm unclear on the point the author is trying to make.

My reading is: people use Rust because it’s fast but then they complain about the semantics that make it fast.

In other words, be careful what you wish for.

Most people would probably be better served by a language that was a tiny bit slower but had better developer productivity. However, once you deviate from the goal of “as fast as possible”, then you have to choose which parts you want to sacrifice speed for productivity. Like Excel, everybody agrees that Rust is too complicated but nobody can agree on which 10% to remove.

Re: Rust's Ugly Syntax (2023)

#17
post #8

The final version is still ugly. Why `pub fn'? Why is public not the default and why do you have to specify that it's a function? Why `: type' and `-> type', why can't type go before the identifier? Why do you need `File::' and `Bytes::'? What is that question mark? Why does the last statement not need a semicolon? It's like the opposite of everything people are used to.

As someone who doesn't think it is pretty , but knows Rust I went through all your points and let me assure you except for the one where you wonder why the syntax can't be more like C/C++ where it comes down to taste, all of your questions have an answer that really makes sense if you understand the language. E.g. making pub default is precisely the decision a language would make that values concise code over what th…

Definitely agree, “pub” was one of the design decisions I loved learning Rust. If you forget to add it, you’ll get a compiler error. But if pub was default, I’d be exposing code unnecessarily. And no need for a separate private keyword, the absence of pub is sufficient.

The same reasoning works for “mut” as well.

That said, I don’t like Rust’s syntax. Especially once you get to lambdas, things get hard to read.

Re: Rust's Ugly Syntax (2023)

#18
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.

Re: Rust's Ugly Syntax (2023)

#19

The final version is still ugly. Why `pub fn'? Why is public not the default and why do you have to specify that it's a function? Why `: type' and `-> type', why can't type go before the identifier? Why do you need `File::' and `Bytes::'? What is that question mark? Why does the last statement not need a semicolon? It's like the opposite of everything people are used to.

Your points have nothing to do with ugliness.

> Why `pub fn'? Why is public not the default and why do you have to specify that it's a function?

If public were the default, you'd end up having to make other functions `priv fn` instead.

> Why `: type' and `-> type', why can't type go before the identifier?

It's easier to parse, and most major typed languages other than C/C++/C#/Java put the type after the identifier.

> Why do you need `File::' and `Bytes::'?

Seriously?

> What is that question mark?

The final version doesn't use a question mark.

> Why does the last statement not need a semicolon?

This is a legitimate question. In Rust, the last statement without a semicolon becomes the return value.

Re: Rust's Ugly Syntax (2023)

#20
If I understood all the semantic properties, including the separate compilation requirements, correctly, here’s how I think it would be done in Swift with the proposed nonescapable types features (needed to safely express the AsRef concept here). (Note that this doesn’t quite compile today and the syntax for nonescaping types is still a proposal.)

  @usableFromInline
  func _read(pathView: PathView) throws(IOError) -> [UInt8] {
      var file = try File(pathView)
      var bytes: [UInt8] = []
      try file.readToEnd(into: &bytes)
      return bytes
  }
  
  @inlinable
  public func read(path: borrowing Path) throws(IOError) -> [UInt8] where Path: PathViewable, Path: ~Copyable {
      try _read(pathView: path.view())
  }
  
  // Definitions...
  
  public enum IOError: Error {}
  
  public protocol PathViewable: ~Copyable {
      func view() -> PathView
  }
  
  public struct PathView: ~Escapable {}
  
  public struct File: ~Copyable {
      public init(_ pathView: borrowing PathView) throws(IOError) {
          fatalError("unimplemented")
      }
  
      public mutating func readToEnd(into buffer: inout [UInt8]) throws(IOError) {
          fatalError("unimplemented")
      }
  }
Post reply on HN