[HN Gopher] Rust extension traits, greppability and IDEs
___________________________________________________________________
Rust extension traits, greppability and IDEs
Author : todsacerdoti
Score : 83 points
Date : 2022-01-29 15:07 UTC (7 hours ago)
(HTM) web link (eli.thegreenplace.net)
(TXT) w3m dump (eli.thegreenplace.net)
| [deleted]
| brundolf wrote:
| I think it's fair to be sad that greappability is being lost. But
| I also don't think we should limit ourselves to it; treating it
| as a design goal holds back the field. Languages can be much more
| powerful when they drop that constraint and assume the reader has
| (language-aware) tooling available to help them make sense of
| code.
|
| I think instead we should focus on continuing to push the tooling
| forward. Language servers were an important step in this
| direction, freeing us from comprehensive IDEs, but I think that's
| just the tip of the iceberg. More recently we have Tree Sitter,
| and GitHub at least can do some basic semantic analysis of code
| right in their UI. How can we make it even easier to build tools
| that understand a language? And what new interfaces can we put on
| top of them? What about a CLI that lets you grep code at an AST
| level, maybe showing the types of the expressions it yields? What
| about a declarative format like TextMate that lets you describe
| the basics of how a type system is wired, so you don't have to
| craft a whole language server by hand?
|
| Maybe there's also something to be said for designing languages
| to be "tooling-friendly", even if that doesn't mean "as plain-
| text". Lowering the bar for writing tooling that can have a
| semantic understanding of the syntax and types, etc.
|
| There's lots to be explored here, in my opinion
| berkut wrote:
| It's not just editors/IDEs though...
|
| Which diff/merge tools support language servers currently?
|
| i.e. how do you thoroughly code-review changes without
| switching between a decent diff program and an IDE continually?
| brundolf wrote:
| GitHub and VSCode both allow this (and I'm sure other rich
| editors do too). In fact, using GitLab at work, I open up
| most of the MRs I review in my local editor specifically for
| this reason
| berkut wrote:
| Do you mean "github.com" or Atom their editor?
|
| Yeah, sure Rich Editors support the "basics" of diffing,
| but for complex (i.e. 3-way) merges, I find them pretty
| limiting: stuff like Beyond Compare, p4diff are more useful
| in those situations IMO.
| brundolf wrote:
| Yeah, github.com has started adding rich hover-overs and
| click-throughs on their web interface for some languages
|
| I'm not familiar with those other tools, but it's not
| hard to imagine they or similar tools could one day add
| rich language integration using language servers, tree-
| sitter, or something else
| pjmlp wrote:
| They aren't new as idea, but I guess one needs to thank
| Microsoft for pushing it.
|
| https://dreamsongs.com/Cadillac.html
| kvark wrote:
| I like to include traits closer to where they are used, to help
| with this. For example, "use cgmath::InnerSpace as _;" at the
| start of a small function. The "_" is a strong signal that I
| don't need the type itself, but only properties of this trait.
| vlmutolo wrote:
| This is the first suggestion I've seen in this thread that
| actually helps to make the code more readable.
| erwincoumans wrote:
| greppability has a high googleability.
| chewbacha wrote:
| I think I've unconsciously biased myself away from extension
| traits and have favored using traits at function boundaries
| instead. This still keeps the greppability and the polymorphism.
| But sometimes can make lifetimes trickier.
| woodruffw wrote:
| I _strongly_ agree with this as someone who enjoys writing Rust
| and who doesn 't use an IDE (or an LSP plugin, or anything like
| that): it's mildly annoying to have to `use` a bunch of traits to
| bring their contracts into scope, but for that `use` to _not_ be
| explicit about the contents of those contracts. Forgetting to
| import `Read`, `Write`, `TryFrom`, etc. probably accounts for
| over 75% of my "small" compilation errors.
|
| I can't find it now, but I remember an RFC that proposes a
| solution to this, although in the opposite direction (i.e., more
| traits in the standard prelude). It would be interesting to see a
| `use` variant in a future edition of the language that allows
| users to bring in specific parts of the trait's contract, e.g.
| `use std::io::Read::read_exact`.
| fmorel wrote:
| One possibility could be something like C# global usings added
| last year. Instead of having your usings in every file, you can
| define them with the `global` keyword and take effect in every
| file in your project. It's great for common things like the
| `IEnumerable` extension methods which reside in `System.Linq`.
| pjmlp wrote:
| Stuck in the past indeed, using IDEs was already a thing in
| Windows 3.x and Mac OS classic, exercise for the reader when they
| came to be.
|
| Or better yet, the development experience of using Toga in
| Mesa/Cedar (1987).
|
| http://toastytech.com/guis/cedar.html
|
| https://www.youtube.com/watch?v=z_dt7NG38V4
|
| Or Smalltalk, Interlisp-D or Lisp Machines for that matter.
|
| The time a language must be usable with Notepad alone is long
| past due.
| Diggsey wrote:
| It's a shame when articles show non-idiomatic Rust code to people
| who might be not realise it :/ fn
| magic_num(&self) -> usize { return if self.name.len()
| == 0 { 2 } else { 33 }; }
|
| The `return` statement is only used for early-exit, so this would
| be written as: fn magic_num(&self) -> usize {
| if self.name.len() == 0 { 2 } else { 33 } }
| brabel wrote:
| Why are Rust developers so pedantic with this stuff.
|
| What the author wrote is perfectly valid, fine code. Please
| stop insisting everyone does something one way or another when
| there's no clear advantage here to doing so except for the lack
| of single bloody keyword.
| vlmutolo wrote:
| It's "perfectly valid, fine" with the exception that it's
| different from how the vast majority of Rust programmers
| write code. That in itself is a problem. Rust has two widely-
| used tools that enforce style: `rustfmt` and `clippy`. The
| former enforces formatting style and the latter general
| programming style, such as whether or not to use a `return`
| statement (`clippy` also does non-style lints).
|
| For many of these formatting/stylistic lints, there are valid
| arguments to be made for an alternative choice. I personally
| often disagree with one or both tools. I still follow them.
|
| The huge benefit here is that most Rust codebases look
| identical. I can open up burntsushi's regex crate and see
| code that is formatted and styled exactly like mine. It makes
| reading new code a lot easier.
| SquibblesRedux wrote:
| I prefer to use explicit return statements everywhere -- for
| greppability.
| berkut wrote:
| Yep, and read-ability: it's more obvious at a glance where
| early-exits are.
| ReleaseCandidat wrote:
| If you have to search for your returns you have either too
| many or your function is too long ;)
|
| I'd even say any return is actually one too many.
| setr wrote:
| Half the functions I write follow the format
| If !validation_rule1 { return default/err } If
| !validation_rule2 { return default/err }
| Work... If !validation_rule3 { return
| default/err } Work... return
| result/success
|
| Don't know how you'd get away with single return except by
| horrifically nesting conditionals
| dragonwriter wrote:
| > Don't know how you'd get away with single return except
| by horrifically nesting conditionals
|
| That pattern is addressed by _chained_ not _nested_
| conditionals, which can then be wrapped in a match, i.e.:
| if !validation1 { err1 } else if !validation1 {
| err2 } . . . else {
| ...work...; success_result }
|
| the error checking part can be reduced to an iteration
| with appropriate definitions of a structure for the data
| to be validated, etc., like: match
| validators.find_map(|v| v(data)) { Some(err) =>
| err, None => { ...work...; success_result }
| }
|
| EDIT:
|
| I missed the intermediate work steps in your post when I
| initially wrote the response. That can be done a number
| of ways, e.g., breaking things up into to chained steps
| (each of which might use the above pattern) that mix
| validation and work and return a Result type with either
| the data for the next step to consume or an error.
| ReleaseCandidat wrote:
| That's what something `bind`-like is for, like Rust's
| `and_then`. (validation_rule1')
| .and_then(validation_rule2') .and_then(work1)
| .and_then(validation_rule3') .and_then(work)
| The_rationalist wrote:
| steveklabnik wrote:
| (Also clippy will probably suggest is_empty() over len() == 0)
| tialaramex wrote:
| I should probably write is_empty() more often, but, it is
| actually doing anything that len() == 0 isn't doing, or is it
| just that is_empty() better explains what I presumably wanted
| to ask?
| spoiler wrote:
| I've not looked at the implementation, so I can't answer
| the first question, but to answer your second
| point/question: yes! I think getting across intent is very
| important for the _other_ people reading your code.
|
| I guess here it doesn't matter as much since it's a simple
| enough cases, but I'm just talking in the general sense.
|
| With that said, I think is_empty probably has very slightly
| smaller overhead when it comes to figuring out the author's
| intent. Because, well, that was the intent. Length checking
| against 0 is merely a method of that intent.
|
| Also, this "intent decoding" while reading code (no pun
| intended) adds up in mental cost, IMO. So, it wears down
| the the reader/reviewer attention more quickly.
| steveklabnik wrote:
| From clippy's docs:
|
| > Some structures can answer .is_empty() much faster than
| calculating their length. So it is good to get into the
| habit of using .is_empty(), and having it is cheap.
| Besides, it makes the intent clearer than a manual
| comparison in some contexts.
|
| It also has a lint for implementing both methods if you've
| only defined one, to help perpetuate the convention.
| lr1970 wrote:
| issue `cargo doc` command to generate the documentation that will
| expose extension traits among other things. Not perfect,
| certainly. But together with rust-analizer and grep the generated
| docs cover all the bases.
| cliftonk wrote:
| what hes looking for can trivially be seen using `cargo docs` or
| `rust-analyzer` https://rust-analyzer.github.io/manual.html
|
| rust-analyzer supports vim/emacs as well. in vim i can put my
| cursor over a symbol and get all the information id get from an
| ide via a quick shortcut. a feature-rich vimrc for rust can be
| seen here:
| https://github.com/jonhoo/configs/blob/master/editor/.config...
| SquibblesRedux wrote:
| I have been bit by the lack of greppability for traits a few
| times. I love the trait system, but I wish there was a way to
| track back to definitions without relying on the IDE of the day.
| It reminds me of old C++ nightmare scenarios where the original
| developers would overload all the operators and bury all sorts of
| redefinitions in an endless hierarchy of includes.
| _ZeD_ wrote:
| > Who in their right mind has the courage to tackle a Java
| project without an IDE?
|
| onestly, as an old-jeezer, I still don't understand the hate on
| IDEs.
|
| Who in their right mind has the courage to tackle _ANY_ project
| without an IDE? I constantly see my collegues insist to use
| vscode without plugins, then fork or COMMANDLINE GIT (ugh..) then
| external tool for viewing jsons, and explicitly use postman and
| whatever tool...
|
| and then fail to understand the very basic fact that an
| integrated collections of tools works better for the end user.
|
| ...I... I don'k know...
| ithkuil wrote:
| I tried and managed to avoid IDEs for years. Then I started to
| use rust for work. I accepted that I just had to use an IDE and
| I picked one. I was happy with CLion; it has a very good
| support for rust.
|
| Unfortunately I had to develop on a remote machine (because
| compiling rust in my local machine is too slow). Jetbrains
| solution for remote development just didn't work for my use
| case (the remote was a M1 ARM running MacOS, not supported by
| jetbrains gateway). So I switched to vscode. Vscode editor is
| great, the support for remote development is also very good.
| Unfortunately rust-analyzer is not as good as jetbrains's rust
| plugin.
|
| This is a problem with IDEs: you're either all in or you're
| out. Language servers did help decoupling language support from
| the actual window where you type stuff, but still not
| everything is in a language server (e.g. jetbrains rust plugin
| is not a reusable language server)
| elsjaako wrote:
| Personally I've just have bad experiences with integrated tools
| like that. I'm sure if you just use it in some "normal" way
| it's fine, but I don't know how that is, and I've spent many
| hours wrestling with visual studio because the magic "easy to
| use" functionality stopped working or broke something. Add to
| that the interface changing with different versions. Having
| several tools that do one thing that I understand has led to
| less frustration for me.
| thesuperbigfrog wrote:
| I am not a Rust expert, but wouldn't extension traits and Unicode
| character look-alikes allow for a subtle attack vector?
|
| What would stop someone from creating a trait that looks similar
| to an existing function name, but that does something bad?
| chewbacha wrote:
| You would still need to import the malicious trait in order for
| it to be extended. If you already have included a bad crate
| which has a bad trait, then why not replace the implementation
| of a well-named function. I can't see a reason to use a
| homoglyph in the function name.
| capitalsigma wrote:
| Remember that in Python you can mutate `globals` to change the
| meaning of arbitrary symbols. It seems like a lost cause if you
| are running a compromised library.
| richardwhiuk wrote:
| Rust emits a compiler warning if you use homoglyphs:
| https://blog.rust-lang.org/2021/06/17/Rust-1.53.0.html#unico...
| melissalobos wrote:
| Similar-ish concerns have been raised before:
| https://www.lightbluetouchpaper.org/2021/11/01/trojan-source...
| davidkunz wrote:
| I like the concept of making the 99% case as easy as possible and
| providing a failsafe when you encounter the 1% case, here an
| example.
|
| People usually complain about Nim's import behaviour which is
| roughly an `import *` in other languages, making it hard to
| immediately tell where things come from. Personally, I find it
| fantastic because it removes a lot of boilerplate. In case of
| conflicts, the compiler throws an error, forcing you to qualify
| your import.
|
| Now in Rust, you explicitly need to import the trait in order to
| use it because there _might_ be naming conflicts. Here, the 1%
| case spoils the 99% case.
| tobz1000 wrote:
| I prefer the Rust/ES/Python etc. import syntax not because of
| ambiguity, but readability. Having everything traceable by
| quickly scanning the code, without IDE assistance, often speeds
| up my understanding of a file. And it becomes essential of
| you're reading code in an IDE-less environment, e.g. github
| gists. Worth the verbosity IMO.
| uncomputation wrote:
| Each language picks its own trade-offs. I'm glad Rust errs on
| the side of caution for imports. Unlike most other languages,
| with Rust I know I can enter any file and know exactly and
| precisely what symbols resolve to. This not only simplifies
| things for me but fits my mental model of programming much
| better (deterministic, predictable, explicit).
| melissalobos wrote:
| I feel like this is a pretty reasonable article, and it makes a
| good point. Much like Lisp most Rust codebases that I have seen
| are written usually by smaller teams of people. The issue the
| Author brings up is one that would be a problem if you had a very
| large team. Does anyone have any experience working on a large
| Rust project where there was extensive use of Traits?
| slaymaker1907 wrote:
| As a big proponent of grepability, I think extension traits are
| still reasonable. You need to find out what the trait is that
| defines that method, but that often isn't too difficult. Once you
| know that, you just need to look at the module defining the
| struct and the module defining the trait.
|
| Two things that can improve this are preferring
| Trait::method(obj) notation and importing traits explicitly
| rather than relying on crate preludes.
| eyelidlessness wrote:
| As someone who has only dabbled with Rust, this:
|
| > preferring Trait::method(obj)
|
| ... vastly improved my understanding of trait usage.
| wffurr wrote:
| Having magic names show up in my code without an explicit
| import somewhere can be really frustrating, especially in
| unfamiliar code bases where I'm trying to contribute a small
| change.
|
| I think your suggestions do a good job addressing that; could
| be a thing for a style guide.
| camgunz wrote:
| I've been digging more into Rust, and things not working because
| I forgot to import the trait drives me _bonkers_. Like, you
| create a struct, you build an implementation, you implement a
| trait on it, you try and use it in another module, you can 't,
| you feel like you must have goofed something, you hack around for
| an hour, oh you remember you forgot to import the trait you
| already implemented, you open up HN in a fury.... Is there a
| really important reason rustc doesn't know what traits are
| implemented on what structs? It can't be a dependency graph
| thing, it has to know about the struct in the first place.
| veber-alex wrote:
| I suggest you start reading the compiler error messages as they
| say exactly what trait is missing, no need to waste an hour.
|
| For example for this code: trait Foo {
| fn foo(&self) {} } struct Bar; impl
| Foo for Bar {} mod test { use super::Bar;
| fn test() { Bar.foo(); } }
| 22 | Bar.foo(); | ^^^ method not
| found in `Bar` | = help: items from traits
| can only be used if the trait is in scope help: the
| following trait is implemented but not in scope; perhaps add a
| `use` for it: | 20 | use crate::Foo;
| |
| wyager wrote:
| Haskell automatically imports all typeclass definitions
| (equivalent to traits) when you import a module, so you
| sometimes see lines like
|
| `import Foo.Bar ()`
|
| Which looks like it's just importing nothing at all (`()`) but
| is actually pulling in some traits and nothing else.
|
| You don't see this often because "orphan instances" (instances
| defined in a file besides the location of the trait definition
| or the type definition) are discouraged, but they do occur.
| mplanchard wrote:
| If you're using rust-analyzer in your editor of choice, it will
| often suggest and auto-import traits when you try to use their
| methods with the trait not in scope. It knows, based on the
| dependency graph and your own code, all of the traits that
| could provide a method.
|
| I use rust-analyzer in emacs, but it's available in any editor
| that supports language servers.
|
| With my setup, I'll start typing a method, get a completion for
| the trait method I want with the trait indicated, and select
| the completion. The trait is then automatically imported and
| the method is completed.
| jolux wrote:
| The bigger problem is that neither rust-analyzer nor IntelliJ
| Rust currently support go-to-definition for trait methods. They
| will just give you a popup with all the overloads. I understand
| this is being worked on with Chalk but it's quite jarring coming
| from Java and C#.
|
| edit: here's the GitHub thread https://github.com/rust-
| analyzer/rust-analyzer/issues/4558
| IshKebab wrote:
| It does support go to definition for trait methods. It just
| goes to the declaration, not the implementation.
|
| Not ideal, but still way better than just not doing anything.
| jolux wrote:
| Well, it should support go to implementation too.
| veber-alex wrote:
| As mentioned in that github thread, this works in JetBrains
| IDEs.
|
| For rust-analyzer it's blocked on improvements in Chalk.
| jolux wrote:
| Yeah, except I've tried it in CLion with the plugin, and it
| doesn't work.
| cletus wrote:
| So I've used Hack extensively and I'm sympathetic on the
| obscurity that can come from traits. It can get completely out of
| control. To be fair, object hierarchies, even interface
| hierarchies, can also get out of control, particularly when
| multiple inheritance is allowed.
|
| But the real message here is if you're relying on regular
| expressions to implement IDE functions, plugins, language syntax
| checking, auto completion and so on, you're going to have a bad
| time. Period. This is the real weakness of VS Code IMO.
|
| An IDE that operates on the syntax of the language is
| _infinitely_ better than one that relies on regular expressions
| and simply treating source files as "text".
|
| This is one reason I will always use Jetbrains IDEs given any
| choice because I know I can hover over a symbol and it'll tell me
| where it comes from. "Go to definition" will just work.
|
| As soon as you start designing your language practices around the
| limitations of what regexes can do you're going to have an even
| worse time. For example, in Hack (@FB) we couldn't use namespaces
| or trait aliasing. You then had people asking "why are people
| creating all these abstract final classes with static methods in
| them?" when the answer is obvious: because they can't use
| namespaces).
|
| My experience using C++ with VS Code was just horrible because
| the IDE was unreliable when it came to pointing out syntax or
| type errors. So you could waste your time compiling something
| that doesn't compile. I've never had this issue with CLion, for
| example.
| halpert wrote:
| VS Code definitely has Rust language server support via the
| Rust extension.
|
| https://marketplace.visualstudio.com/items?itemName=rust-lan...
| veber-alex wrote:
| You should not be using the RLS extension, it hasn't been
| updated in over a year.
|
| Instead you should use rust-analyzer which will soon become
| the official rust extension.
|
| https://marketplace.visualstudio.com/items?itemName=matklad..
| ..
| umanwizard wrote:
| Sorry, had to downvote this as I know people who have gotten
| burned by installing this plugin in the past and got confused
| by why their setup was so broken.
|
| What you really want is to install the rust-analyzer plugin,
| not the Rust plugin.
| SquibblesRedux wrote:
| Thanks - you have just improved my programming life. Just
| the ability to see the implicit types is awesome.
| halpert wrote:
| I actually use rust-analyzer, but I'm not a hardcore Rust
| developer, and I wasn't even aware there were two plugins.
| I picked the first result off of Google. The fact that the
| first result is a bad plugin seems like an issue with the
| Rust community.
| umanwizard wrote:
| It's an issue with VSCode, not the the Rust community.
| Microsoft is pushing their developed-in-house Rust plugin
| as the default.
| steveklabnik wrote:
| > Microsoft is pushing their developed-in-house Rust
| plugin as the default.
|
| I find this comment very confusing. Neither plugin was
| developed by Microsoft.
|
| The "rust" extension generally comes up first because
| it's older and has significantly more downloads. That
| being said, it's true that imho everyone should use the
| new one.
| staticassertion wrote:
| I'll take almost any cost for extension traits. Going back to
| Python this is part of what I miss most.
|
| There is no way to add methods to a type in Python that mypy
| understands. You have to create a new type. This leads to code
| that is very difficult to extend and pushes you towards
| inheritance.
|
| I talk a bit about this here:
| https://insanitybit.github.io/2020/07/19/intersection-types-...
|
| For me, this became a huge problem when I was building a plugin
| system in Python. I wanted types to only own their own logic, but
| I also wanted types to be able to tell other types about
| themselves. For example, we have a Process and a File. I want to
| be able to go from Process to File with only one of those knowing
| about the other. Without extensions you are forced to create ugly
| workarounds.
|
| Also, I've never had a problem with intellij and extension
| traits. I kind of wonder why you'd stick with a tool that's a bad
| experience.
| animal_spirits wrote:
| I read your blog post and TBH I'm not really sure what
| extension types are, I've never used rust. But I tried this
| solution in python and am curious is this is something you
| tried? >>> class A: ... def
| foo(self): ... print('foo') ...
| >>> class B: ... def bar(self): ...
| print('bar') ... >>> A.bar = B.bar >>>
| A().bar() bar
|
| Functions in python are objects as well. So while you can't do
| this to built in python types, there is a high likelihood you
| can do this to most objects in python libraries.
| staticassertion wrote:
| The problem with your code is that it won't _type check_. It
| runs just fine because CPython doesn 't care about type
| checking. But if you run mypy on it it will not understand.
| animal_spirits wrote:
| Oh I see, yea you are correct
| dathinab wrote:
| I wonder if the author is aware that rust has a well working,
| well searchable documentations you can easily open locally in
| case you have no internet ("rustup doc" & "cargo doc --open").
|
| > You check the documentation of that crate and indeed, you find
| the write_u16 method there; phew.
|
| Like, all wild card impl. traits are in the documentation,
| including such which are dereferenced.
|
| EDIT: Just to be clear if you pull in other code, including
| potential traits, you need to open the documentation specific to
| your crate (cargo doc).
| ithkuil wrote:
| Running cargo doc in my project takes sometimes >8 minutes to
| run
| jrimbault wrote:
| If you split your crate in small crates in a workspace you
| should see improvements in compile time.
| [deleted]
| gameswithgo wrote:
| Depending on the day I will either dream of a language
| specifically designed with a particular IDE in mind and all the
| cool stuff you could do with that as a ground up assumption
| (google f# type providers for some inspiration), other days I
| dream of a language whose design specifically does not require an
| IDE, so you can easily understand the code from github or vim or
| anywhere. For instance global or function wide type inference is
| handy but can make non IDE use of a language really hard because
| you can't immediately see what the types are.
|
| Perhaps the general design principle should be to tend towards
| one extreme or the other, rather than end up with a language that
| needs an IDE but doesn't leverage it fully.
| Sindisil wrote:
| > Who in their right mind has the courage to tackle a Java
| project without an IDE?
|
| /me raising hand
|
| I've used all the major IDEs on real projects for years at a time
| each, and so done years (often on the same projects) with just a
| quality editor and a set of external tools, and I honestly
| slightly prefer the latter.
|
| I'm effective both ways, but my observation is that my work is of
| better quality when working in a non-IDE environment.
|
| I fully understand that, as with most such things, says as much
| or more about me than about IDEs.
|
| I think a large element is that, not having auto-complete, I find
| myself reading more docs (increasing system familiarity) and
| noticing unergonomic interfaces sooner.
|
| The one feature I do miss is language aware navigation, but that
| loss is somewhat balanced by the lack of disruption when said
| navigation inevitably breaks, due to non-compiling code or
| working with new language features not yet supported by the
| tools.
| missed-pos wrote:
| Can you tell more about tools you use? And what about renaming
| functions/variables...? It seems it's error prone without
| IDE/language server.
| masklinn wrote:
| > "Interesting", you think, "I didn't know that Vec has a
| write_u16 method". You quickly check the documentation - indeed,
| it doesn't! So where is it coming from? You grep the project...
| nothing. It's nowhere in the imports. You examine the imports one
| by one
|
| > [...]
|
| > It's entirely possible that using a language like Rust without
| a sophisticated IDE is madness, and I'm somewhat stuck in the
| past. But I have to say, I do lament the loss of greppability.
|
| Seems more like Eli has completely missed an important and
| integral feature of the rust ecosystem: `cargo doc`.
|
| While the stdlib sadly remains out of it (long-standing RFC
| 2324[0]), cargo doc will otherwise generate the documentation
| _including all dependencies_ by default.
|
| This means you can in fact get this information by "checking the
| documentation", just the right one: a global search in the
| project's `cargo doc` will quickly tell you where the method
| comes from[1], without the need for any IDE or complicated
| integration (though I don't think it works with text browsers as
| it uses javascript, for terminal / console contexts maybe try
| `rusty-man`, I don't know how good it is tho).
|
| I couldn't imagine working on a Rust project without having its
| `cargo doc` permanently open in a tab, having the unified offline
| documentation for all your dependencies is just way too useful, I
| run `cargo doc` almost as often as I run `cargo check` (despite
| that being mostly useless for binary crates...)
|
| [0] https://github.com/rust-lang/rfcs/issues/2324
|
| [1] just tried it on a local project, the first methods it
| surfaces are 4 methods from byteorder (on ByteOrder,
| WriteBytesEx, BigEndian, and LittleEndian) and one from
| serde_json (on Formatter).
| slaymaker1907 wrote:
| Good point, and for those unaware, cargo doc also shows you all
| of the traits defined for a type including those from other
| modules. You can even quickly see the source code defining the
| trait implementation. Rust has some of the best documentation
| of any language (which to be fair it really needs due to all of
| its quirks).
| curun1r wrote:
| The other path that works well is to use Dash/Zeal for
| documentation.
|
| I find dealing with a browser tab to be a bit awkward,
| especially if I'm working on a Rust project using Wasm and
| actively testing in a browser and having to flip between docs
| and my app. Having a dedicated documentation viewing app that I
| can show/hide with a keyboard shortcut just saves a second or
| so every time I need to pull up docs. And the integration with
| IDEs can sometimes mean I don't even have to leave my editor to
| get the answer I need. It also integrates documentation for
| std/core with docs for crates I'm using giving me a single
| search of everything that my Rust code can use. The only
| downside compared to cargo's docs is that it doesn't document
| my own code that I'm working on, but it's much easier to
| remember the details of that code.
|
| The cherry on top is that it isn't limited to Rust. If I'm
| working on something with an FFI dependency, I can have the
| same documentation workflow for C/C++ documentation. If I'm
| working on a Wasm project, I can pull up HTML/CSS documentation
| the exact same way. All my documentation lives in the same
| place under the same keyboard shortcut.
| dwohnitmok wrote:
| FWIW I personally think 5 possible matches is potentially
| already too much if you're a newcomer to a language or even
| just a large project. If you're willing to give up ad-hoc
| polymorphism (a big ask, but possible!) then in theory you
| don't even need to search outside your current file (given
| explicit import syntax, i.e. no wildcard imports).
|
| But ad-hoc polymorphism is just oh so useful.
| masklinn wrote:
| > FWIW I personally think 5 possible matches is potentially
| already too much if you're a newcomer to a language or even
| just a large project.
|
| I'm... not sure what you'd want to happen when there are
| literally 5 methods called write_u16, how is a general-
| purpose search to know which one you're looking for without
| more information? If you want contextual matching... use an
| IDE (or hook rust-analyser into your editor of preference).
|
| (also there are way more than 5 matches in total as there are
| methods like `write_u16_into` which would also match at a
| lower rank).
| dwohnitmok wrote:
| Without ad-hoc polymorphism and with explicit exports the
| correct one must have been disambiguated in import
| statements or must otherwise have been disambiguated at the
| call site via a namespace prefix (negating the need to do
| any searching at all).
|
| So simple ctrl-f in the file would do (or the call site
| would identify it).
| brabel wrote:
| When someone accuses Java of being an IDE-only language, I
| guess I'll use this argument as well because Java also always
| had javadocs which would allow you to see all type hierarchies,
| inherited methods etc which make Java, similar to Rust, hard to
| read without an IDE.
| agumonkey wrote:
| I must have missed something but stdlib's javadoc is so
| horrendous. Yes it has exhaustive list of methods but it's
| devoid of actual programming content. No clear definition
| most of the time, no examples, no diagrams, no properties ..
| I swear on every remaining hair, everytime I have to visit
| these pages I go depressed. It was so much so that I wrote a
| json doclet to try to embed it into a repl to be able to
| experiment with actual objects with a bit of completion
| rather than having to waste precious time.
| halpert wrote:
| What's the easiest way to access the javadocs for the
| transitive dependency closure of your project? I didn't know
| about cargo docs until now, but it seems way more useful than
| javadocs. An good IDE still seems better than both, however.
| jolux wrote:
| I believe Maven supports this, but I don't know if it's
| turnkey like cargo docs.
| TravelPiglet wrote:
| Something like mvn javadoc:javadoc
| -DincludeDependencySources=true perhaps?
| masklinn wrote:
| Last time I looked at a javadoc there was no search field at
| all, to say nothing of a FAYT across your entire set of
| dependencies.
| pjmlp wrote:
| When Java appeared in 1995, my coding environment for it was
| XEmacs and Make.
|
| Visual Age, JBuilder and Visual Cafe still took a while to
| come into being.
| OJFord wrote:
| > While the stdlib sadly remains out of it (long-standing RFC
| 2324[0]), cargo doc will otherwise generate the documentation
| including all dependencies by default.
|
| It's probably mentioned in that issue, but I'm sure I read
| recently they want to crate-ise `std`; at which point
| presumably `cargo doc` would show it like anything else,
| wouldn't even know the difference? (That was even the
| motivation iirc, just for a different part of cargo, not doc.)
| arghwhat wrote:
| Cargo doc is nowhere near as useful as something like go doc,
| where giving a symbol name immediately prints plain text
| documentation in the terminal. Cargo doc is just...
| inconvenient in comparison.
| staticassertion wrote:
| TBH it's really hard to care about the "I need my docs to
| render in a terminal" use case.
| arghwhat wrote:
| It's really hard to care about people who consider waiting
| for a webpage to build, a browser to load and a search to
| be typed as an acceptable solution to documentation access.
| staticassertion wrote:
| That's how 99.99% of the population interacts with
| computers. They load a web page and then view it.
| alexvoda wrote:
| That argument doesn't work both ways. One group has far
| more stringent requirements than the other as evidenced
| by your use of the word "acceptable".
|
| Web documentation is easy to produce and is acceptable to
| many. All other kinds of documentation can also be
| converted into web documentation, therefore you do not
| have to spend extra effort for it.
|
| Terminal documentation is more difficult due to the
| limitations of displaying things in the terminal,
| therefore it requires more effort.
| pjmlp wrote:
| It is 2022, welcome to the future.
| lijogdfljk wrote:
| Fwiw people aren't building the webpage on demand.
| They're doing it on entry to the project, and so it's
| already ready when you want it.
|
| Rust takes forever to build too if you've never built the
| project before, but most people also build that ahead of
| time too. Repeated doc usage and repeated builds/checks
| don't require the "full build"
| edflsafoiewq wrote:
| What about "programmatic access to docs"? HTML pages aren't
| pipeable.
| staticassertion wrote:
| Honestly, I hadn't considered that (and I've upvoted)
| because I just use "search" in the rust docs. But I can
| see some value in grep'ability of docs, even if for me it
| has never really come up.
|
| I suppose it would be nice if rust's docs supported a
| full text search.
| spoiler wrote:
| What use case is that? FWIW, the docs are already
| generated programmatically in the first place, so you
| could access them with a similar approach (not sure how
| difficult that is, so maybe it's unrealistic advice).
|
| Also there's a tool (forgot the name now) that can render
| them in the terminal similar to manpages.
| bogeholm wrote:
| Sure they are, `cat x.html | rg -A 5 -B 5 'some string'`
| masklinn wrote:
| Not only is that not relevant (that two commands have the
| same name doesn't mean they have the same purpose), as far as
| I know you've managed to bring up "go doc" in a context where
| it is useless: if you give a symbol to `go doc`, it's going
| to search that in the current package, which for the purpose
| of TFA is no more helpful than `grep`.
| arghwhat wrote:
| That go doc does not currently handle rust traits, a
| feature that has no equivalent in Go, is a pointless
| observation. Rust doc shows traits together with the class
| they are implemented for, so a "rust doc std::vec::Vec"
| should print them too.
|
| The point is that Rust is behind Go on convenient
| documentation access, which is ironic seeing that Rust
| requires documentation access much more than Go.
|
| go doc also accesses all documentation for packages used in
| a project, making it do quite a lot more than grep.
| masklinn wrote:
| As far as I know you are, once again, completely wrong.
| `go doc` looks up symbols in a single package, which is
| the current package by default. That is what _go doc 's
| own documentation_ states.
| kzrdude wrote:
| Editor integration (LSP) is the way to go, gives you doc for
| the method or type inline in the editor.
| spoiler wrote:
| I guess it comes down to taste and preference, but I much
| prefer cargo doc to go doc. Go doc has a
| "brutalist/minumalist" approach (I understand some people
| prefer that), while cargo doc has a more "humanist" approach
| to the docs. I _want_ all the bells and whistles in the
| browser docs like making it easy to search, read neatly
| formatted /rendered text, links, and syntax highlighting in
| the code snippets.
|
| Edit: tpying is hard
| marcosdumay wrote:
| Looks like Rust is missing something like hoogle. The
| language's types are barely powerful enough for it to add
| value, but it's certainly on the "adds value" side of the
| divide.
| masklinn wrote:
| I would agree.
|
| rustdoc does support a hoogle-like syntax (in a rustdoc page
| click on the question mark next to the search field for
| shortcut and "search tricks"), sadly it's not very good.
|
| Rust does add a few wrinkles due to its "type policy" being
| less regular though e.g. how you handle `self`, as well as
| the various types of references.
|
| For instance let's say you have impl Foo {
| fn foo(&self, p: &Path) -> usize }
|
| Does this match `Foo, Path -> usize` or `Path -> usize`? Or
| both? Or neither (because references). This also outlines a
| second issue which is whether `Deref` should be involved in
| the search (so e.g. should `PathBuf -> usize` find this).
| Ar-Curunir wrote:
| I think rustdoc supports a weak version of type-directed
| search.
___________________________________________________________________
(page generated 2022-01-29 23:02 UTC)