Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Explain language feature #57

Open
donaldpipowitch opened this Issue Oct 20, 2016 · 10 comments

Comments

Projects
None yet
5 participants
@donaldpipowitch
Copy link

donaldpipowitch commented Oct 20, 2016

As you probably know from the State of Rust survey 2016 "1 in 4 people commented on the learning curve when talking about Rust’s challenges". I'd like to propose a small feature which could be helpful for beginners.

The LS protocol already contains features "Goto Definition Request", "Document Highlights Request" and stuff like that which help to navigate and understand the actual code itself. As I heard that the LS protocol is extensible I thought that it could be extended to help to understand the language, too.

A small non-Rust example I experienced some days before. I tried to explain a non-JavaScript (actually TypeScript) developer some new ES2105 code. He struggled at a line like that:

abstract async self (): Promise<void>;

Even with syntax highlighting enabled he had a hard time to understand that self was the name of a function and not a keyword from JavaScript (like async) or TypeScript (like abstract). He didn't trust the syntax highlighting. If you'd have been alone (so he couldn't asked), it'd have been really helpful for him, if he could have a feature like "Explain this language feature" inside his IDE which could have told him something like: 'self' is the name of a function. It is a method of classFoo... and so on.

Some years ago I saw an interactive app which did the same for CSS (if I remember correctly). Sadly I can't find it anymore. It worked like that:

.foo {
  color: red;
}

If you hovered above .foo it would tell something like: '.foo' is a class selector.. If you hovered above color it would tell something like: 'color' is a property inside a style rule.. If you hovered above red it would tell something like: 'red' is the value assigned to the 'color' property. and so on.

From my own experience when I started learning Rust I had a hard time to figure out how to spell &str so I can search for it more easily. It would have been nice if I could have asked my editor on any occurence of &str in my code "Explain me this language feature" and if it would have returned something like that.

The str type, also called a 'string slice', is the most primitive string type. It is usually seen in its borrowed form, &str. It is also the type of string literals, &'static str.

Strings slices are always valid UTF-8.

[Read more](https://doc.rust-lang.org/beta/std/primitive.str.html)

I'd have immediately learned "Oh, this is called a string slice."

I'd guess this could be turned into a powerful feature.

@bruno-medeiros

This comment has been minimized.

Copy link
Contributor

bruno-medeiros commented Oct 20, 2016

Seems to me the above can be achieved with just the documentation hover feature, no need for a new LSP extension. The documentation hover can show the doc and signature for any element - and even if the element does not have documentation, we can show just the signature, which would help a user understand what the element is (a function, or something else). This would help with cases like self or .foo in the examples you mentioned above, for those languages.

This could be further augmented by showing doc hover for keywords as well.

As for showing help to the user for complex or combined elements, like &str, I think it would be really, really hard (if not impractical) to do this in a useful way. That is, to figure out exactly what help information the user is looking for, and not something unrelated.

@donaldpipowitch

This comment has been minimized.

Copy link
Author

donaldpipowitch commented Oct 20, 2016

It could be achieved with the current documentation hover feature, but this could mix two different needs too much. Say you hover above self in abstract async self (): Promise<void>; (sorry for the TypeScript example): Do you want to see the documentation of self (What does it do? When do I need to use it?) or do you want to see what this is language wise ('self' is the name of a method.).

I think these are two different goals. The latter is "only" needed, if you don't know the language feature.

@MSleepyPanda

This comment has been minimized.

Copy link

MSleepyPanda commented Jun 22, 2017

I thought a lot about this topic and have toyed with it locally. It is definitely achievable, but a maintenance burden, since you'll have to update with every language feature change.

If i understand doc hovers right, they only show documentation for the current element under the cursor - but what when there are multi word expressions, like impl Trait? impl is now ambiguous, it could refer to a implementation of trait for a type, or a type constraint for an argument / return type. How would tackle that? I don't think this is covered with doc hover.

But what i've toyed with went in a slightly different direction. Instead of it trying to explain everything and all, it would try to find the context the current selected text is in and provide links the language features / patterns used in the book. What would've been explained manually is the connection between these features:

Example code:

#![feature(conservative_impl_trait)]
fn test<'a>(slice: &'a [i32]) -> impl Iterator<Item=&'a i32> {
    slice.iter()
}

fn main() {
let values = &[42, 41, 40];
    let mut counter = 0;
    for item in test(values) {
        println!("Number of truth {}", item + counter);
        counter += 1;
    }
}

If the user now hightlighted the test function definition, it would have explained it like such:

The function test

  • declares the lifetime 'a.
  • It takes an argument called slice, which is a reference to a slice, containing i32s. The lifetime 'a is bound to the lifetime of slice.
  • It returns an implementation of the Iterator Trait. It binds the [associated type][assoc_typ] Item of Iterator to the type &'a i32. This type is a reference, bound to the lifetime 'a (bound to slice), of type i32.

In its function block, the function test

  • calls the method iter() on slice. This is the last expression in test, therefore test returns the result of this method call.
