Can you clarify why you have that opinion? What would your syntax suggestion have been?
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 €.
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...
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.
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();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.
...
>> 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?
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).