For disclosure, Amplify is ERSC's lead investors, and I'm one of the cofounders of ERSC.
HN user
thramp
ersc.io; davidbarsky.com.
A couple of gentle corrections:
The document didn't mention a lawsuit and I was just responding to the above comment with only the context of the postmortem and pointing out that this particular article didn't claim anything illegal happened.
You are correct that they did not make any claims, but the article did insinuate illegal behavior on the part of André and Samuel by selectively juxtaposing facts to imply wrongdoing without ever directly stating or saying that their behavior was illegal. For example:
1. André's first commit on RV is placed on the same bullet point as the Ruby Central-funded maintainer offsite, which implies Ruby Central's travel money subsidized a competing project's creation. 2. The `rubygems-github-backup` access token covering "all repos, including private repos" is introduced in the same timeline section as RV development, without any allegation it was used for RV. 3. The "Incident Lessons" section recommends adding an "Outside Business Activities" declaration policy, which only reads as a "lesson" if André's undisclosed side project is being framed as the problem in need of remediation. 4. The report states André "had intimate knowledge of the foundation roadmap" and "did not tell anyone in Ruby Central about this work until it launched". This frames nondisclosure of a lawful side project as a transgression. However, Ruby Central passed on this work, and even if they didn't, André has no obligation to tell Ruby Central about his work! 5. André's proposal to have his consultancy analyze RubyGems.org download logs is presented alongside an OSS Committee member raising PII and "reputational risk" concerns, casting a perfectly sensible rejected business proposal as something suspect.
By my count, Ruby Central makes roughly 10 insinuations throughout the report, but not once do they actually claim any of these constitute a transgression.
I think that topic is extremely complicated (e.g. I am not so sure moonlighting for a competitor while an employee is necessarily protected in California...)
California is actually quite clear on this! Bus. & Prof. Code § 16600 voids non-compete agreements, and California courts have consistently read it broadly enough that working on a competing project during employment is protected. The line is whether you used your employer's proprietary information or resources to do it, not whether you competed. The report does not allege that Samuel or André used Ruby Central's proprietary information, and given how thoroughly they documented everything else, I'd expect them to have said so if they had evidence of it. Ruby Central is insinuating that working on RV in the first place is a problem, not that they crossed any legal or contractual line.
This is a disappointing look for Ruby Central. I have to get back to work, but their retroactive framing that Andre and Samuel's work on RV justified Ruby Central's subsequent actions is contradicted by their own admissions.
By their own admission, André is a contractor to Ruby Central. Contractors, especially under California law, have no contractual obligation of confidentiality to the other party unless there's a pre-existing agreement in place. They later admit in this "incident report" that they didn't have any legal agreements with André in place, so there's no basis for claiming André couldn't work on rv.
Samuel was an employee, not a contractor, but [California Bus. & Prof. Code § 16600](https://leginfo.legislature.ca.gov/faces/codes_displaySectio....) voids non-compete agreements—so even as an employee, he had every right to work on a competing project. There's no indication that he used Ruby Central's proprietary information to do so, and the report doesn't allege that. I have little doubt that if Samuel or André used proprietary information to develop rv, they would have already presented evidence of that.
Independent of the legalese, a "uv but for ruby" is a blindingly obvious thing to do, and Ruby Central doesn't get to lick the cookie and get upset when an independent contractor—Ruby Central's own characterization—does a thing they didn't fund.
My sourcing on this is that I run a 10-person business with employees in California. I'm not a lawyer, but I looked over enough of this paperwork that I feel confident opining on an internet forum.
One of the rust-analyzer co-maintainers (Chayim Friedman) already rewrote it, but we can’t integrate it yet, as about 40 assists (the little lightbulbs?) still rely on mutation. If you want something Rowan-like, I think syntree and Biome’s rowan fork are good options to look into.
(Hi, I’m on the rust-analyzer team, but I’ve been less active for reasons that are clear in my bio.)
Language servers are powerful because they can hook into the language’s runtime and compiler toolchain to get semantically correct answers to user queries. For example, suppose you have two versions of a pop function, one imported from a stack library, and another from a heap library. If you use a tool like the dumb-jump package in Emacs and you use it to jump to the definition for a call to pop, it might get confused as to where to go because it’s not sure what module is in scope at the point. A language server, on the other hand, should have access to this information and would not get confused.
You are correct that a language server will generally provide correct navigation/autocomplete, but a language server doesn’t necessarily need to hook into an existing compiler: a language server might be a latency-sensitive re-implementation of an existing compiler toolchain (rust-analyzer is the one I’m most familiar with, but the recent crop of new language servers tend to take this direction if the language’s compiler isn’t query-oriented).
It is possible to use the language server for syntax highlighting. I am not aware of any particularly strong reasons why one would want to (or not want to) do this.
Since I spend a lot of time writing Rust, I’ll use Rust as an example: you can highlight a binding if it’s mutable or style an enum/struct differently. It’s one of those small things that makes a big impact once you get used to it: editors without semantic syntax highlighting (as it is called in the LSP specification) feel like they’re naked to me.
We (the rust-analyzer team) have been aware of the slowness in Rowan for a while, but other things always took priority. Beyond allocation, Rowan is structured internally as a doubly-linked list to support mutating trees, but: 1. Mutation isn’t really worth it; the API isn’t user-friendly. 2. In most cases, it’s straight up faster to create a new parse tree and replace the existing one. Cache effects of a linked list vs. an arena!
In fairness, I don’t think we predicted just how large L1/L2 caches would get over the coming years.
I’d second Rain’s reply, but having gone from git to sapling to jujutsu, I feel like the jump from sapling to jujutsu was as big as the jump from git to sapling, in terms of “oh, this is a way nicer workflow”. I really like and miss Sapling’s interactive smart log, but I found jj’s conceptual simplicity to be more compelling than ISL. That said, VisualJJ and Jujutsu Kaizen (both listed on https://jj-vcs.github.io/jj/latest/community_tools/) might give you the ISL-style experience you’re looking for.
(disclosure: I started a jj company but I don’t have anything to sell yet.)
Are there "central concepts" in the Jujutsu design?
I think a central concept in jj is that everything is a commit: there’s no staging index, stashes, or unstaged files, only commits. This has a few pretty neat implications: - changes are automatically to recorded to the current commit. - commits are very cheap to create. - as others have already said, rebases (and history manipulation in general!) are way cheaper than in git. It helps that jj as a whole is oriented around manipulating and rewriting commits. Stacked diffs fall out of this model for free. - Since everything is now a commit, merge/rebase conflicts aren’t anything special anymore because a commit can simply be marked as having “a conflict” and you, as the user, can simply resolve the conflict at your own leisure. While I’m sure you know already know thus, I’d rather make subtext text: in git and mercurial, you’d need to resolve the conflict as it got materialized or abort the rebase entirely. - because everything is a commit, jj has a universal undo button that falls out effectively, for free: `jj undo`. It feels so incredibly powerful to have a safety net!
All other Git UIs I've used have been severely lacking, but Magit has made me significantly more productive with Git, and has convinced me of the "magic of git".
I can’t speak to this personally, but I’ve had friends who are magit users tell me that jj isn’t a big enough improvement (on a day-to-day, not conceptual, basis) over magit to switch at this time. It’d be really cool to have a magit-but-for-jj, but I don’t think anyone has written one yet.
(I work on rust-analyzer)
We don't share the query infrastructure in rust-analyzer, but rust-analyzer is a query-driven system. We use Salsa (https://github.com/salsa-rs/salsa/), which is strongly inspired by rustc's query system, down to the underlying red/green algorithm (https://rustc-dev-guide.rust-lang.org/queries/incremental-co...), hence the name: Salsa.
Oh, that’s super clever integration with tracing. Feel free to send us a PR; we’ll link to this as a related project in the docs!
That's a great point about allocation/memory management. As an example, rust-analyzer needs to free memory, but rustc's `free` is simply `std::process::exit`.
If I remember correctly, the new trait solver's interner is a trait (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_...) that should allow rust-analyzer's implementation of it to free memory over time and not OOM people's machines.
I think the future definitely lies in compilers written to be “incremental first,” but this requires a major shift in mindset, as well as accepting significantly worse performance for batch compilation. It also further complicates the already very complicated task of writing compilers, especially for first-time language designers.
I'm in strong agreement with you, but I will say: I've really grown to love query-based approaches to compiler-shaped problems. Makes some really tricky cache/state issues go away.
Are they? I feel like intellisense is largely a subset of what a compiler already has to do.
They are distinct! Well, not just intellisense, but pretty much everything. I'll paraphrase this blog post, but the best way to think about think about the difference between a traditional compiler and an IDE is that compilers are top-down (e.g, you start compiling a program from a compilation unit's entrypoint, a `lib.rs` or `main.rs` in Rust), but IDEs are cursor-centric—they're trying to compile/analyze the minimal amount of code necessary to understand the program. After all, the best way to go fast is to avoid unnecessary work!
If you wanted to argue that intellisense is a subset of compiling and it can be done faster and more efficiently I could buy that argument. But if you’re going to declare the tasks are at odds with one another I’d love to hear specific details!
Beyond the philosophical/architectural difference I mentioned above, compilers typically have a one-way mapping between syntax and mapping, but to support things like refactors or assists, you often need to do the opposite: go from semantics to syntax. For instance, if you want to refactor from struct to an enum, you often need to find all instances of said struct, make the semantic change, then construct the new syntax tree from the semantics. For simple transformations like a struct to an enum, a purely syntax-based based approach might work (albeit, at the cost of accuracy if you have two structs with same name), but you start to run into issues when you consider traits, interfaces (for example: think about how a type implements an interface in Go!), or generics.
It doesn't really make sense for a compiler to support above use cases, but they're are _foundational_ to an IDE. However, if a compiler is query-centric (as rustc is), then it's pretty feasible for rustc and rust-analyzer to share, for instance, the trait solver or the borrow checker (we're planning/scoping work on the former right now).
I've responded on reddit before (https://www.reddit.com/r/rust/comments/1eqqwa7/comment/lhwwn...), but I'll restate and cover some other things here.
I have a maybe wrong and bad opinion that LSP is actually at the wrong level. Right now every language needs to implement a from scratch implementation of their LSP server. These implementations are HUGE and take YEARS to develop. rust-analyzer is over 365,000 lines of code. And every language has their own massive, independent implementation.
rust-analyzer a big codebase, but it's also less problematic than the raw numbers would make you think. rust-analyzer has a bunch of advanced functionality (term search https://github.com/rust-lang/rust-analyzer/pull/16092 and refactors), assists (nearly 20% of rust-analyzer!) and tests.
I think there should be a common Intellisense Database file format for providing LSP or LSP-like capabilities. Ok sure there will still be per-language work to be done to implement the IDB format.
I think you might be describing formats like (https://code.visualstudio.com/blogs/2019/02/19/lsif) and SCIP (https://github.com/sourcegraph/scip). I personally like SCIP a bit more LSIF because SCIP's design makes it substantially easier to incrementally update a large index. We use SCIP with Glean (https://glean.software/) at work; it's pretty nice.
But you'd get like 95% of the implementation for free for any LLVM language. And generating a common IDB format should be a lot simpler than implementing a kajillion LSP protocols.
I wouldn't say 95%. SCIP/LSIF can do the job for navigation, but that's only a subset of what you want from an IDE. For example: - Intellisense/autocomplete is extremely latency sensitive where milliseconds count. If you have features like Rust/Haskell's traits/typeclasses that allow writing blanket implementations like `impl<T> SomeTrait for T`, it's often faster to try to solve that trait bound on-the-fly than storing/persisting that data. - It'd be nice to handle features like refactors/assists/lightbulbs. That's going to result in a bunch of de novo code needs to exist outside of a standard compiler, not counting all the supporting infrastructure.
My dream world has a support file that contains: full debug symbols, full source code, and full intellisense data.
Rust tried something similar in 2017 with the Rust Language Server (RLS, https://github.com/rust-lang/rls). It worked, but most people found it too slow because it was invoking a batch compiler on every keystroke.
It's not a ridiculous argument! Not naming everything means that you can reserve naming things for when it actually makes a difference.
the problem with this approaches like these that it requires blocking the runtime: https://github.com/jaboatman/tokio-scoped/blob/master/src/li....
fehler isn't deprecated, but _I_ did deprecate the similarly named https://github.com/rust-lang-nursery/failure/ with withoutboat's blessing.
failure proceeded fehler by several years.
Otherwise, it is another "rewrite it in rust" post which is yet to materialise into a real project.
I'm not sure you can reasonably said that "it is another 'rewrite it in rust' post..." if it's coming from a QEMU maintainer.
Besides, before starting a large engineering project like this, it's worthwhile to write a high-level proposal _then_ write code. Saves you a lot of wasted effort!
This is based on her presentation and some dinner conversation at HPTS 2019, so I don't know if there's actually a paper I can point to.
Thanks for the explanation! I just found http://www.hpts.ws/papers/2019/howard.pdf; I'm reading through it now :)
Thank you! Could I... hang on, just let me grab reviewer #1 quickly, I'd like them to hear this. ;-)
Do as you please with my praise!
I think there are open possibilities in making leaderless single-round-trip consensus systems for log-oriented FSMs, which is what pretty much everyone WANTS.
Woah, that's wild. Are there any pre-prints/papers/talks that you can link to on this subject? I'd _love_ to read this.
I'm also excited about my own research with Elle, but we're still working on getting that through peer review, haha. ;-)
I read over bits of Elle; the documentation in it is absolutely top-notch. You and Peter Alvaro knocked it out of the park!
I like the retrospective of this post! The "what ifs" that could've been taken are fun to think about.
I think I might take a step further than this post does—I think some sort of Racket/Rust-style macro system should be implemented in JS, which means that that means something like JSX could be implemented as a library. There's already been _some_ work on this in JavaScript (SweetJS https://www.sweetjs.org/), but making it first-class would be a big win, IMO.
I know that there are common objects to macros as being too complicated/having poor misuse resistence, but it can (and has!) been implemented and used pretty judiciously all the non-C/C++ languages I've used.
I think this might be caused by autosave being enabled in VSCode, but this is just idle speculation.
I was _just_ thinking of https://latacora.micro.blog/2020/03/12/the-soc-starting.html and https://sso.tax/ as I was writing my comment!
This is a great change! One request: I wish that SAML was not an enterprise feature. SAML ought be a basic security feature like 2FA—it's especially valuable for open source teams who might use a mixture of services, and an easily accessible and cheap SSO solution would go a long way in raising the security bar for all teams, not just open source teams.
The reason the `http` crate has a "bespoke hashmap implementation" is not because "performance", it's because _HTTP headers call for different behavior than `std::collections::HashMap`_. Some of the differences in behavior include:
- The map needs to be a multimap.
- Insertion order needs to be preserved.
While `std::collections::HashMap` is an excellent HashMap, it is not a good fit for HTTP headers.
How so?
Author here—while many systems are performance-sensitive, many others aren't. Personally, I don't enjoy writing Python at work due to its lack of misuse resistance more than any concerns about performance (although a large-enough project will eventually care about performance _at some point_), but I have little issue writing smaller Python programs that only _I_ maintain.
Yep! Thank you so much! I really need to update the documentation, but I think `cross` (https://github.com/rust-embedded/cross), a drop-in cargo replacement, is the probably the best available solution for building musl-based binaries.
Rust AWS Lambda Runtime author here: while the Rust runtime tends to beat all other runtimes, Go is _very_ close in terms of startup times.
I'm happy to have helped on the AWS side!
Nope, I'm in Boston, but I did the attend the July Rust meetup at Microsoft. You?