Hacker Newsnew | past | comments | ask | show | jobs | submit | nh2's commentslogin

Of course the infinite loop should run as expected.

It breaks the most fundamental debugging expectations (such as "delete code until problem disappears") if the fundamental, minimal building blocks of a language, when on their own, do random rubbish.

To understand a program that does something, better first understand a program that does nothing.

As a fan of sensible analogies:

You put a salad bowl with vinegar into the fridge and notice that when you do that, the fridge stinks afterwards. You try again without the vinegar, then without the salad. In C++ world, upon receiving the empty bowl, the fridge detonates ("it is not useful"), blowing up your house. That is not OK.


But if you program a for loop computing the sum from 1 to n, this also gets replaced by a constant (unless you build in debug mode). Why would an empty loop be different?

I think the argument is that the equivalent of an infinite loop would be a halt / abort instruction, not a complete removal of the loop and continue running anything else.

Not necessarily what you want in that case either: it's a common pattern in cases where you want the system to halt until you can attach a debugger to inspect the state. A halt/abort instruction that trashes that state would be undesirable (some CPUs have an instruction that is equivalent, but many do not, after all, why bother if you can just write an infinite do-nothing loop?).

A halt instruction is probably the appropriate representation for an infinite loop - the process gets stuck same as the infinite loop without proceeding. Abort is the instruction you want unreachable() to compile down into. It wasn’t an either or but both depending on the specific behavior you want.

Expecting a piece of code to be compiled to a precise sequence of machine instructions is exactly what you should not do with high-level languages like C++. Their task is exactly to abstract the machine away. They give you the guarantee that the final observable result will be what you asked for, not that the means to obtain that result will be what you have in mind.

If you write a loop to zero out some memory, it can be compiled to a loop, or to a call to an optimized predefined function, or even to a sequence of single zeroing instructions, if the size is small enough.

Even a single statement as a=0 may be compiled to a "load immediate" instruction, or an "XOR with itself", or a "sub with itself", or a move from another register known to be 0.


