Live data from Hacker News

Rewriting Rust

josephg.com

391–400 of 410 posts

Re: Rewriting Rust

#391

Earlier quoted context omitted.

> As I've noted elsewhere, you can't even safely use `char ` for file names in Windows; it should be `wchar_t ` in order to avoid any encoding problem. Yes, this is true. But I think the overhead of writing that kind of code would not be as enormous as 30k lines or anything in that order. > At the very least it should have checked for TTY in advance. I'm not even interested in terminfo (which should go die). Maybe. I…

> It's an explicit option you must pass. It's often useful to be able to override isatty decisions when you want to embed terminal escapes in output to something like less. But for clear it's debatable. In terms of UX it's just moving the burden to the user, who may not be aware of that problem or even the existence of `-c`. The default matters. > I treat any amount of color as spamming when alternative options exist…

> The default matters.

The default is no clear.

It could be the default is to clear and then I would agree that an isatty check would be necessary. But an isatty check for an explicit option here would be as weird as an isatty check for --color=always for something like ls.

> The bare terminal is too bad for UX

I think it depends on the task and the person. You wouldn't see me doing image editing, 3d modelling, audio mastering, or web browsing in a terminal. But for things which do not suffer for it (a surprising number of tasks) it's strictly better UX than a GUI equivalent.

> emojis

