8 ms·
Experimenting with Rust generics and dynamic traits
- Fede_V 11y agoCool blog. I tried playing around with Rust as well on some toy problems, and had a similar experience: cryptic error messages that only made sense in hindsight. It's an awesome language, but I wish there was a bit more effort put into into making it 'ergonomic'. Of course, it's an open source effort so nobody is owned anything - but useful error messages are incredibly important, especially when the language pushes so many new concepts.
- hellofunk 11y agoA fair but common criticism of new languages. Clojure is famous for this problem as well.
- masklinn 11y agoElm, however, goes the exact opposite and tries to make compiler error messages as helpful as possible to beginners, especially from 0.16 onwards: http://elm-lang.org/blog/compilers-as-assistants http://elm-lang.org/blog/compilers-as-assistants with a whole repository dedicated to non-compiling programs with less than ideal error messages: https://github.com/elm-lang/error-message-catalog/ https://github.com/elm-lang/error-message-catalog/ TBF might be simpler for Elm as it eschews much in the way of type abstractions.
- bjz_ 11y agoYeah, Elm has a far simpler type system at the moment (no ad-hoc polymorphism for example), so it cuts down on the difficulty of experimenting with new ways of displaying errors. Which I think is a good thing to do, especially seeing as one of the goals of Elm is to make static type systems more 'friendly' to a wider audience. But it is definitely going to push the developers of more complex languages to improve their developer experience - we in the Rust world are certainly taking note!
- StavrosK 11y agoOh wow, those error messages alone make me want to try Elm. It looks like I could learn the language just from the compiler output.
- benashford 11y agoHow could that particular error (using that as an example) be improved? > error: the trait `core::fmt::Debug` is not implemented for the type `T` That pretty much is the problem. It seems the bigger pain point is as you say "they make sense in hindsight", but that's because (as the author acknowledges) of expectations driven by other programming languages. C++ wouldn't have raised an error because the type-checking is done after template expansion, whereas Rust is the other way around. The biggest criticism from me would be the hints underneath advising the author to implement the Debug trait, whereas the solution is to add a trait bound to the code instead. If anything I'd say Rust's compilation errors are above average in both the accuracy of the error message, and helpful hints. The learning curve around concepts such as lifetimes and moved values and other rare features do take time, however.
- deleted 11y ago[deleted]
- lhnz 11y agoI would like it to say something like "Either the trait `core::fmt::Debug` is not implemented for the type `T`, or it is implemented but the compiler does not know about it in this context." Not sure if that is the language I would use, but that is what I want it to say. Suggesting that I might be able to solve the problem by providing more information to the compiler would help me realise how I could solve the problem. I've had similar problems when developing Rust code, and I wonder whether they would be happy to accept changes to their error messages? My biggest difficulties trying to understand Rust error messages were either with lifetimes or errors emanating from within macros (it is very hard to see what is failing when you have never seen the code itself.)
- arjie 11y agoInteresting. I'd read that code as "For all T, if we have a Buffer<T>, print out the Vec<T>'s elements" and it makes sense that this doesn't work. It isn't that the compiler doesn't know about it, but that T is not constrained within the form to something printable and consequently you can't print it. It would seem more confusing if it had indeed worked, since that would mean (in a semantic sense) that T is auto-constrained to the types that are actually used as T, so you can't reason about the code having the T on its own but only within the context of the larger form. Not arguing or anything about what error messages are valid. I just found your perspective about the "compiler not knowing" interesting and felt like sharing this.
- pcwalton 11y agoWe put more effort into error messages than almost any language I know of, except Elm and Haskell dialects. A huge fraction of rustc commits are tweaking error messages for ease of use. Rustc error reporting was deliberately based on that of clang. In particular, I think it is going to be impossible to have error messages for lifetime errors that are solvable without doing at least some background reading.
- Fede_V 11y agoI can only offer my point of view as a complete rust novice. Lifetimes are the most intriguing and new aspect of programming in rust - this unfortunately means that when people first start with the language and they run into non-obvious errors, they will need a little handholding. Google/stackoverflow of course help, but, as an expert, I think you may be a bit biased by your own experience as to how helpful the compiler errors actually are.
- masklinn 11y ago> Lifetimes are the most intriguing and new aspect of programming in rust - this unfortunately means that when people first start with the language and they run into non-obvious errors, they will need a little handholding. I genuinely have no idea how you'd even go around improving lifetime errors, if somebody manages to crack that one I'd probably be willing to set up a recurring donation to whatever they wish.
- steveklabnik 11y agoThere's been at least one promising idea floating around: using an IDE to draw out lifetimes, so you can see how they overlap. Something like slides 172/173 of http://www.slideshare.net/nikomatsakis/rust-mozlando-tutorial http://www.slideshare.net/nikomatsakis/rust-mozlando-tutoria...
- Fede_V 11y agoThat would be fantastic!
- infinity0 11y agoThis is pretty much how every language does generics except C++, so it's not actually an issue with Rust.
- dbeck74 11y agoI don't think it is an issue either. In fact I was pretty happy when I understood the concept. Unfortunately I haven't got experience with generics in languages other than C++, so thanks for pointing this out.
- mmebane 11y agoI've often thought of C++'s templates (when used in the "straightforward" manner, anyway) as more of compile-time duck typing than a real generic type system. Even moving from C++ to Java took a while to get used to.
- scott_s 11y agoMoving to Java generics took me a while mostly because of type erasure. In C++, I'm used to being able to use the type in a generic class or function, which kept biting me in Java.
- masklinn 11y agoWhat do you mean by use the type? Query for type metadata at runtime?
- deleted 11y ago[deleted]
- scott_s 11y agoNo, that's not what I meant, but yes, that is a limitation. (Just not one I hit.) The big one is not being able to allocate objects of that type. For example, in C++, I can say: template <class T> T* allocate() { return new T(); } That's not possible in Java because of type erasure. When you try something like that, you get an error message like: Erasure.java:12: error: unexpected type return new T(); ^ required: class found: type parameter T where T is a type-variable: T extends Object declared in class Foo Again, this is because of type erasure: Foo<T> is really Foo<Object>, where Java just does a cast for you to T in all of the right places. It does not actually know the type. For me, that lead to all sort of contortions because a class Foo<T> could not allocate objects of type T internally. I needed to create factory methods in other places which Foo would call. In the instance I'm thinking of, those factory methods ended up living in derived classes. C++ templates have its issues, but it allows parametric polymorphism. In Java, I could not write such code, which was what I was used to. Because of type erasure, I was forced more towards subtype polymorphism, even though I was implementing generic classes.
- mrkgnao 11y agoRust's traits seem similar to Haskell typeclasses. I saw the error at once, perhaps for that reason: I could almost hear ghc whine about not being able to deduce Show for arbitrary types.
- bjz_ 11y agoRust's traits were indeed inspired by typeclasses, so those coming from Haskell shouldn't have much difficulty with these kinds of errors. The tricky thing is trying to make it easier for those who don't have that experience.
- GaveUp 11y agoHardly accurate but coming from the C# world I thought of traits as a hybrid between an interface and extension methods. I think the biggest challenge was that, at first glance, a trait does appear to be very close to an interface, but really it is it's own beast.
- Sharlin 11y agoThe C++ working group has actually tried to provide a solution to this issue - that templates are only type-checked at instantiation time - for almost ten years. The original "Concepts" specification was overly ambitious and was dropped from C++11 - and just this year it was deemed that even the newer "Concepts Lite" proposal is not yet ready for C++17.
- finnyspade 11y ago22:34 error: the trait `core::fmt::Debug` is not implemented for the type `T` [E0277] 22 println!("trait: {:?}", i); This error message is fantastic! On line 22, i is of type T which does not implement Debug. The hint is off, but the actual error is super useful. Turns out if you google "Rust e0277" which is the error code he got, this is the top result: https://users.rust-lang.org/t/generics-or-how-do-i-solve-an-e0277-error/3072 https://users.rust-lang.org/t/generics-or-how-do-i-solve-an-... Which contains the same solution to his problem. TL;DR Nothing to see here, just a case of "let me google that for you"
- masklinn 11y agoedit: please don't downvote finnyspade into the negatives, that's not helpful > The hint is off, but the actual error is super useful. I completely disagree. The actual error is very basic and only useful if you already know what it pertains to, that the hint be way off is actively harmful. > TL;DR Nothing to see here, just a case of "let me google that for you" No, it's a case of the compiler not helping and just dumping the raw error in your lap, let's not settle for being GCC when we can do better: http://elm-lang.org/blog/compilers-as-assistants http://elm-lang.org/blog/compilers-as-assistants You shouldn't need to google a bloody traits bound error (and may not even be able to, because you're trying Rust on a bus during your commute and have run out of data) (note that the rustc --explain output doesn't quite help either, it also assumes you already understand trait bounds and also suggests implementing the relevant trait on your type, which is the other way around from the issue, a careful read of the code snippets may hint at the solution, but the explanation doesn't point to it)
- finnyspade 11y ago> The actual error is very basic and only useful if you already know what it pertains to The error is really solid at showing a type mismatch. Which is of the form "I wanted X but you gave me Y". > that the hint be way off is actively harmful That's true and they could probably do a bit better for type mismatches on type variables vs concrete types > just dumping the raw error What's the difference between a "raw error" and something else. If the hint was accurate would it still be a "raw error" because it's not styled like those elm errors? Any more info (aside from a better hint which I concede should be better) would have to be an actual explanation of static typechecking which seems a bit extreme. All I'm saying is while this error isn't a paragon of what all good error messages should be, it's no more cryptic than any other similar error. Even the nicely formatted elm errors say essentially the same thing.
- finnyspade 11y agoFor interested parties, there's been an open issue on the hint text for this error since September of last year. If ya want to help out take a crack at it! https://github.com/rust-lang/rust/issues/28660 https://github.com/rust-lang/rust/issues/28660
- bsaul 11y agoright when i was about to jump into the elixir / phoenix bandwagon, thinking its type hints would be enough for me ( who like types to be as strong as possible)... damn... when is the erlang pure actor model ( as welle as OTP) going to be implemented in another language ??
- dbeck74 11y agoI am waiting for that too. Especially Rust + OTP would be a big thing for me.