The [function][fn] `test`
 * declares the [lifetime][lifetimes] `'a`.
 * It takes an argument called `slice`, which is a [reference][reference] to a [slice][slice], containing i32s. The lifetime `'a` is bound to the lifetime of `slice`.
 * It returns an [implementation of the Iterator Trait][impl_trait]. It binds the [associated type][assoc_typ] `Item` of `Iterator` to the type `&'a i32`. This type is a reference, bound to the lifetime 'a (bound to `slice`), of type i32.

In its function block, the function `test`
 * calls the [method][method] `iter()` on `slice`. This is the last expression in `test`, therefore `test` returns the result of this method call.

[fn]: https://doc.rust-lang.org/book/first-edition/functions.html
[lifetimes]: https://doc.rust-lang.org/book/first-edition/lifetimes.html
[reference]: https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html
[slice]: https://doc.rust-lang.org/beta/book/second-edition/ch04-03-slices.html
[impl_trait]: https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md
[assoc_type]: https://doc.rust-lang.org/book/first-edition/associated-types.html
[method]: https://doc.rust-lang.org/book/first-edition/method-syntax.html

This is a thought protocol of what my code did, as i currently have not access to my desktop. Though i have to say that this example is cherry picked and more complex situations would create less qualitativ good results. But that's subject to change. Having such capabilities in RLS would be awesome, IMO. It would definitely lower the entry barrier for the "learning by doing" kind of people, who are at some point overwhelmed by the rather extensive / new syntax. With rls possibly beeing integrated into rustdoc and maybe even the playground, it would open up a completly new set of opportunities. "Don't understand this line of code? Just paste it to playground and hit explain!".

I'd like to hear from you, what you think about it :)

@MSleepyPanda

This comment has been minimized.

Copy link

MSleepyPanda commented Jun 22, 2017

Actually, there is a second direction i wanted to go with this:
Different level of details, where it goes more and more in depth with each level increased. Level 1 would be argument slice of type \&'a i32``, where 2 would be like above.

Second, explaining situations with sugar, for example c++ or java. Select a context you're coming from or familiar with and it'll try to bring the syntax closer to you. For example analogy of abstract classes and how trait objects differ, with default functions != virtual functions and so on. In a Java context, this would be trait object <-> Interfaces but more powerful.

@donaldpipowitch

This comment has been minimized.

Copy link
Author

donaldpipowitch commented Jun 22, 2017

With rls possibly beeing integrated into rustdoc and maybe even the playground, it would open up a completly new set of opportunities. "Don't understand this line of code? Just paste it to playground and hit explain!".

Wow, that sounds like an awesome idea!

@nrc

This comment has been minimized.

Copy link
Member

nrc commented Jun 22, 2017

Sounds like it would be really cool! Implementation would be tricky in the current model though.

If i understand doc hovers right, they only show documentation for the current element under the cursor - but what when there are multi word expressions, like impl Trait? impl is now ambiguous

As far as the RLS is concerned, it doesn't see any structure to a program, it only know definitions and references. Trait in impl Trait is a reference, with a link to the definition of Trait, but impl does not exist for the RLS, nor does the type impl Trait.

I'm not sure how one could add info about every type or structure without massively increasing memory use and slowing things down. Perhaps this is something that will work better once the RLS can interactively query the compiler?

@MSleepyPanda

This comment has been minimized.

Copy link

MSleepyPanda commented Jun 23, 2017

without massively increasing memory use and slowing things down

Well that's indeed a question of concern. The current version uses syntex and parses the whole given context, to provide as much information as it can, e.g. variables in scope and so on (not the whole input is explained, one can submit a sub region which is explained more thoroughly). Also, it makes a few assumptions, e.g. that the given code is already syntactically correct.

I still have to look how far rls is bond with rustc, best case would be that my "whole pass" logic would be redundant with the current framework. I'll get in touch when i have more information :)

@nrc

This comment has been minimized.

Copy link
Member

nrc commented Jun 27, 2017

So, if you're using Syntex it sounds like this doesn't need to be built-in to the RLS? You could follow the rustfmt model where it is a separate project that gets linked in to the RLS, rather than using data from the RLS. That means we don't end up slowing the RLS down in any way because we'd only run this on demand.

@MSleepyPanda

This comment has been minimized.

Copy link

MSleepyPanda commented Jun 29, 2017

It is meant to run standalone, though as i'm rewriting it atm, i thought about adding it into tree. But on-demand invocation makes much more sense!

Will (hopefully) publish this weekend.

@donaldpipowitch

This comment has been minimized.

Copy link
Author

donaldpipowitch commented Jul 17, 2018

Hi there! 👋I just watched an awesome talk on Curry on from @Felienne about the importance of pronunciation of code for learning and understanding a language - and that can also ease the cognitive load of a seasoned programmer. It immediately reminded me at this issue I wrote a year ago. I wonder if it would be worthwhile to look at this topic again 🤔

(I heard @withoutboats was here as well. Maybe he heard the talk as well and can better tell if a "language explantation/pronunciation" feature would be a good idea to help to teach Rust.)

Thanks 🙃

@Xanewok Xanewok added the enhancement label Mar 3, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.