Yes, I dislike these. I especially remember when suddenly my terminal would colour emojis because someone felt it was a good idea to add that to some library as a default. :(

> I think you have been sidetracked then, as the very starting point was about cargo-watch being apparently too large. It's too large partly because of bloated dependencies but also because dependencies are composed instead of being inlined. Your point shifted from no dependencies (or no compositions as an extension) to minimal compositions, at least I feel so. If that's your true point I have no real objection.

Well no, I think you can build a cargo-watch equivalent (with a bit of jank) from disparate utilities running in a shell script and still have fewer total lines.

And sure, the line count is a bit inflated with a lot of things not being compiled into the final binary. But the problem we're discussing here is if it's worth to depend on a bunch of things when all you're using is one or two functions.

As I understand it, whenever doing anything with windows, you pull in hideous quantities of code for wrapping entire swathes of windows. Why can't this be split up more so that if all I want is e.g. file watching that I get just file watching. I know windows has some basic things you inevitably always need, but surely this isn't enough to make up 2M SLOC. I've written C code for windows and yes it's painful but it's not 2M SLOC of boilerplate painful.

Large complex dependency graphs are obviously not a problem for the compiler, it can chug away, remove unnecessary shit, and get you a binary. They're usually not a big problem for binary size (although they can still lead to some inflation). But they are a massive issue for being able to work on the codebase (long compilation times) or review the codebase (huge amounts of complexity, even when code isn't called, you need to rule out that it's not called).

And huge complex dependency graphs where you're doing something relatively trivial (and honestly file watching isn't re-implementing cat but it's not a web browser or an OS) should just be discouraged.

We both agree that you can get this done in under 50k lines. That's much easier to manage from an auditing point of view than 4M lines of code, even if 3.9M lines end up compiled out.

Re: Rewriting Rust

#392

Earlier quoted context omitted.

> If you want an edge over the people who are writing RFCs, don't write an RFC. Write a complete, production-ready implementation of your idea, with documentation and test cases, which can be cleanly merged into the tree. Please by all means provide an implementation, but do write the RFC first . (Or in some cases smaller processes, such as the ACP process for a small standard-library addition.) Otherwise you may end…

I've noticed that having even a minimal implementation helps a lot to inform the RFC: some details are non-obvious until you are either forced to clamp down behavior or have tried to use the feature. The RFC discussion doesn't always surface these. I've also been thinking that we should go over our stabilized RFCs and add an appendix to all of them documenting how the current implementation diverges from the original…

I don't understand why one-implementation language project would need RFCs, other than to inflate their sense of self-importance.

RFCs are useful in a multi-vendor situation. They are permanent documents the constitute a kind of standard. For instance internet RFCs, or Scheme SRFIs.

If the rest RFC is something you jettison once it implemented, then it's actually something that belongs in a bug database as a feature request, which can be marked closed when done (after which nobody ever looks at it again except as a historic reference). Someone implementing the same thing in a new implementation would not be looking at it, but at the real documentation (which was written as part of implementing the ticket, and maintained afterward).

Re: Rewriting Rust

#393

Earlier quoted context omitted.

Languages using pure versions of the pi calculus support concurrency without any of the usual headaches. Async is a great example of this problem. It is way more cumbersome in Rust then it could be, in a different universe where Rust concurrency made different choices.

> A properly designed feature shouldn’t require an entire blog post, let alone multiple, to understand. After reading though the wiki about pi calculus and looking up the few languages that support it, I would be pretty shocked to find a language that adds a pi calculus feature wouldn't need several blog posts explaining what it is and how to understand it.

People seem to get how goroutines work without too much effort. (Go's concurrency model is the pi calculus).

Re: Rewriting Rust

#394

Earlier quoted context omitted.

> A properly designed feature shouldn’t require an entire blog post, let alone multiple, to understand. After reading though the wiki about pi calculus and looking up the few languages that support it, I would be pretty shocked to find a language that adds a pi calculus feature wouldn't need several blog posts explaining what it is and how to understand it.

People seem to get how goroutines work without too much effort. (Go's concurrency model is the pi calculus).

It's a stretch to argue that Go's concurrency model is pi calculus. Go supports lexical closures, and even the initial body of a goroutine can close over variables in the parent scope.

Go's concurrency model is fundamentally lexical closures[1] and threading, with channels layered on top. Lexical closing is, afterall, how channels are initially "passed" to a goroutine, and for better or worse it's not actually a common pattern to pass channels through channels. And but for Go hiding some of the lower-level facilities needed for thread scheduling, you could fully implement channels atop Go's lexical closures and threading.

I think the similarity to pi calculus is mostly coincidence, or perhaps convergent evolution. The choice not to make goroutines referencible as objects, and the fact channels can be communicated over channels, makes for a superficial similarity. But the former--lack of threads as first-class objects--comes from the fact that though the concurrency model is obviously threading, Go designers didn't want people to focus on threads, per se; and also it conveniently sides-steps contentious issues like thread cancellation (though it made synchronous coroutines problematic to implement as the GC has no way to know when a coroutine has been abandoned). And the ability to pass channels through channels is just consistent design--any object can be passed through a channel.

[1] Shared reference--non-copying, non-moving--closures. Though Go's motto is "share memory by communicating" as opposed to "communicate by sharing memory", Go comes to the former by way of the latter.

Re: Rewriting Rust

#395
post #394

Earlier quoted context omitted.

People seem to get how goroutines work without too much effort. (Go's concurrency model is the pi calculus).

It's a stretch to argue that Go's concurrency model is pi calculus. Go supports lexical closures, and even the initial body of a goroutine can close over variables in the parent scope. Go's concurrency model is fundamentally lexical closures[1] and threading, with channels layered on top. Lexical closing is, afterall, how channels are initially "passed" to a goroutine, and for better or worse it's not actually a comm…

Just to add, Go was inspired by Hoare's CSP paper [1]. Hoare came up with the ideas of CSP separately from Milner [2] even though they have some cross over concepts. The two collaborated later on, but really had somewhat independent approaches to concurrency.

To respond to the OP. Go's concurrency model absolutely has multiple blogs written about it and explaining how it works. It's actually a little funny OP was thinking Go was based on pi calculus when it was actually based on CSP. That goes to my original disagreement. Good features need explanation and they don't become "bad" just because they require blog posts.

[1] https://go.dev/blog/codelab-share

[2] https://en.wikipedia.org/wiki/Actor_model_and_process_calcul...

Re: Rewriting Rust

#396

Earlier quoted context omitted.

I've noticed that having even a minimal implementation helps a lot to inform the RFC: some details are non-obvious until you are either forced to clamp down behavior or have tried to use the feature. The RFC discussion doesn't always surface these. I've also been thinking that we should go over our stabilized RFCs and add an appendix to all of them documenting how the current implementation diverges from the original…

I don't understand why one-implementation language project would need RFCs, other than to inflate their sense of self-importance. RFCs are useful in a multi-vendor situation. They are permanent documents the constitute a kind of standard. For instance internet RFCs, or Scheme SRFIs. If the rest RFC is something you jettison once it implemented, then it's actually something that belongs in a bug database as a feature…

> I don't understand why one-implementation language project would need RFCs

For multiple reasons. First, because it's not actually obvious from a PR what the overall design and big picture is. And second, because we want to decide about that design and big picture before someone does too much implementation work, lest that work need redoing because the design changed (or lest that work go to waste because we rejected the RFC).

Re: Rewriting Rust

#397

Earlier quoted context omitted.

These features are slow to be accepted for good reasons, not just out of some sort of pique. For example, the design space around combining `if let` pattern matching with boolean expressions has a lot of fraught issues around the scoping of the bindings declared in the pattern. This becomes especially complex when you consider the `||` operator. The obvious examples you want to use work fine, but the feature needs to…

> The obvious examples you want to use work fine, but the feature needs to be designed in such a way that the language remains internally consistent and works in all edge cases. True. How long should that process take? A month? A year? Two years? I ask because this feature has been talked about since I started using rust - which (I just checked) was at the start of 2017. Thats nearly 8 years ago now. 6 years ago this…

> 6 years ago this RFC was written: https://rust-lang.github.io/rfcs/2497-if-let-chains.html - which fixes my issues. But it still hasn't shipped.

As someone who has worked a lot to get if let chains stabilized (but so far not achieved the goal), there is surprisingly few blockers: only an ICE. But the ICE fix requires doing some breaking changes, so it's being phased in as part of the 2024 edition. The alternative to doing breaking changes would be to make if let chains different from if let, which wouldn't be nice.

Hopefully we'll have stable if let chains soon-ish. But note that nowadays on Rust, it's mostly volunteers working on the language, so things might not be as fast any more.

In any case, writing a language from scratch is going to be ten times more involved than targeting nightly Rust where if let chains are available.

Re: Rewriting Rust

#398

Earlier quoted context omitted.

Yes, but that's not unique to Maven because virtually all software repositories have such policies. If that's about the required amount of "moderation" you claim, I don't see how Maven can even be considered better than others.

Or maybe you don't want to. If that's the hill you want to die on, good luck.

Maybe you wanted to say that policies do not imply actual "moderation". But that is demonstrably false, there are documented cases where crates.io removed packages solely because they were malicious and all those cases happened as soon as possible for crates.io. So Maven Central has to do something more in order to be ever considered better than crates.io, but I have no idea---it accepts any well-formed uploads after all. Do elaborate on that.

Re: Rewriting Rust

#399

Earlier quoted context omitted.

> It's an explicit option you must pass. It's often useful to be able to override isatty decisions when you want to embed terminal escapes in output to something like less. But for clear it's debatable. In terms of UX it's just moving the burden to the user, who may not be aware of that problem or even the existence of `-c`. The default matters. > I treat any amount of color as spamming when alternative options exist…

> The default matters. The default is no clear. It could be the default is to clear and then I would agree that an isatty check would be necessary. But an isatty check for an explicit option here would be as weird as an isatty check for --color=always for something like ls. > The bare terminal is too bad for UX I think it depends on the task and the person. You wouldn't see me doing image editing, 3d modelling, audio…

Yeah, I think we are largely on the same page. The only thing I want to correct at this point is that Rust has no OS support yet, so any "system" library will necessarily come out as a third-party crate. Including the `windows` crate in this context is roughly equivalent to including the fully expanded lines of `#include `, which is known to be so massive that it also has a recommended macro `WIN32_LEAN_AND_MEAN` to skip its large portion on typical uses, but that should still count according to you I think? [1] Thankfully for auditors, this crate does come from Microsoft so that gives a basic level of authority, but I can understand if you are still unsatisfied about the crate and that was why I stressed the original figure was very off.

As noted in my other comments, I'm very conscious about this problem and tend to avoid excess dependencies when I can do them myself with a bit of work. I even don't use iterutils (which is a popular convenience library that amends `Iterator`), because I normally want a few of them (`Iterutils::format` is one of things I really miss) and I can write them without making other aspects worse. But I'm also in the minority, I tend to depend on "big" dependencies that are not sensible to write them myself while others are much more liberal, and I do think that cargo-watch is already optimal in the number of such dependencies. More responsibilities and challenges remain for library authors, whose decisions directly contribute to the problem.

[1] I haven't actually checked the number of lines under this assumption, but I recall that it exceeds at least 100K lines of code, and probably much larger.

Re: Rewriting Rust

#400
post #316

Earlier quoted context omitted.

Huh? > It's throwing the baby and bathwater into lava. Is it really so controversial to want to be able to limit the access that utility crates like humansize or serde have to make arbitrary syscalls on my computer? Seems to me like we could get pretty far with just compile-time checks - and that would have no impact whatsoever on the compiled code (or its performance). I don't understand your criticism.

I thought you wanted to prevent transitive dependencies. For sandboxing crates, as JoshTriplett said it's another can of worms.

By default, yes. But it probably makes sense to let people whitelist specific crates in their dependency tree. Crates like std and tokio, or blas libraries that make heavy use of simd. Stuff like that.
Post reply on HN