4 ms·
What bothers me about languages like Rust, which I think I'm in the minority on, is the lack of explicit type declarations. C and Java, my two first languages,
by gravypod 9y ago
What bothers me about languages like Rust, which I think I'm in the minority on, is the lack of explicit type declarations.
C and Java, my two first languages, strictly spell out what types they expect. Sure you can ignore those rules but as long as you don't those types convey a lot of useful information about your program. With languages like Rust I don't think I could ever start writing code in them without an IDE. The entire idea of compiler-specified types is neat but I don't think all of your code should rely on that.
One oddity is Python which I have used a lot. The only difference is that Python is much less strict than the languages I'm used to. Because of this learning Python was still relatively difficult (Why is all the documentation written like a book!? I miss my Doxygen) but I didn't need an IDE.
- twic 9y agoIn Rust, you still have to declare types for function parameters and return values. So, if you prefer to declare types everywhere, break your code down into single-expression functions!
- chewbacha 9y agoAnd even then, you are still allowed to explicitly define types everywhere, they are just optional. https://play.rust-lang.org/?gist=24d87fde3cc5273d4ec73ba5647d733a&version=stable https://play.rust-lang.org/?gist=24d87fde3cc5273d4ec73ba5647...
- oblio 9y agoI have bad news for you, local type inference is coming to Java :)
- hyperpape 9y agoInterestingly, even Java is probably going to introduce local variable type inference using syntax somewhat like let foo = bar(); http://openjdk.java.net/jeps/286 http://openjdk.java.net/jeps/286
- sidlls 9y agoI'm torn on this. I prefer explicit types in declarations as well, but very much like the convenience of inferred types. I find myself thinking, though, that the demand for the convenience of inferred types in these languages is a result of the verbosity in the type specifications themselves, usually with generics (Rust) or templates (C++). I rarely use the convenience of inferred types for concise type labels (e.g. non-generic structs, integers, etc.). Maybe this is a deficiency in the languages' designs?
- steveklabnik 9y agoWe put a lot of consideration into this. Basically, we could let you elide types everywhere, but didn't. There's a few reasons why, and they're sorta inter-related. If you let type signatures be inferred, then you can get very poor errors. This happens when you change some code in the body, that changes the type signature of the function, which then causes an error to happen where the function is used. This misdirects from the source of the error, rather than helping you figure out what goes wrong. Conceptually, signatures are the place where contracts are enforced, especially in Rust. Everything about a function should be expressed in its signature, so that way we can do analysis based on only the signatures. This helps in a few different ways: it's faster for the compiler, and it's also easier for the human reading it. The bodies of functions, however, aren't exposed to the greater world. With a defined signature, the compiler can give you great error messages, pointing exactly to where you made a mistake. In this case, inference makes sense. It's not just about convenience though. You can see this in languages like C++, which optionally support type deduction (but not full inference): auto a = 1 + 2; int a = 1 + 2; With auto, the type is deduced. Without auto, you specify the type. There are various arguments that range between "never auto unless you have to" and "always auto". Consider this example https://stackoverflow.com/questions/6900459/the-new-keyword-auto-when-should-it-be-used-to-declare-a-variable-type https://stackoverflow.com/questions/6900459/the-new-keyword-... SomeType<OtherType>::SomeOtherType * pObject = new SomeType<OtherType>::SomeOtherType(); auto pObject = new SomeType<OtherType>::SomeOtherType(); Here, auto improves readability, because you end up just repeating the type over again. This was my main frustration with Java's generics back in the day. (I primarily used Java in the 1.4 ~ 1.5 era, I know today's is a very different beast!) This is directly related to the parent post; some might say "explicit is better than implicit" but in my opinion, while that's often true, implicit is better than explicit sometimes. The above is a great example. The post is all about trying to tease out better words to talk about these differences.
- kibwen 9y ago> is the lack of explicit type declarations This is mistaken. Rust has explicit type declarations, augmented with type inference. Furthermore, unlike popular statically-typed functional languages, Rust's type inference is deliberately restricted to only operate within functions (intraprocedural) rather than between functions (interprocedural), which means that one always has explicit types available in the function signature when reading code.
- curun1r 9y agoPerhaps not type declarations, but I think GP is onto something when it comes to Rust and how it handles types in a way that often lacks explicitness. There's a lot of Rust code where you have to have familiarity with an API to understand what's going on with the types. As a for instance, let's say you have a function: fn connect(addr: std::net::IpAddr) -> ... { ... } And it gets called: connect("192.168.0.1".parse()); Unless you have a pretty good level of familiarity with the APIs involved, it's pretty difficult to reason about the types when looking at just the invocation of connect. You'd have to know that str::parse() will figure out what type it's supposed to be and, if it implements FromStr, it will call the from_str() function defined for that type to handle the coercion. That's a frustrating level of indirection for a beginner. And, since all of this is defined in the std library, it's also possible for library authors to similarly declare APIs that have this kind of indirect invocation where you only really understand what's going on if you've studied/memorized that API. I've often thought that a maze of From/Into and Deref coercions would be an excellent approach to the underhanded Rust competition because it's often so difficult to realize when that code is getting executed and it would be pretty easy to hide malicious code in functions that are executed implicitly. It also doesn't help that a sizable portion of the Rust community believes console-based editors like vi and emacs are preferred and more advanced Rust IDEs are still early days and aren't able to help out much with situations like these. It's not that I disagree with these types of language design decisions. I just feel this kind of lack of explicitness makes the language optimized for experienced users rather than beginners and helps give Rust it's deserved reputation for having a high learning curve.
- andrewflnr 9y agoDude, just try it. I see where you're coming from, but in practice I find that the reduction in obviousness to be small, and the benefits of reduced typing and noise in my program to be huge. I've come to see type declarations as work fit mostly for computers and I'm almost personally offended at languages that make me do it for them. So basically, if you try type inference, I don't think you'll want to go back. :) P.S. I hear the Rust plugin for IntelliJ is pretty solid.