<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Hacker News: awused</title><link>https://news.ycombinator.com/user?id=awused</link><description>Hacker News RSS</description><docs>https://hnrss.org/</docs><generator>hnrss v2.1.1</generator><lastBuildDate>Tue, 28 Apr 2026 17:53:32 +0000</lastBuildDate><atom:link href="https://hnrss.org/user?id=awused" rel="self" type="application/rss+xml"></atom:link><item><title><![CDATA[New comment by awused in "Was Rust Worth It?"]]></title><description><![CDATA[
<p>><i>It's the problem with classical stage-oriented compilers. A compiler designed for diagnostics from the beginning</i><p>I'm not sure any compiler, even one "designed for diagnostics," can gather the "necessary metadata" from inside my brain based on my original intentions. If the compiler could unambiguously interpret what I meant to write, it wouldn't have needed to fail with a compilation error in the first place. Whenever I see something like "perhaps" or "maybe" in a compilation error, the information just didn't exist anywhere the compiler could possibly get to, and it's just a suggestion based on common mistakes.</p>
]]></description><pubDate>Thu, 26 Oct 2023 17:55:27 +0000</pubDate><link>https://news.ycombinator.com/item?id=38029257</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=38029257</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=38029257</guid></item><item><title><![CDATA[New comment by awused in "Was Rust Worth It?"]]></title><description><![CDATA[
<p>Honestly I found myself coding very much the same way in Rust as I did in Python and Go, which were my go-to hobby languages before. But instead of "this lock guards these fields" comments, the type system handles it. Ownership as a concept is something you need to follow in any language, otherwise you get problems like iterator invalidation, so it really shouldn't require an up-front architectural planning phase. Even for cyclic graphs, the biggest choice is whether you allow yourself to use a bit of unsafe for ergonomics or not.<p>Having a robust type system actually makes refactors a lot easier, so I have less up-front planning with Rust. My personal projects tend to creep up in scope over time, especially since I'm almost always doing something new in a domain I've not worked in. Whenever I've decided to change or redo a core design decision in Python or Go, it has always been a massive pain and usually "ends" with me finding edge cases in runtime crashes days or weeks later. When I've changed my mind in Rust it has, generally, ended once I get it building, and a few times I've had simple crashes from not dropping RefCell Refs.</p>
]]></description><pubDate>Thu, 26 Oct 2023 17:40:59 +0000</pubDate><link>https://news.ycombinator.com/item?id=38029037</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=38029037</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=38029037</guid></item><item><title><![CDATA[New comment by awused in "Was Rust Worth It?"]]></title><description><![CDATA[
<p>Lifetimes and borrowing are very much a correctness thing and aren't just for tracking when memory is freed. While you won't have use-after-free issues in a GCed language, you will still have all the other problems of concurrent modification (data races) that they prevent. This is true even in single-threaded code, with problems like iterator invalidation.</p>
]]></description><pubDate>Thu, 26 Oct 2023 17:26:16 +0000</pubDate><link>https://news.ycombinator.com/item?id=38028813</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=38028813</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=38028813</guid></item><item><title><![CDATA[New comment by awused in "Maybe Rust isn’t a good tool for massively concurrent, userspace software"]]></title><description><![CDATA[
<p>Honestly I assumed you had read the article and were just confused about how tokio was pretending to have preemption. Now you reveal you hadn't read the article so now I'm confused about you in general, it seems like a waste of time. But I'm glad you're at least on the same page now, about how checking if something is ready and yielding to the runtime are separate things.</p>
]]></description><pubDate>Sat, 09 Sep 2023 08:59:22 +0000</pubDate><link>https://news.ycombinator.com/item?id=37443469</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37443469</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37443469</guid></item><item><title><![CDATA[New comment by awused in "Maybe Rust isn’t a good tool for massively concurrent, userspace software"]]></title><description><![CDATA[
<p>Actually, no, I misread it trying to make sense of what you were posting so this post is edited.<p>This is just mundane non-blocking sockets. If the socket never needs to block, it won't yield. Why go through epoll/uring unless it returns EWOULDBLOCK?</p>
]]></description><pubDate>Sat, 09 Sep 2023 08:25:17 +0000</pubDate><link>https://news.ycombinator.com/item?id=37443317</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37443317</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37443317</guid></item><item><title><![CDATA[New comment by awused in "Maybe Rust isn’t a good tool for massively concurrent, userspace software"]]></title><description><![CDATA[
<p>Are you sure about that?<p>><i>Rust embraces abstractions because Rust abstractions are zero-cost. So you can liberally create them and use them without paying a runtime cost.</i><p>><i>you never need to do a cost-benefit analysis in your head, abstractions are just always a good idea in Rust</i><p>Again though, and ignoring that, "zero-cost abstraction" can be very narrow and context specific, so you really don't need to go out of your way to find "costly" abstractions in Rust. As an example, if you have any uses of Rc that don't use weak references, then Rc is not zero-cost for those uses. This is rarely something to bother about, but rarely is not never, and it's going to be more common the more abstractions you roll yourself.</p>
]]></description><pubDate>Sat, 09 Sep 2023 08:15:05 +0000</pubDate><link>https://news.ycombinator.com/item?id=37443270</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37443270</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37443270</guid></item><item><title><![CDATA[New comment by awused in "Maybe Rust isn’t a good tool for massively concurrent, userspace software"]]></title><description><![CDATA[
<p>You're confusing IO not happening because it's not needed with IO never happening. Just because a method can perform IO doesn't mean it actually does every time you call it. If I call async_read(N) for the next N bytes, that isn't necessarily going to touch the IO driver. If your task can make progress without polling, it doesn't need to poll.<p>>I'm not familiar with tokio so I did not know that it maintained buffers in userspace<p>Most async runtimes are going to do buffering on some level, for efficiency if nothing else. It's not strictly required but you've had an unusual experience if you've never seen buffering.<p>>filled them before the user called read()<p>Where did you get this idea? Since you seem to be quick to accuse others of it, this does seem like trolling. At the very least it's completely out of nowhere.<p>>it could still have read() yield and return the contents of the buffer.<p>If I call a read_one_byte, read_line, or read(N) method and it returns past the end of the requested content that would be a problem.<p>>I assumed that users would issue reads of like megabytes at a time and usually receive less.<p>Reading from a channel is the other easy example, if files were hard to follow. The channel read might implemented as a quick atomic check to see if something is available and consume it, only yielding to the runtime if it needs to wait. If a producer on the other end is producing things faster than the consumer can consume them, the consuming task will never yield. You can implement a channel read method that always yields, but again, that'd be slow.<p>>The proposal is obviously not to yield 1 million times before returning a 1 meg buffer, is this trolling<p>No, giving a illustrative example is not trolling, even if I kept the numbers simple to make it easy to follow. But your flailing about with the idea of requiring gigabyte sized buffers probably is.</p>
]]></description><pubDate>Sat, 09 Sep 2023 08:00:08 +0000</pubDate><link>https://news.ycombinator.com/item?id=37443214</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37443214</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37443214</guid></item><item><title><![CDATA[New comment by awused in "Maybe Rust isn’t a good tool for massively concurrent, userspace software"]]></title><description><![CDATA[
<p>>This sort of design solves the problem for any case of "My task that is performing I/O through my runtime is starving my other tasks."<p>Yeah, there's your misunderstanding, you've got it backwards. The problem being described occurs when I/O isn't happening because it isn't needed, there isn't a problem when I/O does need to happen.<p>Think of buffered reading of a file, maybe a small one that fully fits into the buffer, and reading it one byte at a time. Reading the first byte will block and go through epoll/io_uring/kqueue to fill the buffer and other tasks can run, but subsequent calls won't and they can return immediately without ever needing to touch the poller. Or maybe it's waiting on a channel in a loop, but the producer of that channel pushed more content onto it before the consumer was done so no blocking is needed.<p>You can solve this by never writing tasks that can take "a lot" of time, or "continue", whatever that means, but that's pretty inefficient in its own right. If my theoretical file reading task is explicitly yielding to the runtime on every byte by calling yield(), it is going to be very slow. You're not going to go through io_uring for every single byte of a file individually when running "while next_byte = async_read_next_byte(file) {}" code in any language if you have heap memory available to buffer it.</p>
]]></description><pubDate>Sat, 09 Sep 2023 06:15:39 +0000</pubDate><link>https://news.ycombinator.com/item?id=37442735</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37442735</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37442735</guid></item><item><title><![CDATA[New comment by awused in "Maybe Rust isn’t a good tool for massively concurrent, userspace software"]]></title><description><![CDATA[
<p>>Trying to solve the problem by frequently invoking signal handlers will also show in your latency distribution!<p>So just like any other kind of scheduling? "Frequently" is also very subjective, and there are tradeoffs between throughput, latency, and especially tail latency. You can improve throughput and minimum latency by never preempting tasks, but it's bad for average, median, and tail latency when longer tasks starve others, otherwise SCHED_FIFO would be the default for Linux.<p>>I read the blog about this situation at <a href="https://tokio.rs/blog/2020-04-preemption" rel="nofollow noreferrer">https://tokio.rs/blog/2020-04-preemption</a> which is equally baffling<p>You've misunderstood the problem somehow. There is definitely nothing about tokio (which uses epoll on Linux and can use io_uring) not responding in there. io_uring and epoll have nothing to do with it and can't avoid the problem: the problem is with code that can make progress and doesn't need to poll for anything. The problem isn't unique to Rust either, and it's going to exist in any cooperative multitasking system: if you rely on tasks to yield by themselves, some won't.</p>
]]></description><pubDate>Fri, 08 Sep 2023 21:16:11 +0000</pubDate><link>https://news.ycombinator.com/item?id=37439543</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37439543</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37439543</guid></item><item><title><![CDATA[New comment by awused in "Maybe Rust isn’t a good tool for massively concurrent, userspace software"]]></title><description><![CDATA[
<p>The way you used it in your parent comment didn't make it clear that you were using it properly, hence my clarification. I'm honestly still not sure you've got it right, because Rust abstractions, in general, are not zero-cost. Rust has some zero-cost abstractions in the standard library and Rust has made choices, like monomorphization for generics, that make writing zero-cost abstractions easier and more common in the ecosystem. But there's nothing in the language or compiler that forces all abstractions written in Rust to be free of extra runtime costs.</p>
]]></description><pubDate>Fri, 08 Sep 2023 20:41:57 +0000</pubDate><link>https://news.ycombinator.com/item?id=37439134</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37439134</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37439134</guid></item><item><title><![CDATA[New comment by awused in "Maybe Rust isn’t a good tool for massively concurrent, userspace software"]]></title><description><![CDATA[
<p>"Zero-cost abstractions" can be a confusing term and it is often misunderstood, but it has a precise meaning. Zero-cost abstractions doesn't mean that using them has no runtime cost, just that the abstraction itself causes no additional runtime cost.<p>These can also be quite narrow: Rc is a zero-cost abstraction for refcounting with both strong and weak references allocated with the object on the heap. You cannot implement something the same more efficiently, but you can implement something different but similar that is both faster and lighter than Rc. You can make a CheapRc that only has strong counts, and that will be both lighter and faster by a tiny amount, or a SeparateRc that stores the counts separately on the heap, which offers cheaper conversions to/from Rc.</p>
]]></description><pubDate>Fri, 08 Sep 2023 20:19:05 +0000</pubDate><link>https://news.ycombinator.com/item?id=37438871</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37438871</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37438871</guid></item><item><title><![CDATA[New comment by awused in "Maybe Rust isn’t a good tool for massively concurrent, userspace software"]]></title><description><![CDATA[
<p>>but Tokio forces all of your async functions to be multi thread safe<p>While there are other runtimes that are always single-threaded, you can do it with tokio too. You can use a single threaded tokio runtimes and !Send tasks with LocalSet and spawn_local. There are a few rough edges, and the runtime internally uses atomics where a from-the-ground-up single threaded runtime wouldn't need them, but it works perfectly fine and I use single threaded tokio event loops in my programs because the tokio ecosystem is broader.</p>
]]></description><pubDate>Fri, 08 Sep 2023 18:40:14 +0000</pubDate><link>https://news.ycombinator.com/item?id=37437621</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37437621</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37437621</guid></item><item><title><![CDATA[New comment by awused in "Maybe Rust isn’t a good tool for massively concurrent, userspace software"]]></title><description><![CDATA[
<p>You don't even need other runtimes for this. Tokio includes a single-threaded runtime and tools for dealing with tasks that aren't thread safe, like LocalSet and spawn_local, that don't require the future to be Send.</p>
]]></description><pubDate>Fri, 08 Sep 2023 18:38:32 +0000</pubDate><link>https://news.ycombinator.com/item?id=37437598</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37437598</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37437598</guid></item><item><title><![CDATA[New comment by awused in "Maybe Rust isn’t a good tool for massively concurrent, userspace software"]]></title><description><![CDATA[
<p>There's nothing buggy about a future that never yields because it can always make progress, but people prefer that a runtime doesn't let all other execution get starved by one operation. That makes it a problem that runtimes and schedulers work to solve, but not a bug that needs to be prevented at a language level. A runtime that doesn't solve it isn't buggy, but probably isn't friendly to use, like how Go used to have problems with tight loops and they put in changes to make them cause less starvation.</p>
]]></description><pubDate>Fri, 08 Sep 2023 18:24:06 +0000</pubDate><link>https://news.ycombinator.com/item?id=37437382</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37437382</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37437382</guid></item><item><title><![CDATA[New comment by awused in "FP-Go: Functional programming library for Golang"]]></title><description><![CDATA[
<p>><i>You are right. I concede nil is not useful.</i><p>You say this sarcastically, but it is actually true. A nil pointer is not useful. Once you have determined that a pointer is nil, you have confirmed that the function returning it at all was a waste of both space and time. Though it's actually only half true: nil pointers are worse than useless and they provide negative utility, because they allow invalid code to compile. A better design - which is also more efficient, even considering the overhead of tagged unions - is to not return the pointer/value at all if it would be useless. Other languages allow for this, even C does <i>allow</i> for it with manually tagged unions. Go is rather unique, especially among modern languages, in how it doesn't provide any mechanism for it, so people use what is available to emulate that.<p>For the rest of it, well, you've contorted yourself into some really interesting positions.</p>
]]></description><pubDate>Sun, 20 Aug 2023 05:52:01 +0000</pubDate><link>https://news.ycombinator.com/item?id=37196492</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37196492</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37196492</guid></item><item><title><![CDATA[New comment by awused in "FP-Go: Functional programming library for Golang"]]></title><description><![CDATA[
<p>You are now claiming that they are useful when you <i>must</i> discard them as useless when the error is non-nil. At least with you being caught in such a plain and clear lie I can be done with this.<p>><i>I love nothing more than being wrong.</i><p>That's odd, because you've contorted yourself into defending absurd positions based on personal definitions no one else shares, including the Go authors, just to avoid admitting you were wrong. The same Go authors responsible for both the proverbs, which you quote as gospel, and the style guide, which you claim doesn't apply when it's inconvenient because it directly contradicts your claims in plain english.</p>
]]></description><pubDate>Sat, 19 Aug 2023 20:56:51 +0000</pubDate><link>https://news.ycombinator.com/item?id=37193104</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37193104</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37193104</guid></item><item><title><![CDATA[New comment by awused in "FP-Go: Functional programming library for Golang"]]></title><description><![CDATA[
<p>><i>No, it is very much written from a consumer perspective. We're talking about from the producer perspective.</i><p>This is just a lie. It's written about Go and doesn't split its perspectives, the producer should only ever return meaningful non-error values with an error if explicitly documented, and the consumer should only ever expect those when documented.<p>><i>you point to a good example of where you can find un-meaningful return values when there is an error.</i><p>Okay, skimming the release notes for 1.21. The slog package, brand new in 1.21, contains a MarshalText method (and others, but this is the first I noticed). It returns ([]bytes, err) and it is not documented to be idiomatic as per your personal definition. Therefore, by your interpretation of the style guide and your own personal standards, it is not idiomatic. What's more, a nil/empty slice is potentially valid output from marshaling something, so the slice is entirely useless and <i>must</i> be ignored if err is non-nil. It is not valid to try to "derive meaning" (your terminology) from the slice being nil or not, so it is well and truly useless if err isn't nil.<p>Moreover, I'll assert that if Either existed in the stdlib, it would return Either[bytes[], err] instead of ([]bytes, err), and it is a limitation of Go that they're using (T, error) which does not offer the appropriate semantics.<p>><i>Clearly the vast majority of the standard library, especially in the newer stuff, does return meaningful values upon error</i><p>This, too, is simply a lie.</p>
]]></description><pubDate>Sat, 19 Aug 2023 20:36:52 +0000</pubDate><link>https://news.ycombinator.com/item?id=37192902</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37192902</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37192902</guid></item><item><title><![CDATA[New comment by awused in "FP-Go: Functional programming library for Golang"]]></title><description><![CDATA[
<p>><i>Yes, it says you cannot trust functions, unless documented, to be idiomatic.</i><p>That is not what it says, in fact, it almost says the opposite. It is idiomatic Go to never return useful values if error is non-nil unless explicitly documented. It never affirms your particular, personal, definition of what "Idiomatic Go" is and directly contradicts it.<p>><i>If you believe that the stdlib is idiomatic</i><p>I believe most of the stdlib is idiomatic Go, especially the newer stuff. Your excuse earlier was that the older stuff in the stdlib isn't idiomatic but the newer stuff is. But the newer stuff doesn't match your personal standards for being idiomatic either. I would challenge you to point to a large body of code that actually matches your definition of idiomatic, I do not think it exists.</p>
]]></description><pubDate>Sat, 19 Aug 2023 20:19:04 +0000</pubDate><link>https://news.ycombinator.com/item?id=37192738</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37192738</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37192738</guid></item><item><title><![CDATA[New comment by awused in "FP-Go: Functional programming library for Golang"]]></title><description><![CDATA[
<p>><i>Based on what?</i> ... <i>In fact, Go Proverbs even says so.</i><p>And the Go style guide says otherwise: if err is non-nil, you shouldn't even check the other return values. The Go proverbs are just words, it doesn't make them true or even good ideas. When Go proverbs don't agree with how Go code is written, including idiomatic Go code, reality wins over a bad theory. The Go style guide happens to better match real code written by real people, even the people directly responsible for the proverbs.<p>><i>I'd love to see some real-world code you think is idiomatic</i><p>To be fair, I have been talking about the Go programming language and idiomatic code written in that language. You seem to have a different idea of "Idiomatic Go" from everyone else's. Most of the stdlib, including the newest additions, is idiomatic as judged by other people but evidently not by you.</p>
]]></description><pubDate>Sat, 19 Aug 2023 17:36:23 +0000</pubDate><link>https://news.ycombinator.com/item?id=37191126</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37191126</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37191126</guid></item><item><title><![CDATA[New comment by awused in "FP-Go: Functional programming library for Golang"]]></title><description><![CDATA[
<p>Since you seem unwilling or unable to follow an argument you started this seems more like an attempt to bait a response that you can report to the mods instead of an honest conversation. If you want to know why the alleged tangent was relevant, well, the posts are still there.</p>
]]></description><pubDate>Sat, 19 Aug 2023 17:29:23 +0000</pubDate><link>https://news.ycombinator.com/item?id=37191047</link><dc:creator>awused</dc:creator><comments>https://news.ycombinator.com/item?id=37191047</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37191047</guid></item></channel></rss>