Rust: Dropping heavy things in another thread can make your code 10000x faster - <AUTHOR> https://abramov.io/rust-dropping-things-in-another-thread <comment><USER2> Some important things I think people should note before blindly commenting:

* The example code is obviously contrived. The real gist is that massive deallocations in the UI thread cause lag, which the example code proves. That very thing can easily happen in the real world.

* I didn't see any difference on my machine between a debug build and a release build.

* The example is preforming 1 _million_ deallocations. That's why it's so pathological. It's not just a "large" vector. It's a vector of 1 million vectors. While that may seem contrived, consider a vector of 1 million strings, something that's not too uncommon, and which would likely suffer the same performance penalty.

* Rust is not copying anything, nor duplicating the structures here. In the example code the structures would be moved, not copied, which costs nothing. The deallocation is taking up 99% of the time.

* As an aside, compilers have used the trick of not free-ing data structures before, because it provides a significant performance boost. Instead of calling free on all those billions of tiny data structures a compiler would generate during its lifetime, they just let them leak. Since a compiler is short lived its not a problem, they get a free lunch (pun unintended), and the OS takes care of cleaning up after all is said and done. My point is that this post isn't theoretical, we do deallocation trickery in the real world.

<comment><USER3> This deallocation trick is neat but in C and C++ you could use a memory pool to do this.

In theory, you could also use a memory pool in Rust but I think the standard library uses malloc without some way of overriding this behaviour.

<comment><USER4> You can change the global allocator in any rust project. You can write your own easy enough, or use one like jemalloc

<comment><USER5> Sure; but when you're using arenas and things like that you usually you will want different objects allocated into different pools (or with different lifetime properties). Rust only lets you pick one allocator for the entire process, so you can't specify "all the children of this data structure go in arena A, and this other allocation goes into a traditional heap".

It's more awkward, but I much prefer Zig's approach here where everything that allocates takes an allocator as a parameter. Usually the allocator is specified at compile time - in which case zig can generate identical code to the rust compiler. But when you want the flexibility, it's there.

Aside from compilers, this is heavily used in video games where there's often a lot of objects that get allocated per frame, and can be discarded all together. And in that case rust's lifetime tracking would be a huge asset. The dovecot email server (C) also makes superb use of a mix of memory containers for different tasks. Given how messy email parsing is, dovecot is an absolute pleasure to read.

<comment><USER6> As someone that is interested in the topic and in Zig's "provide your own allocator" approach I have a question: would it be possible to make an allocator wrapper that moves values to be deallocated to a different thread?

As far as I know it would require both Rust's borrowing semantics and Zig's architectural choice.

From purely my own fan-boy perspective Zig approach is something that I would have really liked for Rust to adopt (I have no idea of which one came first chronologically).

