The point is, if you don't need the rigor of a strongly typed compiled language, there are other languages you can use. Perhaps a bash script is all you need.
Until very recently, Java was just tedious, repetitive, high-entropy language, where you had to write everything multiple times.
Eg.:
VeryLong<Type> variable = VeryLong<Type>();
In this expression, it's obvious what would be the most likely type of variable, but you still have to write it twice -- which is just worthless use of your time, especially when trying to read this very repetitive mess, and very easy to make a typo.Recently, Java tried to improve this situation by allowing to omit types when the type inferred by default is the one you want. So, you need to write less. You also need to learn the inference rules, obviously, so it increases the cognitive load and rises expectations towards programmer's skill a bit. But, I think it's fair, since Java from a language for the brain-dead transformed into a language that requires more effort to master. While I'm not sure it's a positive change... this decision by Java developers kind of flies in the face of your argument:
No, it's not necessary to repeatedly spell out what you want your program to do. It's just boring and contributes nothing to the program's correctness. If anything, it only causes the programmer to lose focus and introduces mechanical errors that would've been totally avoidable, had the language was more terse.
var fireable = someMethod();
firable.fire();
The programmer intended this code to fire an employee. Let's say this code is in a military application, and another programmer modified the someMethod() function to return a missile. As long as the missile object has a fire() method this code will compile just fine... and do something the code didn't intend to do.How likely are you to have employee firing and missile firing in the same program? Not very likely, but the principle is valid, regardless. You need to express your intention more clearly like this:
Employee fireable = someMethod();
Now if someMethod() is modified to return a missile you get a compilation error, and the world will be a lot safer. You don't want missiles being fired by accident!You should be insane if your program accidentally confuses people with missiles, but I understand that this is a stretch to amplify the point. What tends to happen in practice is that eg. the same method which used to only read something from the local storage gets a new overload that goes out into network, and brings with it a whole new bunch of problems the calling code wasn't prepared to handle. Or, when a string was passed to the method that used to do something simple, and then the method gets overloaded with a more sophisticated method that interprets substrings in the passed string as commands to run some code -- and then you get security problems.
Have you ever seen the IntelliJ interface when it deals with Rust code? I'm not sure if it does the same for other languages with type inference feature. Anyways, the idea here is that the programmer can toggle the display of inferred types to qualify every expression. So, it's really trivial to make sure you aren't calling fire() of a missile instead of an employee. And, in practice, this doesn't lead to problems. This is so because dispatch, essentially, blurs the difference between multiple different objects, while type inference is just a kind of abbreviation. It may cause confusion, but it will be of a different type: the reader might not know what's being abbreviated, whereas with dispatch, the reader may be convinced they know what the author meant, but still be wrong.
The point being, someMethod is doing some job that you want it to do. It is incredibly unlikely to simultaneously start doing a completely different job, while also returning something of the same shape.
Following your logic, Java developers can now say “if you don’t like freedom of Java, use Rust/Haskell/Scala to validate everything at compile time”
foo():boolean throws Some, List, Of, Errors
foo():boolean | Some | List | Of | Errors
foo():(boolean | nil) , (nil | Some | List | Of | Errors)
The first is checked exceptions. The second is returning different types. Typically there's some sort of Option wrapper for ergonomics. The third returns a result, err tuple and by checking if err is nil you can see if foo succeeded.
Ultimately they are all the same. What differs is the boilerplate/syntax to accomplish what you want. If what you want is a generic error to handle unknown events then you gotta write it that way no matter which system you use.
I wish C++ had checked exceptions.
I would love if, at design time, all the possible exceptions that could happen were able to be inferred. But, the way it happens in java, it's entirely manual, and it won't catch things where I'm referencing compiled code. The design of checked exceptions in Java lead to all kinds of exception anti-patterns becoming common, just to shut up javac.
That a lot of languages force you to write it out is not an inherent property of strong typing.
This has nothing to do with strongly typed compiled languages vs alternatives.
Brutal, even for this site