Hacker News new | ask | show | jobs
by the_mitsuhiko 661 days ago
> The use of ' as a symbol that has any meaning on it's own has got to be one of the most stupid choices I've seen in a language

Can you clarify why you have that opinion? What would your syntax suggestion have been?

2 comments

Because pretty much any other language has '...' for strings, or at least something to do with text. It's also a character that in all other languages (that I know of) must be closed with another '.

Now you could say, we don't close it in contractions in English, so there's a case where one ' can just exist on it's own. That's sort of fine, a bit outside of the realm of programming, but fine, but then I think you should remove then '...' usage. It's really confusing that the same character has two different meanings depending on something that happens later. Rust does this with ! as well if I understand correctly, so it's NOT like everywhere else, but something!() is macro expansion... Why not just prefix with "macro" so macro something()

So you have something that has a ' in front, is that a lifetime, or a missing ' later? The compiler will catch it, so it not a problem in that sense, it just makes it hard to read the code.

Personally I would almost always prefer a keyword. For Rust I think my problem is that the language is a little to happy with symbols and operators being one character picked for the none numbers and letters and the choice of ' makes it seem like they are running out of characters to choose from. Like we just one or two features away from assigning meaning to § and €.

> Because pretty much any other language has '...' for strings, or at least something to do with text.

I think you didn't use that many languages to see other forms [1]. LISP and Scheme don't have single-quoted string literals for example. Double-quoted strings are not really universal either, for example SQL uses single-quoted strings and double-quoted names.

[1] https://rigaux.org/language-study/syntax-across-languages.ht...

> Because pretty much any other language has '...' for strings, or at least something to do with text.

The ' aren't used in places where strings occur (strings just don't make sense there anyways), don't take up to much space (i.e. give more space to the name).

I am not a Rust pro, but this has never been an issue for me, same for ! for macro expansions.

> So you have something that has a ' in front, is that a lifetime, or a missing ' later?

Not once has this come up for me. They are in completely different places syntactically and can never overlap.

Sure, `'` might be text related in a lot of languages but definitely not universally. In LISP 'foo is shorthand for (quote foo) and also does not have a second character. Ocaml uses 'foo for types and foo' is just a valid identifier. Standard ML also has 'foo for type variables and I believe also allows identifiers named foo'. Haskell allows identifiers named foo' as well.

Maybe it's odd coming from languages you are familiar with, but it's not at all something that is unique to Rust.

> Rust does this with ! as well if I understand correctly

I am not sure how the case with ! is similar. Macros just end with ! to make them clearer visually, it's not part of an operator. There can never be any syntax ambiguity with them, neither visually or lexically. Also what would be the point. Take this example:

    try!(do_something(...)).further();
Do you really think this would be more readable?

    (macro try(do_something(...))).further();
> Do you really think this would be more readable?

Much more readable, I can just browse the code, and see: Hey a macro.

I mostly write Python, but sometimes have to read, debug and modify C, Java, PHP, JavaScript, Bash and so on. Having code being easily readable and obvious is a huge win.

Very often your code has to be read, and reasonably understood by someone who doesn't exactly know the language, or at least is much less proficient. They don't need to be able to do complex task or debug the inner most workings of your code, but they do need to be able to reason about it, quickly, if you want them to contribute with patches or detailed bug reports.

In rust "macro" would be abbreviated to "mac".
Rust does reserve the exact `macro` keyword for the eventual replacement of `macro_rules!` [1] [2]. But it is unlikely to be used in the invocation syntax because that will be too verbose.

[1] https://doc.rust-lang.org/reference/keywords.html

[2] https://github.com/rust-lang/rust/issues/39412

>> It wouldn't fit the syntax of the language obviously, but why not simply have the developer prefix the variable with the keyword "lifetime", rather than assigning a symbol.

...

>> The use of ' as a symbol that has any meaning on it's own has got to be one of the most stupid choices I've seen in a language

> What would your syntax suggestion have been?

Is the syntax suggestion he provided not applicable?

> Is the syntax suggestion not applicable?

Lets look at proposed syntax

  fn list_items<lifetime life0, lifetime life1, lifetime async_trait>(
         &lifetime life0 self,
         collection_href: &lifetime life1 str,
     ) -> Pin<Box<dyn Future<Output = Result<Vec<ItemRef>, Error>> + Send + async_trait>>
     where
         Self: life0,
         life0: async_trait,
         life1: async_trait,
I'm not going to pretend I understood what mrweasel meant fully, so I assume we can either omit generic or in parameter declaration (so I went with omitting lifetime keyword in parameters):

  fn list_items<lifetime life0, lifetime life1, lifetime async_trait>(
         &life0 self,
         collection_href: &life1 str,
     ) -> Pin<Box<dyn Future<Output = Result<Vec<ItemRef>, Error>> + Send + async_trait>>
     where
         Self: life0,
         life0: async_trait,
         life1: async_trait,

I guess you might be able to omit the "generic part" like so (it might be impossible, lifetime are just generics useful for lifetime tracking):

  fn list_items(
         &lifetime life0 self,
         collection_href: &lifetime life1 str,
     ) -> Pin<Box<dyn Future<Output = Result<Vec<ItemRef>, Error>> + Send + async_trait>>
     where
         Self: life0,
         life0: async_trait,
         life1: async_trait,
In both cases, you get a huge verbosity increase, and mix between not knowing if a value like `Self: x` is a trait with lower case or a lifetime.

So you trade verbosity for more ambiguity and programmer confusion, and possibly worse error reporting (is &a b a lifetime or a missing comma e.g. &a, b).