Not when taken to such an extreme so as to obfuscate the meaning and behavior of code, and make it difficult to understand how you would arrive at that code.
Sane defaults serve to reduce verbosity without obfuscating meaning, simpler syntax with different ordering and fewer tokens reduce verbosity to make the code easier to read by reducing the amount of text you have to pay attention to to understand what the result is.
I imagine there’s also a distinction to be made between verbosity and redundancy - sometimes extra text might fail to carry information, or carry information that’s already carried elsewhere. I’m not sure where the line should be drawn, because sometimes duplicate information can be helpful, and spacing out information with technically meaningless text has value for readability, but I feel like it’s there.
Frankly, I have way more often ended up scratching my head for some cryptic piece of syntax than the opposite. Sure I could sit down and spend the rest of my life learning each language designer’s favourite syntax optimisations, but I kinda don’t want to. I’m a human, not a parser.
And frankly, a good IDE editor should be able to fold/unfold verbose syntax. Better for it then to be there and folded, than for it to not be there and for someone to have to work backwards the intendrd meaning of every single line of code.
std::string doesn’t have a template type for the allocator. You are stuck using the verbose basic_string type if you need a special allocator.
But, of course, nobody sane would write that by hand every time. They would use a typedef, like how std::string is just a typedef for std::basic_string<char, std::char_traits<char>, std::allocator<char>>. Regardless, the C++ standard library is insanely verbose when you start dropping down into template types and using features at an intermediate level. SFINAE in older versions of C++ was mindfuck on the best of days, for example.
Don’t get me wrong, though. I’m not saying Rust is much better. Its saving grace is its type inference in let expressions. Without it, chaining functional operations on iterators would be an unfathomable hellscape of Collect<Skip<Map<vec::Iter<Item = &'a str>>>>
As long as you call .collect() on it at the end, don’t need to write the entire type as it is a method with a generic parameter, and returns that generic.
The intermediate iterators though, those are hell. Especially if you pass it to a lambda and for some reason rust can’t infer the type.
I once came across a parsing library that did the parsing with basically just the type system. It was absolute hell to debug and build. Types of parsers would be hundreds of characters long. It would take tens of minutes to build a simple parser.
I don’t know much much time it would take to build a complex parser, since it was unable to. it reached the max type generic depth of the rust compiler, and would just refuse to compile.
I believe it was called Chomsky or Chumsky or something like that. Discovering nom was a blessing.
let a: &'static str
Rust is verbose, but C++ might still take the cake with its standard library templates. Especially when using fully-qualified type names…
auto a = ::std::make_shared<::std::basic_string<char, ::std::char_traits<char>, MyAllocator<char>>>();
A reference-counted shared pointer to a string of unspecified character encoding and using a non-default memory allocator.
I don’t understand why verbose is bad. Verbose is maintainable.
Not when taken to such an extreme so as to obfuscate the meaning and behavior of code, and make it difficult to understand how you would arrive at that code.
Sane defaults serve to reduce verbosity without obfuscating meaning, simpler syntax with different ordering and fewer tokens reduce verbosity to make the code easier to read by reducing the amount of text you have to pay attention to to understand what the result is.
I imagine there’s also a distinction to be made between verbosity and redundancy - sometimes extra text might fail to carry information, or carry information that’s already carried elsewhere. I’m not sure where the line should be drawn, because sometimes duplicate information can be helpful, and spacing out information with technically meaningless text has value for readability, but I feel like it’s there.
Frankly, I have way more often ended up scratching my head for some cryptic piece of syntax than the opposite. Sure I could sit down and spend the rest of my life learning each language designer’s favourite syntax optimisations, but I kinda don’t want to. I’m a human, not a parser.
And frankly, a good IDE editor should be able to fold/unfold verbose syntax. Better for it then to be there and folded, than for it to not be there and for someone to have to work backwards the intendrd meaning of every single line of code.
fully qualified type names make any language awful.
Here’s the same example in rust:
let a = std::rc::Rc::new(std::vec::Vec<u8, MyAllocator>::new());
I believe u8 also comes from a module, so it would be something like
std::u8::u8
, but I’m not sure.deleted by creator
std::string
doesn’t have a template type for the allocator. You are stuck using the verbosebasic_string
type if you need a special allocator.But, of course, nobody sane would write that by hand every time. They would use a typedef, like how
std::string
is just a typedef forstd::basic_string<char, std::char_traits<char>, std::allocator<char>>
. Regardless, the C++ standard library is insanely verbose when you start dropping down into template types and using features at an intermediate level. SFINAE in older versions of C++ was mindfuck on the best of days, for example.Don’t get me wrong, though. I’m not saying Rust is much better. Its saving grace is its type inference in
let
expressions. Without it, chaining functional operations on iterators would be an unfathomable hellscape ofCollect<Skip<Map<vec::Iter<Item = &'a str>>>>
As long as you call
.collect()
on it at the end, don’t need to write the entire type as it is a method with a generic parameter, and returns that generic.The intermediate iterators though, those are hell. Especially if you pass it to a lambda and for some reason rust can’t infer the type.
I once came across a parsing library that did the parsing with basically just the type system. It was absolute hell to debug and build. Types of parsers would be hundreds of characters long. It would take tens of minutes to build a simple parser.
I don’t know much much time it would take to build a complex parser, since it was unable to. it reached the max type generic depth of the rust compiler, and would just refuse to compile.
I believe it was called Chomsky or Chumsky or something like that. Discovering
nom
was a blessing.Yeah, I missed the custom allocator at first. I thought I deleted my comment fast enough, but I guess you were faster. :)