[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)