HN user

benschulz

225 karma
Posts0
Comments50
View on HN
No posts found.

This seems like an uncharitable reading of the post.

They talk about the importance of purity for automatic optimizations but in the real world there’s all sorts of practical reasons for needing to debug production compiled code

I imagine they're talking about their defaults. One can commonly reconfigure how different build profiles work.

Also blaming the users of your language for your language not being able to meet their needs isn’t a good look.

Isn't that what the whole post is about though? They even say the following.

Returning to earth: we may be academics, but we are trying to build a real programming language. That means listening to our users and that means we have to support print debugging. The question is how?

Most approaches, I assume, will leverage conditional compilation: When (deterministic simulation) testing, use the deterministic async runtime. Otherwise, use the default runtime. That means there's no (runtime) overhead at the cost of increased complexity.

I'm using DST in a personal project. My biggest issue is that significant parts of the ecosystem either require or prefer your runtime to be tokio. To deal with that, I re-implemented most of tokio's API on top of my DST runtime. Running my DST tests involves patching dependencies which can get messy.

Because the compiler optimizes based on the assumption that consecutive reads yield the same value. Reading from uninitialized memory may violate that assumption and lead to undefined behavior.

(This isn't the theoretical ivory tower kind of UB. Operating systems regularly remap a page that hasn't yet been written to.)

Rust in 2022 5 years ago

Sorry, based on the replies I'm getting I did not make myself clear. I only want to use Either in cases like the following.

    fn some_func() -> impl SomeTrait {
        if some_condition {
            Either::Left(a)
        } else {
            Either::Right(b)
        }
    }
Both a and b will implement SomeTrait which is all callers care about. However, because they're structurally different they must be wrapped in an Either that delegates all methods from SomeTrait to a or b respectively.
Rust in 2022 5 years ago

Can you expand on that? As long as the public type is opaque I don't see what there is to regret.

Rust in 2022 5 years ago

I wish there was an `Either` type in std. I realize that there used to be one and we have `Result` now. However, now that we have `impl Trait` it's worth revisiting, I believe. If we don't we'll have the one from `itertools`, the one from `futures` etc.

In most GCed languages it wouldn't matter so much because you'd return a boxed `Iterator` or `Future` or what have you. But in Rust you generally want to avoid the allocation.

Lamport acknowledges the report, not the error. I'm still not convinced there even is an error.

The state after step 9 should be the same as after step 7, i.e. `A(-:-,100) B(100:b,100) C(100:b,-)` because C needs to retain the "highest-numbered proposal" it accepted, not the one it accepted last. That means the nine steps outlined in the post/on StackOverflow do not, by themselves, demonstrate any problem.

So what additional steps are missing/what alternative steps actually produce an inconsistency/divergence?

Quoting from the paper's description of Phase 1:

(b) If an acceptor receives a prepare request with number n greater than that of any prepare request to which it has already responded, then it responds to the request with a promise not to accept any more proposals numbered less than n and with the highest-numbered proposal (if any) that it has accepted.

It says an acceptor must respond with the highest-numbered proposal (if any) that it has accepted.

How is acceptor C going to do that after step 9? That's where the bug is introduced, I think, not anywhere in the paper.

Alphafold 5 years ago

My understanding is that it has been manually tested. I.e. it has produced correct results to previously intractable problems. I'm not sure how much automated testing would add at that point.

In spite of this, I am in the top 7% of accounts on the site, which is a nice reminder on the power of compound interest!

I'm also in the top 7%. That's down from 12% or so from five years ago. However, I haven't gained many points during the same interval. That leads me to believe it's not about compound interest but new users joining.

Data races are undefined behavior, and race conditions are a logic error. Yes, both are bugs, and both are important to fix. But they have (at least to me) different severities.

Some data races really are benign while some other race conditions can lead to data corruption or security vulnerabilities. Why then should data races be strictly more severe than data races? What am I missing?

Actually "this context" was my previous reply. Much like I can nest a lexical scope inside a program and have it reach up and past the containing scope, I can create a new context in a discussion. Please at least try to understand my position before you reply.

It's possible to have truly benign data races too, e.g. lazily computing a hash of immutable data.

One of the reasons that Rust's ownership model is necessary is most data races cannot otherwise be statically detected. The compiler will be unable to apply any of its theoretical UB optimizations. It will emit its native code and you get the defined behavior of the underlying hardware. There will be no undefined behavior. If that ever changes, the bigger news, I imagine, will be that we solved the halting problem.

I'm not convinced this is a meaningful distinction in this context. Assuming a developer consciously creates a race which turns out to be a bug, how does it matter whether it was a data race or some other kind of race condition?

AFAIU one can create races in safe code using atomics with insufficient ordering.

(That notwithstanding, I agree that Rust is a vast improvement over C/++.)

I'm not sure I buy the premise. The point of the original article was that you shouldn't dig a hole for yourself to get out of later. Compiler writers usually go out of their way, digging extra deep holes, to accept a broad range of invalid input. Not because they like complexity---though, as a group they.. I digress---but because it lets them give more valuable user feedback.

Fair enough. I think I misinterpreted the "easier to approach" part of your original answer. Sorry if my answer came across as defensive. My wounds are still fresh. ;)

My reading of the article's introduction is that Redis is adding this feature and are (among other things I'm sure) paying jepsen to test it. So this is them having tests.

If you follow basic software engineering principles, you'll find distributed systems easier to approach.

When I implemented Paxos I had tests and when they failed they spit out an exact trace of what happened in what order and on what node. Sometimes it was still excruciating to figure out what happened. Here's[1] a comment which you can think of as a bug tombstone. It took me half a day to figure out after I had a trace to analyze the issue.

[1] https://github.com/benschulz/paxakos/blob/ee051ff67b5da6f287...

It's unbelievable how hard to grasp distributed systems are. I recently implemented Paxos in Rust and at certain points I literally thought I was losing my mind.

When you read Paxos Made Simple it really all seems so, well, simple. But then you get inconsistent commits and look at the traces of what happened and just go "How?!"

You're making the assumption that he knew what the reaction would be. The post could have easily gone ignored, especially in the current turmoil.

I agree that software developers have it pretty good. But let's not, on that basis, discount acts of moral integrity.

You do realize that Anders Hejlsberg is on the TypeScript team? I don't want to imply that he's superhuman or anything, but.. just what is your idea of "serious compiler engineers"?