<comment><USER7> It is not an allocator wrapper, but [https://docs.rs/defer- drop/1.0.1/defer_drop/index.html](https://docs.rs/defer- drop/1.0.1/defer_drop/index.html)

</comment></comment></comment></comment></comment></comment><comment><USER8> This is the standard problem with tracing data structures to free them. You frequently run into it with systems based on malloc/free or reference counting. The underlying problem is that freeing the structure takes time proportional to the number of pointers in the structure it has to chase.

Generational/compacting GC has the opposite problem. Garbage collection takes time proportional to the live set, and the amount of memory collected is unimportant.

It's actually a lot to be said for rust that the ownership system lets you transfer freeing responsibility off-thread safely and cheaply in order to not have it block the critical path.

But overall, there's nothing really unexpected here, if you're familiar with memory management.

<comment><USER9> > This is the standard problem with tracing data structures to free them. You > frequently run into it with systems based on malloc/free or reference > counting. The underlying problem is that freeing the structure takes time > proportional to the number of pointers in the structure it has to chase.

That doesn't seem to make intuitive sense. A GC has the same problem.

A garbage collector has to traverse the data structure in a similar way to determine whether it (and it's embedded keys and values) are part of the live set or not, and to invoke finalizers. You're beginning your comparison after the mark step, which isn't a fair assessment since what Rust is doing is akin both both the mark and sweep phases.

The only way to drop an extensively nested structure like this any faster than traversing it would be an arena allocator, and forgetting about the entire arena.

The difference between a GC and this kind of memory management is that the GC does the traversal later, at some point, non-deterministically. Rust allows you to decide between deallocating it in place, immediately, or deferring it to a different thread.

<comment><USER8> I said generational/compacting collector. You're talking about a mark and sweep collector.

A generational/compacting collector traverses pointers from the live roots, and copies everything it finds to the start of its memory space, and then declares the rest unused. If there is 1GB of unused memory, it's irrelevant. Only the things that can be reached are even examined.

As I said, this has the opposite problem. When the live set becomes huge, this can drag performance. When the live set is small, it doesn't matter how much garbage it produces, performance is fast.

<comment><USER9> How are finalizers invoked if the structure isn't traversed? Would it just be optimized away none of the objects have finalizers? Hence my suggestion about the area allocators being a better point of comparison.

<comment><USER10> Java is an example of a language with a generational copy collector by default. Most objects in Java don't have a finalizer, since after all the main point of, for example, destructors in C++ is to make sure you don't leak memory, which the GC solves. But when the `finalize` method is used is causes significant overhead.

> Objects with finalizers (those that have a non-trivial finalize() method) > have significant overhead compared to objects without finalizers, and should > be used sparingly. Finalizeable objects are both slower to allocate and > slower to collect. At allocation time, the JVM must register any > finalizeable objects with the garbage collector, and (at least in the > HotSpot JVM implementation) finalizeable objects must follow a slower > allocation path than most other objects. Similarly, finalizeable objects are > slower to collect, too. It takes at least two garbage collection cycles (in > the best case) before a finalizeable object can be reclaimed, and the > garbage collector has to do extra work to invoke the finalizer. [1]

Sure, you're technically correct that if the objects all had finalizers that did the same thing as C++ destructors, it would be equivalent, but because of the existence of a GC we don't have to do any work for most objects. A GC is equivalent to an arena allocator in this sense.

Another point is the C++/Rust pattern of each object recursively freeing the objects it owns presumably leads to slower deallocation, because in the general case it involves pointer following and non-local access.

[1] [https://www.ibm.com/developerworks/java/library/j-jtp01274/i...](https://www.ibm.com/developerworks/java/library/j-jtp01274/index.html)

<comment><USER11> Destructors in C++ aren't just for making sure you leak memory. They are used for many lifetime controlled things such as: 1\. general resource cleanup (file handle, database connection, etc.) using RAII (Resource Aquisition Is Initialization); 2\. tracing function entry/exit.

<comment><USER12> Apparently, that doesn't work in Rust: [https://news.ycombinator.com/item?id=23363647](https://news.ycombinator.com/item?id=23363647)

<comment><USER13> It does work in rust. you just cannot rely on Drop _for memory-safety_. If you mem::forget a struct that holds onto some other resource then all that means is that you're committing that resource to the lifetime of the process. We usually call that a leak but it can be intentional.

</comment></comment></comment></comment></comment></comment></comment></comment><comment><USER14> The title is slightly wrong: it's not going to make your code _faster_ , it's going to reduce _latency_ on the given thread.

It maybe a net win if this is the UI thread of a desktop app, but overall, it will come at a performance cost: because modern allocators have thread-local memory pools, and now you're moving away from it. And if you're running you code on a NUMA system (most server nowadays), when moving from one thread to another, you can end up freeing non-local memory instead of local one. Also, you won't have any backpressure on your allocations, and you are susceptible to run out of memory (especially because your deallocations now occur more slowly than they should)

Main takeaway: if you use it blindly it's an anti-pattern, but it can be a good idea in its niche: the UI thread of a GUI.

<comment><USER15> Yes it'll reduce latency, but doesn't it also increase parallelism? A single- threaded program ought to improve overall, unless the extra overhead you mentioned dominates. A parallel program might improve or not.

I think if you wanted to do deferred destruction right, ideally you'd mod an allocator to have functions like (alloc_local, alloc_global, free_now, free_deferred) to avoid exhausting memory. Traits could make this ergonomic.

Also I admit I don't understand why "you won't have any backpressure on your allocations," shouldn't deferred destruction give you more backpressure if anything? I am probably confused.

<comment><USER16> > Also I admit I don't understand why "you won't have any backpressure on your > allocations," shouldn't deferred destruction give you more backpressure if > anything? I am probably confused.

I think the point is that, if the same thread is doing both allocation and de- allocation, the thread is naturally prevented from allocating too much by the work it must do to de-allocate. If you move the de-allocation to another thread, your first thread may now be allocating like crazy, and the de- allocation thread may not be able to keep up.

In a real GC system, this is not that much of a problem, as the allocator and de-allocator can work with each other (if the allocator can't allocate any more memory, it will generally pause until the de-allocator can provide more memory before failing). But in this naive implementation, the allocator thread can exhaust all available memory and fail, even though there are a lot of objects waiting in the de-allocation queue.

<comment><USER15> Ah, I see what you mean, thanks!

</comment></comment></comment></comment><comment><USER17> Just be careful, because moving heavy things to be dropped to another thread can change the _semantics_ of the program. For instance, consider what happens if within that heavy thing you had a BufWriter: unless its buffer is empty, dropping it writes the buffer, so now your file is being written and closed in a random moment in the future, instead of being guaranteed to have been sent to the kernel and closed when the function returns.

And it can even be worse if it's holding a limited resource, like a file descriptor or a database connection. That is, I wouldn't recommend using this trick unless you're sure that the only thing the "heavy thing" is holding is memory (and even then, keep in mind that _memory_ can also be a limited resource).

<comment><USER18> I only know a very little rust, but since it's generally a good practice to never defer writing (or other side effects) to an ambiguous future point in time - with memory allocations as the only plausible exception - is there any way in rust to make sure one doesn't accidentally move complex objects with drop side-effects into other threads?

Granted the way the type system work you usually know the type of a variable quite well, but could this happen with opaque types?

I'm very much out of my depth, but it felt like one of those things that could really bite you if you are unaware, as happened with finalizers in Java decades ago.

<comment><USER19> > I only know a very little rust, but since it's generally a good practice to > never defer writing (or other side effects) to an ambiguous future point in > time - with memory allocations as the only plausible exception - is there > any way in rust to make sure one doesn't accidentally move complex objects > with drop side-effects into other threads?

If you're the one creating the structure, you could opt it out of Send, that'd make it… not sendable. So it wouldn't be able to cross thread-boundaries. For instance Rc is !Send, you simply can not send it across a thread-boundary (because it's a non-threadsafe reference-counting handle).

If you don't control the type, then you'd have to wrap it (newtype pattern) or remember to manually mem::drop it. The latter would obviously have no safety whatsoever, the former you might be able to lint for I guess, though even that is limited or complicated (because of type inference the problematic type might never get explicitly mentioned).

</comment></comment></comment><comment><USER20> I've seen variations on this trick multiple times. Using threads, using a message sent to self, using a list and a timer to do the work "later", using a list and waiting for idle time...

They all have one thing in common: pampering over a bad design.

In the particular example given, the sub-vector probably come from a common source. One could keep a big buffer (a single allocation) and an array of internal pointers. For example of such a design to hold a large array of text strings, see for example this blog entry and its associated github repo:

        https://www.spiria.com/en/blog/desktop-software/optimizing-shared-data/
        https://github.com/pierrebai/FastTextContainer

Roughly it is this:

        struct TextHolder
        {
            const char* common_buffer;
            std::vector<const char*> internal_pointers;
        };

This is of course addressing the example, but the underlying message is generally applicable: change your flawed design, don't hide your flaws.

<comment><USER21> Yes. There's also a number of pool/arena allocators in rust which could be used here instead to drop All entries at once.

</comment></comment><comment><USER22> Why would you ever write a get_size function that drops the object you call it on? Surely in an actual, non-contrived usecase spawning another thread and letting the drop occur there would just be plain worse?

<comment><USER23> I believe this is contrived to prove a point.

And this isn't just a help in these contrived examples. I believe process cleanup (an extreme case of cleaning up objects) is one of cases where garbage collection performs better because it doesn't have to unwind the stack, call cleanup functions that are not in the cache, and make a lot of `free` calls to the allocator.

I vaguely remember reading about Google killing processes rather than having them clean up correctly, relying on the OS to properly clean up any resources of significance.

Now this doesn't mean you should do this in all cases. Profile first, see if you can avoid the large objects, and then look into deferred de-allocations ... if the timing of resource cleanup meets your application's guarantees.

<comment> seventh-chord Killing a process without freeing all allocations is, as far as I can tell, routine in C. Especially for memory it makes no sense "freeing" allocations, the whole memory space is getting scrapped anyways. Of course, once you add RAAI the compiler cant reason about which destructors it can skip on program exit, and if programmers are negligent of this you get programs that are slow to close.

<comment><USER24> > Killing a process without freeing all allocations is, as far as I can tell, > routine in C.

Many times by accident :)

> if programmers are negligent of this you get programs that are slow to > close.

I wouldn't call that negligence, just not fully optimized.

</comment></comment></comment></comment><comment><USER23> For those wanting a real world example where this can be useful:

I am writing a static site generator. When run in "watch" mode, it deletes everything and starts over (I'd like to reduce these with partial updates but can't always do it). Moving that cleanup to a thread would make "watch" more responsive.

<comment><USER25> That's not really the same issue that is mentionned in the article though, is it ?

The issue from the article would be solved by just passing a reference to the variable.

In your case, cleanup is an action that _needs_ to be done before writing new files. So you have to wait for cleanup anyway, don't you ?

<comment><USER26> That's not true.

Typically any server with a watch functionality will have a mutable reference to the data that's being watched. When you change that data out you're both changing the mutable reference, and also deallocating any memory that was previously used. One _could_ separate these two steps, moving the watched data to another variable that's dropped in another thread, if you wanted.

</comment></comment></comment><comment><USER27> There is nothing unique to Rust about this; it is a very old technique. It is usually much inferior to the "arena allocator" method, where all the discarded allocations are coalesced and released in a single, cheap operation that could as well be done without another thread. That method is practical in many languages, Rust possibly included. C++ supports it in the Standard Library, for all the standard containers.

If important work must be done in the destructors, it is still better to farm the work out to a thread pool, rather than starting another thread. Again, C++ supports this in its Standard Library, as I think Rust does too.

One could suggest that the only reason to present the idea in Rust is the cynical one that Rust articles get free upvotes on HN.

<comment><USER28> > C++ supports it in the Standard Library, for all the standard containers.

I don't know what the situation is today, but in the past, the GCC standard library containers had non-trivial destructors when running in debug mode. Ensuring their proper invocation was required to avoid dangling pointers in their book keeping. Non-obvious and painful to debug.

</comment></comment><comment><USER29> Speedup numbers should be given when optimizing constant factors -- e.g. "I made this operation 5X faster using SIMD" or "By employing readahead, I sped up this file copy by 10X".

The points raised in this article are really different:

* don't do slow stuff in your latency-critical path

* threads are a nice way to unload slow stuff that you don't need done right away (especially if you have spare cores)

* dropping can be slow

The first and second points are good, but not really related to rust, deallocations, or the number 10000.

The last point is worth discussing, but still not really related to the number 10000 and barely related to rust. Rust encourages an eager deallocation strategy (kind of like C), whereas many other languages would use a more deferred strategy (like many GCs).

It seems like deferred (e.g. GC) would be better here, because after the main object is dropped, the GC doesn't bother to traverse all of the tiny allocations because they are all dead (unreachable by the root), and it just discards them. But that's not the full story either.

It's not terribly common to build up zillions of allocations and then immediately free them. What's more common is to keep the structure (and its zillions of allocations) around for a while, perhaps making small random modifications, and then eventually freeing them all at once. If using a GC, while the large structure is alive, the GC needs to scan all of those objects, causing a pause each time, which is not great. The eager strategy is also not great: it only needs to traverse the structure once (at deallocation time), but it needs to individually deallocate.

The answer here is to recognize that all of the objects in the structure will be deallocated together. Use a separate region/arena/heap for the entire structure, and wipe out that region/arena/heap when the structure gets dropped. You don't need to traverse anything while the structure is alive, or when it gets dropped.

In rust, probably the most common way to approximate this is by using slices into a larger buffer rather than separate allocations. I wish there was a little better way of doing this, though. It would be awesome if you could make new heaps specific to an object (like a hash table), then allocate the keys/values on that heap. When you drop the structure, the memory disappears without traversal.

</comment><comment><USER30> If I seriously wanted to move object destruction off-thread, I would use at least a dedicated thread with a channel, so I could make sure the dropper is done at some point (before the program terminates, at the latest). It also avoids starting and stopping threads constantly.

Something like this: [https://play.rust- lang.org/?version=stable&mode=debug&editio...](https://play.rust- lang.org/?version=stable&mode=debug&edition=2018&gist=bf35e0f30b0a730f41b215e5bff8270a)

You could have an even more advanced version spawning tasks into something like rayon's thread pool, I assume.

<comment><USER31> Someone is working on this as a direct response to this blog:

[https://www.reddit.com/r/rust/comments/go4xcp/new_crate_defe...](https://www.reddit.com/r/rust/comments/go4xcp/new_crate_deferdrop_defer_dropping_your_data_to_a/)

And yes, spawning a thread for every drop is horrible. It's just to prove the concept. The defer_drop crate uses a global worker thread.

</comment></comment><comment><USER32> I'm not very familiar with Rust, but I don't understand why you wouldn't just use a reference-to-HeavyThing as the function argument, so that the object isn't moved and then dropped in the `get_size` function?

<comment><USER23> For these contrived cases, yes, you would just pass a reference to the function but I think the point is to simplify the case down to demonstrate a point.

<comment><USER33> In the olden days, it was just out.flush(); out.close();

</comment></comment></comment><comment><USER34> One thing I just noticed is that the example doesn't make sure to actually run the new thread to completion before the main thread exists.

This means that if you do a "drop in other thread" and then main exists, the drop might never run. Which is often fine as the exit of main causes process termination and as such will free the memory normally anyway.

But it would be a problem one some systems where memory cleanup on process exit is less reliable. Through such systems are more rare by now I think.

<comment><USER31> It would have to be a non-desktop system.

I'm pretty sure Linux will always free process-private memory, and threads, and file descriptors when a process exits.

The only things that can leak in typical cases are some kinds of shared memory and maybe child processes?

</comment></comment><comment><USER35> It'd be interesting to implement this on a type that would defer all of these drop threads (or one big drop threads built off a bunch of futures) until the end of some major action, like sending the http response on an actix-web thread. Could be a great way to get the fastest possible response time, since then the client has their response before any delay on cleanup.

<comment><USER36> There is no such thing as a free lunch here, so it would reduce the unloaded response time but should have no effect (or a negative impact) on a highly loaded server's response time. I'm finding this out when benchmarking a message passing/queue management system. Anything I do to defer work onto a separate threadpool improves latency up to a point, then reduces throughput.

<comment><USER35> If you're bottlenecked, then certainly. There's no free lunch, but for us, problems that can be solved by simply scaling up the resources on the host as relatively cheap as free vs expensive developer time. When we're purely focused on sales and not anywhere close to hitting a full mem/cpu bottleneck, this would bee good.

This situation you describe sounds a lot like dealing with garbage-collection cycles, so you give a good recommendation on something to watch out for, as rust performing at the level of a GC'd language removes a big reason for choosing rust.

</comment></comment></comment><comment><USER37> Looks like Evan Wallace ran into the same issue in practice in esbuild

[https://news.ycombinator.com/item?id=22336284](https://news.ycombinator.com/item?id=22336284)

 _I actually originally wrote esbuild in Rust and Go, and Go was the clear winner._

 _The parser written in Go was both faster to compile and faster to execute than the parser in Rust. The Go version compiled something like 100x faster than Rust and ran at something around 10% faster (I forget the exact numbers, sorry). Based on a profile, it looked like the Go version was faster because GC happened on another thread while Rust had to run destructors on the same thread._

ESBuild is a really impressive performance-oriented project:

[https://github.com/evanw/esbuild](https://github.com/evanw/esbuild)

 _The Rust version also had other problems. Many places in my code had switch statements that branched over all AST nodes and in Rust that compiles to code which uses stack space proportional to the total stack space used by all branches instead of just the maximum stack space used by any one branch_ : [https://github.com/rust-lang/rust/issues/34283](https://github.com/rust- lang/rust/issues/34283)

(copy of lobste.rs comment)

</comment><comment><USER38> I used to do this sometimes with C++ when I realized that clearing out a vector with lots of objects was slow. Is Rust basically based on unique_ptr? One problem with this approach was that you still had to wait for these threads when the application would shut down.

<comment><USER22> Rust basically gives the compiler understanding of unique_ptr and prevents you from using it after you've moved it.

<comment><USER38> Would you have to keep track of these threads in Rust? I have done a lot of desktop development where you have to be aware of what happens during shutdown. Seems a lot of server guys write their code under the assumption that it will never shut down.

<comment><USER39> You would need to add `thread.join()` at the end of main, or have some RAII guard that does it for you.

In practice that's probably optional, because the heap and all resources are usually torn down with the process anyway. Important things, like saving data or committing transactions, shouldn't be done in destructors.

</comment></comment></comment></comment><comment><USER40> There's a worse case in deallocation. Tracing through a data structure being released for a long-running program can cause page faults, unused data having been swapped out. This is part of why some programs take far too long to exit.

</comment><comment><USER41> Completely different dynamic (because no Rust GC), but this reminds me of how Twitch made their server, written in Go, a lot faster by allocating a bunch of dummy memory at the beginning so the garbage collector doesn't trigger nearly as often:

[https://news.ycombinator.com/item?id=21670110](https://news.ycombinator.com/item?id=21670110)

<comment><USER13> The java equivalent to the Go case would simply be adjusting the -Xms flag. The Go approach is a needlessly convoluted because the runtime doesn't offer any tuning knobs.

As for the rust case, if you squint then it's similar to a concurrent collector.

</comment></comment><comment><USER42> Contrived examples like this are ridiculous. Creating such a heavy thing is likely even more expensive than tearing it down. So unless you create it on a separate thread, you probably shouldn't be freeing it on a separate one. It's not going to solve your interactivity problem. If you are creating the object on a separate thread then it's already going to be natural to free it on a separate one too.

<comment><USER31> Something is better than nothing.

</comment></comment><comment><USER43> Maybe some sort of "collector" could come by a clean up "garbage" memory periodically to improve performance…

</comment><comment><USER44> I wonder if it might be possible for OS's to provide a fast, asynchronous way of deallocating memory.

</comment><comment><USER45> Does anyone know how would this work in Go?

<comment><USER46> Lots to be learned at [https://blog.golang.org/ismmkeynote](https://blog.golang.org/ismmkeynote)

</comment></comment><comment><USER47> Minor typo, `froget` instead of `forget`

</comment><comment><USER48> Is this applicable for Go as well ?

</comment><comment><USER49> The obvious solution would be to borrow the HeavyThing instead of having it dropped inside the function.

</comment><comment><USER50> I guess choosing when or how a program deallocates is important in a language that's close to the metal.

Rust tries to be zero cost while providing abstractions that make it seemingly a high level language but ultimately things like this show that it's not exactly zero cost because abstractions can incur hidden penalties. There needs to be some internal syntax that allows a rust user to explicitly control deallocation when needed.

If I started reading code where people would randomly move a value into another thread and essentially do nothing I would be extremely confused. Any language that begins to rely on "trick" or "hacks" as standard patterns exposes a design flaw.

Maybe if rust provided special syntax that a function can be decorated with so that it does deallocation in another thread automatically? Or maybe an internal function called drop_async...? This would make this pattern an explicit part of the language rather than a strange hack/trick.

</comment><comment><USER51> Pass by reference?

<comment><USER52> If you pass by reference the heavy object won't be dropped. If your goal is to drop a heavy object, this is a cool way to do it.

</comment></comment><comment><USER53> If _freeing_ the data structure in question takes this long, how much time are you wasting _duplicating_ the data structure?

<comment><USER22> I'm actually very curious why it takes this long; is Rust memseting the buffer when dropping it?

Edit: it seems like turning on optimizations seems to improve the situation quite a bit. Not sure why they were profiling the debug build.

<comment><USER2> > it seems like turning on optimizations seems to improve the situation quite > a bit.

I'm not seeing that on my local machine? Were you comparing on the Playground which would be quite variable in its results?

        > cargo build
           Compiling foo v0.1.0 (/private/tmp/foo)
            Finished dev [unoptimized + debuginfo] target(s) in 0.42s
        > ./target/debug/foo
        drop in another thread 52.121µs
        drop in this thread 514.687233ms
        >
        >
        > cargo build --release
           Compiling foo v0.1.0 (/private/tmp/foo)
            Finished release [optimized] target(s) in 0.47s
        > ./target/release/foo
        drop in another thread 48.418µs
        drop in this thread 548.005373ms

<comment><USER22> I saw an increase of about 2x on my computer, though I didn't take too much effort to control for noise.

</comment></comment></comment></comment><comment><USER54> hmm my first thought its, having to do that is a lot like c and cleaning up my own allocations. This feels like something rust should automatically do for me?

<comment><USER55> In C, if you forget to clean up, you have a memory leak which is hard to track down. In Rust, if you don't do this, you're not sacrificing memory leaks, only performance. A profiler can tell you when you should drop asynchronously.

<comment><USER56> >A profiler can tell you when you should drop asynchronously

Is there any profiler that does this today?

What are the drawbacks with asynchronous drops?

<comment><USER57> See some discussion here: [https://www.reddit.com/r/rust/comments/gntv7l/dropping_heavy...](https://www.reddit.com/r/rust/comments/gntv7l/dropping_heavy_objects_in_another_thread_can_make/)

</comment></comment></comment></comment><comment><USER58> Oh my good god.

I'm hoping this is down to developer naivety rather than being a feature of rust.

<comment><USER59> 1) he should pass by reference to avoid the extra copy. So in his example yes it's dev naivety

2) but somewhere somehow this object will deallocate, so his trick of putting it to another thread would work if the deal location takes awhile. Same for cpp if you have a massive object in a unique ptr. So it's not a rust issue

<comment><USER60> Where's the extra copy? I don't see one. He's moving the struct into the function, getting size and then dropping it.

</comment></comment></comment><comment><USER61> In other words, Rust's automagical memory deallocation is NOT a zero-cost abstraction:

      fn get_len1(things: HeavyThings) -> usize {
          things.len()
      }

      fn get_len2(things: HeavyThings) -> usize {
          let len = things.len();
          thread::spawn(move || drop(things));
          len
      }

The OP shows an example in which a function like get_len2 is 10000x faster than a function like get_len1 for a hashmap with 1M keys.

See also this comment by chowells: [https://news.ycombinator.com/item?id=23362925](https://news.ycombinator.com/item?id=23362925)

<comment><USER34> No the zero-cost refers to the abstraction (and runtime cost), which still is zero-cost. Deallocating is part of the normal work load not the abstraction.

Also this isn't rust specific. Most (all?) RAII languages are affected and many GC approaches have this effect, too. Some do add _additional_ abstraction to magically always or sometimes put the de-allocation into another thread.

But de-allocating in another thread is not generally good or bad. There are a lot of use-cases where doing so is rather bad or can't be done (in case TLS is involved). Rust and other similar RAII languages at least let you decide what you want to do.

Now it's (I think) generally known that certain kinds (not all) of GC do make some thinks simpler for GUI-like usage. Through they also tend to have less control.

Note that it's a common pattern for small user CLI facing tools (which are not GC'ed) to leak resources instead of cleaning them up properly. You can do so in rust too if you want but it's a potential problem for longer running applications.

Also here is a faster get `get_len` then both which is also more idiomatic rust then both:

``` fn get_len1(things: &HeavyThings) -> usize { things.len() } ```

If you have a certain thread (e.g. UI thread) in which you never want to do any cleanup work you can consider using a container like:

``` struct DropElsewhere<T: Send>(pub Option<T>); impl<T: Send> Drop for DropElsewhere<T> { fn drop(&mut self) { if let Some(value) = self.take() { thread::spawn(move || drop(value)); } } } ```

You can optimize this with `ManualDrop` to have close to zero-runtime overhead (removes the `take` and `if let` part).

<comment><USER61> > No the zero-cost refers to the abstraction (and runtime cost), which still > is zero-cost. Deallocating is part of the normal work load not the > abstraction.

Yeah, you're right. In hindsight my comment was poorly thought-out and poorly written.

</comment></comment></comment><comment><USER62> Why should i ever need to drop a heavy object for only getting a size? Not in C++ and also not in Rust, the diffent thread idea is just creativ stupidity, sorry

</comment><comment><USER63> It seems that this would be a great reason to not pass the entire heavy object through your function, and to instead pass it as a reference. When passing an object (rather than a reference to an object) there's a lot more work going on both in function setup, and in object dropping. I'm not a rust guru, so I don't know the precise wording, but it's simple enough to realize that if this function, as claimed, must drop all the sub-objects within the `HeavyObject` type, then those objects must have been copied from the original object.

If you instead define the function to take in a reference (by adding just two `&` characters into your program), the single-threaded case is now almost 100x faster than the multithreaded case.

Here's a link to a Rust Playground with just those two characters changed: [https://play.rust- lang.org/?version=stable&mode=debug&editio...](https://play.rust- lang.org/?version=stable&mode=debug&edition=2018&gist=9bbe169c77cd31b6cd25b74c24635e12)

Note that the code that drops the data in a separate thread is not timing the amount of time your CPU is spinning, dropping the data. So while this does decrease the latency of the original thread, the best solution is to avoid copying and then freeing large, complex objects as much as possible. While it is of course necessary to do this sometimes, this particular example is just not one of them. :)

As an aside, I'm somewhat surprised that the Rust compiler isn't inlining and eliminating all the copying and dropping; this would seem to be a classic case where compiler analysis should be able to determine that `a.size()` should be computable without copying `a`, and it should be able to eliminate the function call cost as well. Manually doing this gives the exact same timing as my gist above, so I assume that this is happening when passing a reference, but not happening when passing the object itself.

<comment><USER30> As already mentioned, Rust wasn't copying anything; the `HashMap` is not a `Copy`-able type, so it was just moved around (it's also not very large: all its items are behind a pointer to the heap).

All you did was move the drop from the `fn_that_drops_heavy_things` to the end of `main`, where it is outside the timing function.</comment></comment>


How not to be a crank: rules for not being a science-dick - <AUTHOR> https://medium.com/@jamesheathers/how-not-to-be-a-crank-819103800502 <comment><USER3> All of these are extremely important! Two life skills:

* If you are without a doubt, you are wrong

If you can't fathom the other side and where they're coming from, you, are in fact, biased beyond listening to facts, and are likely wrong.

* Words matter

As my grandma said, "If you don't have anything nice to say don't say anything at all."

<comment><USER4> > If you can't fathom the other side and where they're coming from, you, are > in fact, biased beyond listening to facts, and are likely wrong.

This one especially applies to politics. If you are one of those looking for "sanity", or "common sense", and can't imagine how the other side can possibly hold some position, then this applies to you.

<comment><USER5> I'm not sure that's accurate. People hold all manner of irrational political beliefs and there is value in recognizing that irrationality.

<comment><USER6> Do you know the reasons for their beliefs? Can you articulate them? If not then you are conflating your own beliefs with the standard for rationality. You will also be really ineffective at convincing them they are wrong. Not because they aren't smart enough but because you are unable to communicate effectively to them.

<comment><USER7> What makes you think people understand the reasons for their own beliefs? How do you know the reasons they give you when asked are the correct ones? Why do you believe that challenging those statements respectfully will change their minds?

The actual requirement for persuasion is a believable narrative with a bit of moral weight, and a random selection of standard persuasive tricks that politicians and lawyers have been deploying with outrageous success for millennia.

Generally, being objectively correct is one of the least effective ways to change anyone's mind. You might have some hope in a scientific setting. But in popular debate, facts and rationality are almost completely powerless.

<comment><USER6> I don't know that challenging them respectfully will change their minds. After all what if they are right?

I do know that not challenging them respectfully is unlikely to persuade anyone least of all yourself.

</comment></comment></comment></comment></comment></comment><comment><USER8> A certain amount of this boils down to, "Don't be mentally ill or have an otherwise disordered mind." I've known people who were the sort of crank he's talking about, and they were generally — though not always — unhealthily isolated people who had difficulties managing their personal lives. Most had a tenuous grasp on reality, especially the motivations of other people.

There are cranks who could respond to these rules, but I believe (though I am not a mental-health professional) that many would be unable to.

<comment><USER6> I think we can let our emotions get away from us whether we suffer from mental illness or not. Many people exhibit the behavior in the article despite being of perfectly sound mind.

<comment><USER8> Certainly true as well.

</comment></comment></comment><comment><USER9> Nice article. For the last few years, I've had concerns that parts of economics have serious problems. But it's good to get a reminder of how to criticise well: points one and two (calm down, and don't be a dick) are particularly relevant to me.

For me, the stakes feel high enough that it's easy to get worked up and spit vitriol. But I've found that I'll lose the interest of anyone I'm talking to when I do.

<comment><USER10> You definitely don't want to come across as worked up or vitriolic. I would note that the guy who wrote this article is sometimes a tiny bit dickish though, check this article out:

[https://medium.com/@jamesheathers/long-hair-dont- care-5eeba2...](https://medium.com/@jamesheathers/long-hair-dont- care-5eeba266ec52)

Sample comments: _If that title leads you to expect off-brand evo psych exploring massive behavioural changes induced through the complicated medium of hairdressing… well, you'd be right._

Mmmm.

It's also worth bearing in mind your audience.

This article was written by two guys who by and large are going after junk science in psychology, nutrition, and so on, where the _worst_ motivation can only be to advance the careers of the scientists - and quite possibly the errors are just the result of over-optimism or lack of statistical abilities.

For that sort of work it makes sense to try and fix psychology from within, by pointing out errors. There isn't much point in trying to spread the word through the wider world that psychology is full of errors: what's the best outcome, exactly? A few people stop being invited to give TED talks? Big deal. Psychology isn't going to stop being studied, nor should it be!

But in the case of economics, there are two problems:

1) Economics is absolutely riddled with not just bad individual papers but entire sub-fields that are nonsense, it's an epidemic. It probably cannot be fixed by shaming individuals who make simple errors via their own journals and hoping for the field to improve. Even when major economists like Paul Krugman or Paul Romer have gone on very serious attacks against their own field, there has been no visible impact and in Romer's case he simply lost his job.

2) Economics is routinely used to justify massive government interventions (or lack of interventions) in markets and society. Bad economics research can have a very serious impact on people's lives.

In this case, it's probably better to work at a different level and try to spread the word amongst the general public that economics is not trustworthy. Thus the audience is not journals or the authors of the papers themselves. It's the public.

This is not hard because most people who follow the news have already encountered major cases where consensus economic predictions were simply wrong. Polling shows that trust in economists is quite low as is. If and when the field reforms it can try to rebuild trust.

</comment></comment><comment><USER11> I don't know how much I agree with the premise of this article. People aren't resistant to retracting faulty research because the people who point out faulty research sound like cranks, they do it because their incentives are to maintain the work they've done. If you look at someone like Brian Wansink[1], what started off as unearthing methodological errors seems to have found actual fraud, although I'm sure Wansink wouldn't view it that way. And this massive peer review process not only didn't discover it, it's been an impediment to correcting it. At stake are millions of dollars in federal funding and more than a few careers. Do you think anyone involved is primarily concerned with tone? And I'm not sure how effective anyone can be at combating it by working within a crooked and broken system, where extracting rents from academic institutions for publishing their own work is the main incentive for publishers, and academics are incentivized to go along because their careers depend on numbers of publications and citations. You may have a high success rate at combating individual errors, but you aren't making any headway on the bigger issues like publication bias and the overall trend away from long, important work and towards shorted studies designed to provide an eye-catching conclusion so that you can get published and cited. It's like bailing out a boat with a drinking cup. You're still sinking.

1) [https://slate.com/technology/2018/02/how-brian-wansink- forgo...](https://slate.com/technology/2018/02/how-brian-wansink-forgot-the- difference-between-science-and-marketing.html)

</comment><comment><USER12> Currently I'm trying to think of a way to get my father to read this without overtly telling him he needs to read this. Because that would be being a crank.

<comment><USER13> Open it on his computer and walk away

<comment><USER14> This is bad advice. I hope you only being funny.

</comment></comment></comment><comment><USER15> If we extended these rules to the internet, Facebook and Twitter would go out of business.

</comment><comment><USER16> I would use Andrew Gelman and John Ioannidis as prototypes for the Good Critic and Bad Critic, respectively.

Gelman does real, solid work and confines his righteous takedowns to a side hobby. And his criticisms are directed at individual, specific cases, with evidence, and he reserves most of his wrath for repeat offenders rather than one-off mistakes, which are unavoidable given enough projects. He confines criticisms to his area of expertise, which is statistics.

Ioannidis' claim to fame is writing a hand-waving, philosophical argument in order to cast doubt on all research at once. Followed up shortly by a paper that implied (but didn't directly state!) that regression to the mean on replication implies error or fabrication in the original. And he has ridden this sort of tired argument into a lucrative and prestigious career and Stanford appointment. Never mind the collateral damage on funding and morale. My theory is that people pay attention to Ioannidis and wring their hands about these highly generic issues for the same reason most people pretend to be highly, highly concerned about sexual harassment/discrimination in the workplace -- they're praying that if they act concerned enough, the hammer will fall somewhere else. But indiscriminate criticism like this is highly toxic to science (or anywhere else, for that matter, and has the side effect of letting real bad actors off the hook).

A further moral of the story is that, for better or worse, I don't trust and generally ignore criticisms that do not come from someone who has invested time into a field and made useful contributions to it. 'Full-time critics' strike me as generally sleazy and opportunistic, and I doubt the sincerity of their desire to 'improve' a field if all they can do is tear down others' work and not provide any of their own.

<comment><USER17> The fact that Ioannidis stakes his claim to fame as attacks on medical research is no evidence that he is a crank: it's evidence that medical research is a target-rich environment.

<comment><USER16> No doubt it is a target-rich environment. However, his arguments are so generic that they could apply to any field studying anything multifactorial or with high variance.

Fundamentally, however, I don't believe, for example, that physicists are more scrupulous/intelligent/honest than biologists, who are more so than psychologists. The irreproducibility rates in a field have to be primarily caused by the nature of the system studied in that field rather than some inherent attributes of the researchers.

So any field will have some constant level of irreproducibility which which essentially cannot be changed. But some researchers do better than others. My fundamental point is that if you want to change what can be changed, and genuinely improve a field, you have to focus the criticisms on specific bad actors rather than target an entire field at once and leverage a near- tautology (more complex systems yield more irreproducible results) into a 20-year tirade/career.

Also, helpfully for people like Ioannidis, a statement like "field X has lots of errors and irreproducibility" is non-falsifiable, and indeed will be true no matter what, so he is taking no risk with his criticisms -- even though they do more damage to public perception, morale, and funding, and help less to change things than targeted criticisms would do.

If I sound irritated by this sort of thing, it is because my graduate advisor dabbled in "meta-science" / "error correction" and I stoutly refused to have anything to do with those projects. I thought, and still think, that it is considerably more valuable to try to build my own solid lego tower despite the difficulties rather than knocking down other people's, despite the latter being considerably easier and a fairly simple and reliable route to a high citation count. In the end, irreproducible or erroneous papers in science just get ignored rather than retracted, and I think that's fine.

</comment></comment></comment><comment><USER10> I've also investigated bad science papers before, and blogged about it a few times. There's a lot out there. There's nothing special about getting a PhD that makes you politically neutral or morally superior. The temptation to abuse maths to make your personal views seem "scientific" is irresistible for too many. My last public attempt:

[https://blog.plan99.net/did-russian-bots-impact-brexit- ad66f...](https://blog.plan99.net/did-russian-bots-impact-brexit-ad66f08c014a)

I feel some sympathy with fellow Brit Nick Brown after reading this story about his work:

[https://www.theguardian.com/science/2014/jan/19/mathematics-...](https://www.theguardian.com/science/2014/jan/19/mathematics- of-happiness-debunked-nick-brown)

(as an aside, totally unsurprised the guy works in computing, developing an intolerance for abuse of logic is a job hazard.)

But I don't know if this perspective is helpful to be honest. "Don't be a dick" is both quite an obvious principle and also rather useless when criticising people's work: some of the authors, and some of the people who want to believe the research is true, will inevitably view any criticism as being dickish. This is doubly true if you take the obvious next step and speculate as to whether the issues are mere oversights or (far more commonly, in my view) deliberate deceptions intended to further an agenda.

One problem is that genuine, honest mistakes tend to get picked up already by the existing peer review process. The really bad papers that get through are usually bad in support of some wider social mission, usually leading the public to some policy goal, and they don't get struck down because the peer reviewers share the same goals. Thus pointing out mistakes has no effect, because they already knew the science was bad. The only thing that can work is pointing out to the people who they're trying to influence that something has gone wrong.

There _is_ a responsibility to be harsh in these cases. Failing to do so can simply let the issues fester and compound. From the Guardian article on Brown:

 _There were several psychologists, versed in non-linear dynamics, who smelt something fishy about the maths in the published paper. Stephen Guastello, from Marquette University, wrote a note of mild complaint to American Psychologist, which it chose not to publish because "there wasn't enough interest in the article". Guastello feels now that he should have been more forceful in his opinions. "In retrospect," he says, "I see how I could have been more clearly negative and less supportive of what looked like an article that could move the field forward if someone would follow up with some strong empirical work."_

The story describes Brown's first debunking of a paper that used lots of clever looking math to reach obviously absurd conclusions about psychology. One author of the paper admitted that she had never understood the maths and the person who did create the maths (Losada) has refused to ever respond to the debunking in any way. _All_ the reviewers were successfully intimidated by the maths and were unwilling to criticise it, allowing Losada to get away with it:

 _John Gottman, a leading authority in the psychology of successful relationships, wrote to Losada because he couldn 't follow the equations. "I thought it was something I didn't know about, because he's a smart guy, Losada. He never answered my email," he says._

So the critics weren't critical enough and a paper based on pure mathematical bullshit racked up 350 citations. Vast amounts of time, money and effort was wasted. What does this say about the scientific process?

By the way, in case anyone thinks computing is immune to this sort of thing, it's not. Papers about "Russian twitter bots" are a current streak of bad science in computing, for obvious reasons: the authors want to undermine political trends they don't like. The last one I read claimed to have constructed a neural network that could detect Russian bots with 99%+ accuracy. Nowhere in the paper did it give any examples of what the network detected, nor what the ground truth they were comparing to was. When I emailed the authors to ask for the data so the study could be replicated, I was told the data was not available (despite being just a bunch of tweets i.e. public data).

It was literally an entire paper that looked scientific but boiled down to "we made a magic black box that without fail finds evidence of a vast conspiracy, but we can't show you. Trust us."

<comment><USER18> I don't understand why this is being downvoted. It seems to be the most insightful, empirically grounded, high-effort comment in the thread.

<comment> shaki-dora When an article on how not be seen as a crank makes you want to post a long comment about your research into Russian bots, you should probably think again.

<comment><USER10> It's become a cliche, but that kind of low effort insult is exactly how people like Trump win. You can't argue your position so you resort to calling people who challenge you "cranks". The lazy assumptions that so often pervades these debates leads directly into over-enthusiastic trust of pseudo-science.

I've been out all evening, and my post is now at +11. But if it was getting downvoted I am 99% certain it's because a lot of people _really_ want to believe in the whole Russia/Trump/Twitter story and can't stand anything that challenges it, even incidentally. It meets their pre-existing biases and grants a feeling of moral and mental superiority: the _other_ tribe might be brainwashed by something as trivial as a retweet, but there's _no way I 'd be like that_.

But that's the whole point of this blog post we're discussing: lots of people have very, very strong incentives to believe in pseudo-science dressed up as the real thing. That doesn't just include scientists themselves but also journalists, politicians and so on.

The psychological paper that Nick Brown did a takedown of was cited by hundreds of papers and led to lucrative speaking careers. The underlying equations that made it seem like science vs mere opinion weren't connected to anything and boiled down to nonsense (a problem I've seen several times). Yet it took enormous efforts to do anything about it, and in the end the scientists who got caught are unrepentant: one of them didn't even bother to respond and the other agreed that the maths was nonsense but doesn't believe it really matters.

The same thing has happened repeatedly in recent years. See the story of Amy Cuddy: her 'power pose' research was thoroughly debunked but she simply refused to accept it, despite her co-authors accepting that the research was wrong. She continues to milk the speaking circuit and has even been cited by the BBC as an example of an "inspiring woman", although her career is arguably built on deception.

At this point, if you believe in Russian twitter bots influencing elections, why shouldn't you be the crank? Where is the evidence? All claims I've seen on this topic fall apart under examination. Even the premise is absurd - <USER2> relies on the belief that millions of people are so politically ungrounded their vote can be shifted merely by seeing a spammy retweet. That is a very dubious belief.

But if you believe you have a reliable study that proves the existence of armies of bots capable of swinging elections, please do show it. I will enjoy examining it. However, it is not sufficient to merely point at high-status individuals and delegate to them, because - as this entire discussion shows - bad "science" is capable of spreading and even becoming a consensus far too fast.

<comment> shaki-dora The article here is about the mistakes people make when trying to communicate their doubts in published science: how, _even when they are right_ , they can come across as "cranks" and easily dismissed.

I have no idea if you're right, and I'm not about to waste time down that particular rabbit hole. But you're arguably doing wrong everything the article mentions. Starting with the impulse of "hold on, I'm not a crank and here are 12 paragraphs and my blog to prove it". It's simply off topic in this discussion.

<comment><USER18> > But you're arguably doing wrong everything the article mentions. Starting > with the impulse of "hold on, I'm not a crank and here are 12 paragraphs and > my blog to prove it". It's simply off topic in this discussion.

I don't think it came across that way to most people. I'm a bit surprised you got that impression from it, and can't see how you'd read it that way. There's nothing in there about "I'm not a crank," for starters, and it didn't seem at all verbose.

</comment></comment></comment></comment></comment></comment><comment><USER19> I was struck by how every word of this could apply to how not to do politics and advocacy on social media. (Aside from the part where they actually advised taking all the terrible behavior to social media. It seems everyone is already doing that.)

<comment><USER18> You'd be surprised at how far people get simply by making it unpleasant and socially destructive to express certain views.

</comment></comment><comment><USER20> _Other would-be data whistleblowers are impressed by the duo's success in getting journals to act. Paul Brookes, of the University of Rochester Medical Center in New York, briefly used his now-defunct blog, science-fraud.org, to highlight questionable papers anonymously. Brookes, who was outed amid legal threats in 2013 after only 6 months, says he would "routinely write dozens of emails [to journal editors], and it was common to have no response at all."_

Quote from the Science article linked to in OA. I think the OA is useful in laying out a less confrontational approach to raising issues.

</comment><comment><USER21> This is great advice for information security professionals as well, especially vulnerability researchers and other appsec types!

</comment><comment><USER22> Cranks generally don't think they are cranks....

</comment><comment><USER23> the authors make some good points, but i have a different perspective when it comes to criticizing science.

1\. criticism is easy. penetrating criticism that demands an answer beyond the evidence already presented lest the criticized appear totally defeated is hard. it's also the only kind of criticism worth doing, imo.

2\. being listened to is a matter of having penetrating criticism and offering a reasonable alternative. if you destroy, you must offer a chance to rebuild afterward, or else the criticism will be too uncomfortable to respond to, and nobody will appear to listen as a result. if you are skeptical of this point (as you should be) refer to the position of string theory within the world of particle physics; its criticism of the mainstream is very difficult to recover from if accepted, and there's no real mental way forward as a result.

3\. it sucks to have your work criticized in public -- it's intolerable, even. but it sometimes gets results. it also sucks to have someone be impolite to you. but i am sure we can all remember a time that someone (perhaps a teacher or parent) has corrected us impolitely when we did not deserve courtesy. you need to retain the ability to dismiss cranks out of hand once you've suitably proven that you can beat them by making a diligent argument. anything else would lead to your time being wasted rehashing the same mistakes of others in detail.

4\. scientists are, very frequently, in their professional life, jerks. i am speaking from my own experiences and my own actions. the OP doesn't exactly brush on this, but sometimes being a jerk to the right people is what makes you the right friends. you don't really want to be friends with baddies anyway. this next point is super important and directly related.

5\. don't be a jerk to people because they produced incorrect work. often the theories that turn out to be totally wrong are the ones that move the field forward the most by virtue of the work put into disproving them. if they're fabricating data or doing things that are methodologically unforgivable, that's a different story.

6\. scientists are a stubborn lot, until they break in the face of evidence. if you are "right" and the world is "wrong," perpetually aggregating more evidence and showing it off will eventually work, especially if you make a point to summarize your findings every once in a while. this is just as true regarding criticism as it is regarding experimental results. here is a secret: if the subfield where you are directing your criticism has only made incremental progress for a long time -- which is to say, recently there have been no major breakthroughs or destructive revolutions which reshape prior understandings -- time is on the critic's side. incremental progress isn't stagnation, but it rarely adds enough evidence about fundamental assumptions to protect those assumptions from a sustained attack. if a field is making leaps and bounds forward, criticism is going to be shrugged off because there will be new understandings which are too juicy to slow down to refine. the later refining stages are where critics are the strongest.

</comment><comment><USER24> "And death threats (and trolling, and weird online gender-flavoured violence) are not just deeply unpleasant, they're CRIMES. If you do this, you are breaking the law AND being a shit human being, and you should either stop or walk yourself into the sun."

Death threats towards people that use death threats, really?

I don't like the article. Some people are more knowledgeable on a topic than others, "if you aren't in doubt you're probably wrong" doesn't apply there. Not even in general in my estimation.

A better alternative to "you have to sugarcoat all your thoughts by 30% before you speak them out" would be to train people to be better at taking criticism. People get spoiled by a high baseline positivity. I'd like to bring my points objectively without sugar coating, if everyone did that there would be no problem. Now i would have to either pretend to be more nice than i am ( talking behind people's back is a consequence of this), be straight to the point and get disliked by people who are used to sugar coating or keep silent. It usually boils down to the latter. Let me work alone if i can't be my critical self.

Also, this article seems to be mostly aimed at unfair criticism, let me pose the following.

If the criticism is fair and reasonable, it is justified, doesn't have to be nice, and the receiver is at fault if they dislike it.

If the criticism is not fair or reasonable, it is not justified, the criticizer should express uncertainty where applicable, they are at fault as the article suggests.

<comment> shaki-dora The article makes the point, quite explicitly, that you should not even call a vast conspiracy a "vast conspiracy". Not because it's "not PC", but simply because people on the receiving end of such diatribes have come to associate certain terms with cranks.

You can disregard such advise, and simply launch more and more over-the-top screeches against the MSM trying to silence you. But you're not going to change any minds.

<comment><USER24> What about using evidence instead of manipulating your point in order to convince people?

<comment> shaki-dora Yes, it would be great to live in a world where everyone would judge everything on its merits alone, like you do.

Unfortunately, we don't. Which is why we still put on pants for interviews, write in full sentences, and occasionally waste oxygen being nicer to others than warranted by the cold hard facts alone.

<comment><USER24> Well i do like warmth, just the genuine kind, not the politeness peer-pressure kind i feel is promoted in the article. Real warmth speaks from actions (patterns) and not from words, because words are forged too easily. An evil person could sugar coat twice as much and get a better job than their honest peer, hm? (virus scanners)

When you see through it you can choose to either exploit it or be fair. That's your call.</comment></comment></comment></comment></comment>


Ask HN: Where else do you get your news? - <AUTHOR> I think HN does a pretty good job at aggregating news that is interesting to me, but I'm looking to broaden where I get my news from. <comment><USER2> I quit news entirely. I only get my information about current events through headlines on Reddit and HN, which I avoid clicking. Or through conversation with colleagues and friends. Or through books.

I blocked all news sites on Facebook and unfollowed all friends who tend to spam links. I replaced them with topics of personal relevance and interest, or simply stuff that makes me feel good.

My life has improved dramatically since starting this news diet. I no longer carry this burden of disdain and frustration towards friends and family who support Trump. I no longer see the USA as a hellhole or the world as such a violent scary place. I no longer feel personally responsible for improving the world by starting arguments online or in-person. I don't get distracted as easily or waste quite as much time.

News is not making you smarter, happier, a better voter, anything. Most news is nothing but a series of facts that have been filtered and selected for their clickbaiting, enraging, shocking, fear-inducing powers (to show you ads). They have nothing to do with the world you yourself live in and experience every day. Quit news.

<comment><USER3> I did the same thing and encourage friends and family to do it too. News is generally presented as low-quality information that should be consumed as rarely as possible. Here are two good write ups on quitting the news:

[http://www.raptitude.com/2016/12/five-things-you-notice- when...](http://www.raptitude.com/2016/12/five-things-you-notice-when-you- quit-the-news/)

[http://www.dobelli.com/en/essays/news- diet/](http://www.dobelli.com/en/essays/news-diet/)

</comment></comment><comment><USER4> Legible News!

It's simple to read, and provide links to wherever necessary. No ads, just clean text.

[https://legiblenews.com/](https://legiblenews.com/)

</comment><comment><USER5> HN and podcasts. If its relevant, I usually pick it up from conversations in podcasts. Most of whats considered news these days is opinion pieces and people trying to predict what happens in the future and pretty much no one gets it right. News consumption outside your field/industry is counterproductive if one wants to live a positive stress free life.

</comment><comment><USER6> [https://en.wikipedia.org/wiki/Portal:Current_events](https://en.wikipedia.org/wiki/Portal:Current_events)

</comment><comment><USER7> I read through the economist, but only once a week.

<comment> Engineering-MD I find it summarises the important international political/economic changes with some critical analysis.

I prefer this type of journalism rather than constant updates, although I do use both.

</comment></comment><comment><USER8> It surprised me, but I've come to like the News app on iOS. A little bit of currating and adding subscriptions to The Economist and such and its become part of my morning news ritual.

</comment><comment><USER9> HN is awesome for that specific niche. Interestingly, I've been using twitter (exclusively) for global news, in addition to HN (tech news). It works pretty well and you get straight to the point. What made me switch is the amount of articles written around one single tweet every day.

It's crazy to see how journalists these days can create a whole story out of a 140 character message. I'd rather get the 140 original characters...

</comment><comment><USER10> Other sites with similar content to hn I visit weekly:

      https://lobste.rs/
      https://dzone.com/
      https://old.reddit.com/r/programming/
      https://hackernoon.com/
      https://www.oreilly.com/ideas
      https://blog.usejournal.com/

</comment><comment><USER11> I mostly get news from patch [1] as it is generally the only news that applies to me. News on HN sometimes applies to my career field, yet rarely ever applies directly to me.

[1] - [https://patch.com/](https://patch.com/)

<comment><USER12> _" Hello! Patch is currently unavailable in most European locations. We are working on a technical compliance solution, and hope to be able to provide our local journalism offerings to EU readers soon. —The Patch Team"_ :(

</comment></comment><comment><USER13> BBC Radio Four. (But "Today" is increasingly tedious with Humphries and Robinson).

The Economist.

The Financial Times.

The Guardian, The Independent, and The Telegraph.

</comment><comment><USER14> For a sane take on general news, I like Reuters. I think Google does a decent job of collecting headline news.

</comment><comment><USER15> Twitter can be nice once you curate some.

<comment><USER16> I'd like to second this.

Also make sure on Twitter you are using the "Lists" feature which is very important / keeps you sane.

As an example, for news on China I'll create 3 lists: China 1, China 2, China 3. I'd then fill each list with 15 ppl. Now each list is almost a mini news app in itself.

Surprisingly, I have found Russia Today and CGTN tv (the propaganda arm of Russia and China respectively) interesting at times. Russia Today has some truths to its reporting (and even good Western guest writers / reporters at times) ; CGTN does not and is mostly entertainment for me.

Also you can watch live Bloomberg TV on YouTube which is pretty cool.

</comment></comment><comment><USER17> New google news app works well for me.

</comment><comment><USER18> Keep in mind as always that if you aren't paying, you are the product.

<comment><USER19> That's not true. Even if you _are_ paying, you are still part of the product. Unless you have been given an explicit promise otherwise, most pay services are happily monetizing you the same as the free services.

<comment><USER18> "If you are not paying then you are the product" does not imply the negation "if you are paying then you are not the product." Only the contrapositive.

<comment><USER18> I have been leaning toward news that doesn't read you back (print newspapers). It is actually amazing how less inflammatory and clickbaity the paper is, even from the same news organizations.

Another obvious thing to keep in mind, look at the ads or the embedded ads to understand your fellow readers. E.g. is there outbrain/taboola stuff at the bottom, or ads for something a thoughtful person would be interested in?

</comment></comment></comment></comment><comment><USER20> I subscribe to two online news papers. One left-wing and one to the right.

<comment><USER21> Could you name them? Anyone else please do too the X-wing sites you think are worthwhile. It's intersting to see different points of view.

<comment><USER20> DN and ETC.

</comment></comment></comment><comment><USER22> NPR - I listen to All Things Considered and read articles on their website.</comment>


Eloquent JavaScript, The Annotated Version - <AUTHOR> https://docs.google.com/document/d/1aa2-HtUglQrAps31s4LdTPVsiFb1BxhyjZolxeezzcI/edit

<comment><AUTHOR> This is an annotated version of the second edition of [http://eloquentjavascript.net/](http://eloquentjavascript.net/).

There are two objectives for this project: (1) Add comments to make the text easier to understand. (2) Allow you to ask me questions using comments so you don't get stuck.

The big idea is that you'll be able to get through the book without any issues and understand everything on a very deep level. I've heard from too many people that the first few chapters have been smooth and then the middle to later chapters have been a struggle (which is a big shame). I want the entire book to be a smooth experience so that you can feel confident about JavaScript and can move on to bigger things.

My goal is to create a really useful and lasting resource that helps a ton of people. Please let me know what you think!

If you've struggled through parts of the book before, I'd love to hear about it so that I can spend more energy on the parts where you need it most.

I also posted this on Reddit and it's currently at the top of /r/learnjavascript if you'd like to see the discussion there. [http://www.reddit.com/r/learnjavascript/](http://www.reddit.com/r/learnjavascript/)

<comment><AUTHOR> Crap so if you open the file now you may get a message at the top of the page that says:

"Wow, this file is really popular! Some tools might be unavailable until the crowd clears. Try again. Dismiss."

This sucks because comments don't show when this happens, which is the whole point. Hopefully things will die down later and the comments will be visible again soon.

<comment><USER2> I think this won't change any time soon.

Take a look at Angular Announcements[1] released in November 2014. The warning message is still visible today. I think it's a bug or something because once your file get that warning message it remains forever.

[1] [https://docs.google.com/a/ideveloper.ro/presentation/d/1fE0P...](https://docs.google.com/a/ideveloper.ro/presentation/d/1fE0PW1FMlYU9Xhig_QIGF8Yk1ApVfQQvntEEi4GbCm8/preview?sle=true&slide=id.p)

<comment><AUTHOR> So if I add "/edit" to the link that you provided, the doc seems fine.

[https://docs.google.com/presentation/d/1fE0PW1FMlYU9Xhig_QIG...](https://docs.google.com/presentation/d/1fE0PW1FMlYU9Xhig_QIGF8Yk1ApVfQQvntEEi4GbCm8/edit)

I wonder if the bug you're seeing is something that is specific for Google slides in presentation mode.

</comment></comment></comment></comment><comment><USER3> People keep voting this up, even though the comments are broken. If you're just going to read the book, note that there's a better-formatted, interactive version at [http://eloquentjavascript.net](http://eloquentjavascript.net)

<comment><USER4> Just curios, did this guy asked for your permission to basically republish your book ?

<comment><USER5> The content of the book is specifically licensed Creative Commons and MIT. Therefore no permission is required as long as you follow the terms of the licensing agreement.

</comment></comment></comment><comment><USER6> I haven't been able to see the comments so I can't give feedback on that, but you should give proper credits to the book's author, Marijn Haverbeke and respect his choice of license, [http://creativecommons.org/licenses/by- nc/3.0/](http://creativecommons.org/licenses/by-nc/3.0/) (summary) and [http://creativecommons.org/licenses/by- nc/3.0/legalcode](http://creativecommons.org/licenses/by-nc/3.0/legalcode) (full license).

<comment><AUTHOR> Thanks for pointing this out. I've added Marijn Haverbeke's name to the top of the doc and also linked to the license.

</comment></comment><comment><USER7> It's a great and well written book already. I'm not sure how can you benefit from annotating it any further. It's important to accept that some books are aimed at a certain level and for people not quite there yet better alternatives exist [1]. There are also some topics that a book needs to just mention and not go into much details, because for a beginner the exact internals of TCP are not useful anyway.

[1] [http://jsbooks.revolunet.com/](http://jsbooks.revolunet.com/)

<comment><USER8> That's a nice resource, never saw that page before.

Just to clarify I'd say Eloquent JavaScript is a nice book, and definitely a beginners book. I say this because it seems you are saying the annotations could help "people not quite there".

</comment></comment><comment><USER9> I just bought this book last week and havent dove in yet. Bookmarking this page for future reference.

Can anyone suggest a JS book to read after this one, for someone thats not quite a beginner with programming but trying to improve their JS skill set?

<comment><USER10> Javascript Allongé [0] by Reg Braithwaite [1]

[0] [https://leanpub.com/javascript- allonge/read](https://leanpub.com/javascript-allonge/read)

[1] [https://news.ycombinator.com/user?id=raganwald](https://news.ycombinator.com/user?id=raganwald)

</comment></comment><comment><USER11> > "Below the surface of the machine, the program moves. Without effort, it > expands and contracts. In great harmony, electrons scatter and regroup. The > forms on the monitor are but ripples on the water. The essence stays > invisibly below."

Man, I hate reading stuff like this in technical books.

<comment><USER12> Me too. I already spend a lot of time reading to stay up on technology. I don't need crap like this wasting more of my time.

</comment></comment><comment><USER13> This would probably not be trivial, but perhaps it would be better to upload this to Github in Markdown format? Github would allow comments, suggested changes to the original text, version control, etc.

</comment><comment><USER14> Does anyone know the difference between the online version and the published version?

<comment><USER3> The published version has one bonus chapter. That's basically it (except for a few small mistakes that were caught after the thing went to print -- [http://eloquentjavascript.net/errata.html](http://eloquentjavascript.net/errata.html))

</comment></comment><comment><USER15> Is it only aimed at beginners?

<comment><USER4> Yes, if you already know JavaScript you can probably peak and chose what is interesting for you from the book. Check the actual book website [http://eloquentjavascript.net](http://eloquentjavascript.net)

<comment> atom-morgan I've always found it interesting that people say this book is targeted towards beginners. If this had been my first programming book, or one of my first, I know the chapters starting with functional programming would have really confused me.

I personally recommend this book after another more introductory level book on JS.</comment></comment></comment>


Engineering is the bottleneck in deep learning research - <AUTHOR> http://blog.dennybritz.com/2017/01/17/engineering-is-the-bottleneck-in-deep-learning-research/ <comment><USER2> After few years of research in DL I learned not to trust any single paper at all. 99% of DL papers are not scientific but rather 'hey guys, look this trick is our new awesome discovery'.

Also I learned to communicate with other teams and exchange with ideas proved by practices - this really helps.

To improve, I would suggest to publish whole setup, all the parameters used, the programming code, and publish either all the data or a reference to a large free data set (no MNIST anymore in papers, please).

<comment><USER3> > (no MNIST anymore in papers, please)

If you have a breakthrough in transfer learning then you will be able to very effectively demonstrate it with MNIST.

The race to the bottom is essentially over, but that doesn't mean MNIST can't be used to demonstrate learning.

Regarding setup and parameters. I hope AI researchers move toward something like pachyderm [[https://pachyderm.io](https://pachyderm.io)] -- providing a single docker image to completely replicate their work. However, I sincerely doubt that will happen. As "open" as research is the details are almost always obfuscated to prevent competition with the spin-out company (or other researchers).

<comment><USER4> How about unlocking access to ImageNet? Unless one has a .edu account, its overlords seem to ignore requests to access it. Mind you, it's relatively easy to social engineer access to it, but why should this be necessary? OpenAI and Google have both knocked it out of the park with easy access to datasets and examples.

But sadly, IMO at the amateur-level, TensorFlow considered harmful. I have repeatedly observed novices blow the thing up by starting from one of many of its amazing and fantastic teaching examples. It's not a question of the TensowFlow API, but rather of the engineering quality of its underlying engine, which kind of sucks. Nothing ruins an enthusiastic data scientist's day like a cryptic seg fault for no apparent reason whatsoever.

And I know they're working on it, but fer cryin' out loud, the API is great, and Google has the bottomless pockets to do a lot better than this. It's been over a year and I still see people throw their hands up in frustration trying to make use of the thing. Of course, Google has never been a customer-driven company, but if we don't want an AI Fall, methinks this needs to be fixed.

<comment><USER3> I agree. I think all reference datasets should be free and open source. Also, researchers shouldn't publish on datasets that _are not_ free and open source. That is a basic requirement for repeatability.

As far as the TensorFlow API is concerned. This may be a tradeoff between speed and robustness. In order to have every operation checked every time would certainly slow down the code for general use. Probably better how-to / setup / use guides are a better solution for this (unless it is a flat out bug).

</comment></comment></comment></comment><comment><USER5> Anecdotally, my master thesis on natural language processing was supposed to consist of first reproducing the results of an influential paper (back then) and then hopefully improving upon it by extending the model used.

The paper made it seem like they had been using a standard PCFG parser (which circulated in the research community at the time) to achieve their results. It turned out they hadn't and instead had written a custom one and in fact their results were not reproducible using the standard parser.

What was meant to be a timesaver in terms of engineering (using a standard parser instead of writing your own) turned out to be a massive time sink. It also turned out that by using a custom parser they had unintentionally diverted from a vanilla PCFG (probabilistic context free grammar), or in other words, some implementation details had led to a departure from the assumed underlying theoretical model.

</comment><comment><USER6> A lot of research depends on software written by researchers and yet writing software is not really supported or incentivised by academia. Organizations like the software sustainability institute in the UK ([http://software.ac.uk](http://software.ac.uk)) are lobbying to change this, with some success, but I guess it takes a long time to effect cultural change.

<comment><USER7> See also Artifact Evaluation, a process used in several PL/SE conferences that makes evaluation of code (and datasets/studies) an explicit step in the review process:

[http://evaluate.inf.usi.ch/artifacts](http://evaluate.inf.usi.ch/artifacts)

[http://www.artifact-eval.org/](http://www.artifact-eval.org/)

<comment><USER6> Hey thanks - I hadnt seen those before. Good stuff.

</comment></comment></comment><comment><USER8> Unfortunately CS is not as rigorous as some other academic fields.

I've been to 100+ colloquia in the physics dept at Cornell and I have never been at one that I felt was a waste of time or that the person should not belong there.

The CS department colloquium is a different story: yes I got to see Geoff Hinton before he became a celebrity but maybe half of the talks are awful.

<comment><USER4> IMO (to be fair, some) CS people became engineering bottlenecks the day the universities switched out teaching C/C++ for Java and Python (IMO the Why Not Zoidberg? of programming languages). Those who learned C/C++ anyway became my heroes.

I have sat through too many presentations obsessing on HW-level perf/W especially w/r to Deep Learning ASIC wannabes. Just writing one's code in C/C++ (and doing it well) guarantees at least a 2x improvement over Java and a 10-100x improvement over Python. I won't even bring up the computational coup that is CUDA.

But hey, let's base a mobile phone OS on Java and block low-level access to its GPU, that's a fantastic idea, right?

See also many experiences with data scientist and CS primadonnas dismissing low-level coding as "ops." I liken this to the Eloi dismissing the Morlocks as "the help."

<comment><USER9> wrong thread, take the best programming language fight elsewhere

<comment><USER4> It's not a best programming language fight. In my experiences in the industry, an enormous of amount of technical debt and operational inefficiency is accrued when someone ignorant of how machines and processors actually work (SIMD, cache, pipelines, threading, etc) is in a leadership position to dictate the toolset for solving problems.

This wasn't a noticeable issue until about a decade ago. But it is now and it continues to get worse IMO. The "programming language" bit is just one of its symptoms when the root cause is ignorance of practical computer architecture.

That said, the mentality of throwing all big data problems at Hadoop clusters with 4 year-old GPUs and flaky 10 gB interconnect (many of which could be solved _faster_ on one.big.modern.and.cheaper.machine(tm)) is working wonders for my Amazon stock so maybe I should just shut up and get rich?

</comment></comment></comment></comment><comment><USER10> Ah yes, the story of my master's ML thesis.

I had to select features from multiple papers in order to try and select the best ones with classification results to prove it.

A few problems included:

\- Incomplete/unavailable datasets (404 on some copyright pictures)

\- Features consisted on Math formulas and text descriptions (no code whatsoever)

\- Classifier names only (which framework did you use? parameter values?)

In the end i couldn't contribute as well, got instructions to save my work in a private repo despite being funded by an EU academical scholarship.

</comment><comment><USER11> Agreed. The tooling around deep learning is not as mature as the tooling around software development. There is a fair amount of engineering and grunt work needed to even get started, let alone build on others' research. A few problems from top of mind: \- Setup: Installing DL frameworks, Nvidia drivers and CUDA is an exercise in dependency hell. Trying to run someone's project, which has different dependencies than what you have is difficult to get right. Docker images [1] and nvidia-docker make this simple, but are still not the norm. \- Reproducibility: This is big as Denny mentions. Folks still use Github for sharing code. But DL pipelines need versioning of more than just code. It's code, environment, parameters, data and results. \- Sharing and collaboration: I've noticed that most collaboration on deep learning research, unlike software, happens only when the folks are co-located (e.g. part of the same school or company). This likely links back to reproducibility, but there are not many good tools for effective collaboration currently IMHO. [1] [https://github.com/floydhub/dl-docker](https://github.com/floydhub/dl-docker) (Disclaimer: I created this)

</comment><comment><USER12> Sorry to knock the post author off his high horse, but "just like you wouldn't want a highly trained surgeon spending several hours a day inputting patient data from paper forms." Highly trained surgeons _do_ spend several hours a day doing tedious paperwork.

As a researcher, I expect 50-90% of my time to be slogging through organizational and preparatory work.

<comment><USER13> They _do_, but they _shouldn't_. It's an inefficient allocation of skills and resources.

<comment><USER14> >It's an inefficient allocation of skills and resources

Is it? Maybe the paperwork is important for other members of the care team and the surgeon is the only one who is familiar enough with the surgery to fill out the forms. And, you can't reasonably be doing surgery round the clock.

</comment></comment></comment><comment><USER15> I agree with the central thesis: engineering is a huge bottleneck. I work for a FinTech company that is building novel machine learning models and this is our experience.

We've had a few machine learning experts working here for a couple of years, but recently brought in a software engineer with a passion for machine learning. He was able to, within a few months, streamline the data acquisition pipeline to the point where we could iterate on a new models in about 30 minutes, down from days. He accomplished this not just with better data but by building efficient in-memory data structures. It saves literally days of time per iteration because of disk I/O.

Before his work the training data versus the data we used in production had minor differences. Each new release required intensive manual verification to make sure that our model worked. Now we have much more certainty that the two match up.

Looking down on engineering problems is like a famous architect looking down on structural engineers. You're not gonna have a very good skyscraper if your foundation is shaky and ad-hoc.

</comment><comment><USER9> coming from the machine learning research community, i am in awe of the availability and relative ease-of-use of the deep learning frameworks. Rarely can i find comparison code in ML that i didn't have to bug the author for, or try and implement myself based on the paper alone. in short DL is on a much better path than the author realizes. Perhaps we have to thank the github/bitbucket era. The real problem with DL is that until there is a more robust theory(if even possible, the bane and boon of ML is the complexity of the models), much of the application research will sorta be a form of digital alchemy.

</comment><comment><USER16> Just yesterday, browsing the forum of kaggle, I thought that we may need a GitHub for Deep Learning...

So that you could link your code to a dataset, have it automatically run, and show the result...

Not sure if it is worth the time...

<comment><USER3> I think OpenAI is working on this with gym and universe.

[https://universe.openai.com](https://universe.openai.com)

[https://gym.openai.com](https://gym.openai.com)

A general dataset pool in OpenAI would be nice. Kaggle has quite a few just basic datasets (MNIST etc) for evaluation.

</comment></comment><comment><USER17> i was playing around with the emotion data set on kaggle using tensorflow. depending on the seed, i was getting between 58 and 60% accuracy on the hold out test set (what you submit against).

i thought i came up with a good set of hyper parameters using aws gpu instances (python 2.7). i wanted to visualize some of the outputs so I copied the code to my machine and ran under python 3.5 (windows) and only got 57% accuracy. these swings in accuracy are huge</comment>