I'm not sure what this has to do with my comment. I am aware of all of this. It would be nice if an infinite loop was defined to be 'do nothing, indefinitely'. On architectures with an instruction that works that works precisely that way, it could be turned into that, perhaps, but that's an implementation detail and should follow the as-if principle (I'm also not sure any compiler would bother).

> I'm not sure what this has to do with my comment

Because you explicitly mentioned details that belong in the implementation, not in the semantic:

> A halt/abort instruction that trashes [the] state would be undesirable

If you want to attach a debugger, then use a breakpoint, don't try to obtain the same effect within the code.


Memory allocation behaviour has visible impact also for users of managed languages, and the behaviour of software for end users.

In our Python program, a bit of numpy processing of large pictures led to 100 GB not being returned to the OS by glibc's default allocator and the machine running out of memory shortly after. With jemalloc's reliable memory return settings, those problems disappear.


I'm in the same boat, I just switched to using it for Kavita, which only does some basic open Image -> Thumbnail to smaller size -> write to disk when importing new comics/books and on linux, memory could swell to 10GB and never get released. Switched to jemalloc and instantly memory stayed well below 1GB.

Generally yes, but the wording of "instantly" begs for the following pedantic remark:

This is controlled by jemalloc settings `dirty_decay_ms`, `muzzy_decay_ms`, and their interaction with `background_thread`.

`dirty_decay_ms` currently defaults to 10 seconds, so it's not that instant.

That is important e.g. for single-threaded programs that start other programs, such as my Python example: If it starts a subprocess before the 10 seconds elapse after `free()`, Python (and jemalloc) do not run, and get no chance to return memory to the OS.

In such cases, either enable `background_thread`, or set the `_decay_` values to `0` to ensure immediate return to the OS upon `free()`. (This costs some performance.)

See e.g. https://github.com/jemalloc/jemalloc/issues/2688


Okay but do you think the hordes of JavaScript developers at FANG can just change the browser’s allocator?

The number of programmers who are in positions to care about jemalloc vs other malloc is minuscule


The point is that such bugs shouldn't exist in the first place.

Using recursion on unbounded inputs on a programming language that doesn't support that (which are most) is an extremely classical mistake that really should be known to all programmers, especially those of low level languages that care about safety.

Every time you call something recursively you should be thinking "how deep is this?".


> The point is that such bugs shouldn't exist in the first place.

That's true of every bug, but you don't have infinite time or manpower, so how do you prioritise?


Do you have an example comparison?

> oh, it seems that the lumatone is the commercialized version essentially

From the same makers or others?

On the website I can find no info whether this project is concluded or not.


This website has unbearable scroll performance on mobile.

Is it the animation at the top?


We tested it in mobile, but several people pointed out that we have more performance work to do to make sure that the animation is fast on lower-end hardware. I don't know what phone you're using, but we'll get it fixed regardless.


1 more data point - it's very slow on my desktop which has relatively high performance as well. Using Brave if that matters.


We're about to push a change that should improve this a bit, thanks for the reports!


Thanks, the animation is gone now and the problems are gone as well.

Good choice in my opinion, as I hadn't even noticed the animation existed until I looked for something that might make the scrolling slow.


One more data point--I'm using Firefox on an M1 Mac mini (MacOS 15.7.7), and this web site destroys the responsiveness of this system in a way I have literally never seen before (4+ years) from anything, web site or otherwise.

I opened up Activity Monitor and CPU use looked normal but it showed the GPU was pegged at 100% as long as that page was open.


Justified fear. A former flat mate of mine reported an unexpected outgoing transfer to his UK bank and they blocked his account for 3 months. He was essentially unbanked. He had to pay his rent in cash after getting it from an ATM with a credit card (which cost a lot extra and hit limits). Resolving it took months even though we lived right next to a branch of that bank, where he went every day.


In Haskell they are a little less annoying. It is just easier to reason about (including proving) pure functions.


I meant the constrained types by hiding the constructors. Super annoying, not automatically convertible, in Haskell you have to remember what the fake constructor is called, and write it every time you use it, but at least it's efficiently implemented with newtype, unlike the Java OOP version. Think about writing a value with several nested constrained types, like NonEmptyListOne (makeNonZeroNumber 42, 'h' `NonEmptyString` "ello world"). It's just really annoying.


The blog link I mentioned avoids this cost with literals, by providing using a required type argument to check the string length at compile time without TH. It requires a relatively recent GHC:

    make :: forall symbol -> (IsNonEmptySymbol symbol) => NonEmptyText

    type family IsNonEmptySymbol symbol :: Constraint where
      IsNonEmptySymbol "" = Unsatisfiable (Text "Expected a non-empty string")
      IsNonEmptySymbol _ = (()::Constraint) -- empty constraint is always satisfied


Code review tools should really compare with reviewable.io, which supports proper review of every-commit in a PR, with force pushes, making sure all changes get read, and comment sign-off and disposition, making sure no comment remains unaddressed.

In contrast to Gerrit and Phabricator, it needs not "Change IDs" inserted in your commits (easier workflow just using git) and "just works" to review whole branches.

It seems to me that "1 PR = 1 commit = 1 review" and "stacked PRs" workflows are just workarounds for not properly having implemented that as Reviewable has. Am I not seeing something?

Reviewable's main drawback is being for Github only and not open source.


Help me understand why I care about reviewing the fifteen commits my junior developer did while figuring out how to make a SQL query, and not just the final line of code? Typically, all I really care about is what's actually going into production, not the journey they took to get there. So, what am I missing?


> So, what am I missing?

Gerrit/CodeApprove/Reviewable-style reviews are actually designed for exactly the scenario you're describing.

The thing you're missing is that it's helpful to see a diff view of, "What changed since my last review?"

If your review workflow is:

1. Junior engineer makes 15 commits to implement a feature in 300 LOC

2. Junior engineer sends you the PR for review

3. You review and send your notes to the engineer

4. Junior engineer makes 15 more commits and another 100 LOC churn, but PR is 350 LOC total diffs

At (4), the thing you probably want to see are the 100 LOC of diffs since step (3). I haven't tried this on GitHub for awhile, but last I checked, your options are to either view only diff of PR against main branch, view each of the 15 commits individually, or hand edit the URL to get the "what's changed since (3)?" view.

On Gerrit/CodeApprove/Reviewable, they all default to "what changed since I last reviewed?" and you comment on that diff rather than what's changed against the main branch, which is the default on GitHub.


Ah, if true, than I misunderstood and agree. That didn't sound like what the person I replied to was saying though.

It's hard to leave Gerrit after using it.


Those would be squashed into one commit.

Then, when your senior developer is working on a new feature that requires some changes to adapt to a dependency upgrade, some refactoring, some forwards-and-backwards compatible database migrations, you'll appreciate a stack of discrete, clean, working, individually reviewable commits.


You have just reinvented "Safe Haskell" from 2012.

It guarantees that pure functions are pure.

https://www.microsoft.com/en-us/research/publication/safe-ha...

https://downloads.haskell.org/ghc/latest/docs/users_guide/ex...


Oooh I didn't know that was a thing!

Yes, I want this but in a fast, compiled systems language like rust.


Haskell is a fast, compiled systems language like Rust (or rather, Rust is like Haskell).


Are you sure about that? My understanding is that Haskell programs generally run much more slowly than their C counterparts because of all of Haskell’s magic. Like lazy evaluation and memoisation and however Haskell manages memory.

Rust certainly borrows from Haskell. Like all good languages. But I’m not aware of Haskell beating rust in program performance & memory usage benchmarks.

SeL4 was first written in Haskell and proven correct in Haskell. Then, with a great many years of effort, ported to C and proven correct there. If Haskell were a viable systems language, I suspect the kernel would not have been converted to C.


Yes, I'm sure about that. I said that it is a systems language, not that it is as fast as C! I don't mind if your terminology excludes Haskell from being a systems language, as long as it also excludes Go. They are both managed, garbage collected, fast languages.

> Like lazy evaluation and memoisation

Yes, that causes performance impact. If you don't want the performance impact then don't write code that uses those behaviors. Sure, that rules out large parts of the ecosystem, but I said Haskell was a systems language not that its ecosystem was generally suitable for systems programming.

> however Haskell manages memory

No, Haskell's memory manager is world class, with two (at least) tunable garbage collectors.

> But I’m not aware of Haskell beating rust in program performance & memory usage benchmarks

Nor am I!

> If Haskell were a viable systems language, I suspect the kernel would not have been converted to C.

I suspect they converted it to C because you can't write a kernel in a managed language with a garbage collector.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: