Fast data processing engine written in C - <AUTHOR> https://github.com/x86-64/frozen

<comment><USER2> Looks interesting, but I am struggling to figure out what it actually does. Some concrete example output in the tutorials would help.

<comment><USER3> Same here - I'd suggest moving the design justification to a separate page and having the project home page start with a less-than-10-line usage example of something useful you can do with it.

<comment><USER4> The thing I found interesting is its flexibility. A list of planned/implemented modules might be helpful. Once you understand that Frozen just chains together small programs (modules) that process streams of data you can start to think of all sorts of interesting applications.

Of course that sounds a lot like Unix. What can Frozen do that a series of chained programs can't? A self-documenting config file may be better than a bash script, for one.

<comment><USER5> I like the idea. Unix pipes are very limited though.

Something like this but using, say, ZeroMQ could be really interesting. Mongrel2 could be the HTTP server in such a system, etc.

</comment></comment></comment></comment><comment><USER6> Interesting. This reminds me of a product I used to work on. It is a node design. Nodes can be plugged together to normalise and aggregate trade data.

I'd be interested in contributing to your project, starting with working on the docs. If interested, please contact me. I'm at gmail, username cratuki.

<comment><AUTHOR> Feel free to fork it on github and make contributions. To avoid double work, check out TODO file - top items have first priority and would be done very soon.

</comment></comment><comment><USER7> _To setup a web server we need to install many different components: database, server, may be some cache, balancer, fastcgi handlers and so on. And every part must be connected somehow. But any connection introduce significant latency and limit performance of overall system. So, if there is only one physical machine, why bother with it? Lets join all components to one process. Simple call within process is best avaliable to world communication channel, it is fast and simple._

So, what happens when you need to scale it to more than one machine?

<comment><AUTHOR> Depends on what you scaling. Actually there is no borders in such approach. If you app overloaded with template parsing you could move it to another machine, if problem in "database" thing same solutions came as for NoSQL. There is no limit what to scale and how. You could have everything in one process exept something that need scaling and this would be more efficient than dividing things on databases, cgi and balancers.

<comment><USER8> What makes you think that IPC is the dominating cost?? It's usually network or disk bandwidth, not IPC. And once you scale past one machine, you can't avoid network chatter by definition.

<comment><AUTHOR> All this is not only about ipc. Removing some ipc will give a little speed-up in latency - nice bonus, nothing more.

</comment></comment></comment></comment><comment><USER9> After reading through the source code, I'm no closer to figuring out how this is different to plugging functions, classes or external libraries together.

Can someone describe what makes this library different to a standard utility library?

<comment><AUTHOR> In case of using it as library - if you write some application you use different api to make things work, for example call api to write info into file. But, if you face with scaling or other problems in most cases you need to rewrite code of your application, for example set up buffer before writing to file. If you use frozen you can define format in which you dump info to it and stop touching code and binaries of your application at all. Quick changes in configuration file to add buffer, or write into memory, or flush info by network and everything is working.

</comment></comment><comment><USER10> Sorry to be a bother, but the title of the section should be "Rationale" and not "Rational"

...just a pet peeve of mine. :p

<comment><AUTHOR> Fixed. Thanks. English is not my first language, i'm sure there is a lot more bugs than this one.

</comment></comment><comment><USER11> is there a project you have used this for?

<comment><AUTHOR> Plan to use in web project with huge data sets (domains, whois, dns, traceroutes). Now i collect data with crawler and writing this.

<comment><USER11> hmm, given that this is a kind of toolkit... would love to see an real-world example app to go with your product. that way i can figure out what purpose it's right for.

</comment></comment></comment><comment><USER12> What does it offer compared to memcached, redis, leveldb, etc.?

<comment><AUTHOR> Sorry, but for now - nothing. There is a lot of work to do, especially in caching and indexing. Try to do it as fast as i can.

<comment><USER12> Best of luck with your project then!

</comment></comment></comment><comment><USER13> Seems like a half-assed scripting language. Another example of over- engineering gone awry.</comment>


I can't keep up with idiomatic Rust - <AUTHOR> https://timidger.github.io/posts/i-cant-keep-up-with-idiomatic-rust/ <comment><USER3> Rust seems to change constantly, because _it 's changing so slowly_. The 1.0 release has held back a lot of stuff to avoid stabilizing wrong things, and it's now slowly backfilling the missing features bit by bit.

Instead of starting with a fat standard library, it started with minimal one and now each release adds 2-3 functions that could have been there in 2015. But none of it is idiom-changing revolution. These are mostly convenience functions, and you don't have to use them all just because they're there.

Every addition to the language is bikeshedded to death, goes through betas, revisions, refinements, before being stabilized _years later_. The first experimental release of async was _4 years ago_ and it has landed last November. So you may hear about new features a lot and they churn in nightlies, but actual big changes reach stable rarely.

Apart from async/await, since 2015 Rust made only 2 changes to how idiomatic code looks like (? for errors, and 2018 modules), and both of them can be applied to code automatically. I maintain over 60 Rust crates, some of them as old as Rust itself. All work fine as they are, and running `cargo fix` once was enough to keep them looking idiomatic.

<comment><USER4> > it's now slowly backfilling the missing features bit by bit

This isn't slow.

Java went three years, from December 1998 to February 2002, without any language changes. And to be honest, even that wasn't that slow!

> Every addition to the language is bikeshedded to death

Not to death, because many of them don't die!

What i find annoying about Rust's changes is that some of them are so trivial - they change the language for such small improvements. async/await is not in that category, for sure. But Ok-wrapping actually is. The need to Ok-wrap results is a minor annoyance at most. Ditto a bunch of the problems solved by match ergonomics changes.

I think the root of the problem is that the changes are driven by a small core of Rust programmers - many working on Rust itself or some of its flagship projects - who are actively involved in the discussions around Rust. They tend to view change as natural, and the cost of change as low. I believe there is a larger group of Rust programmers who are not actively involved in these discussions, and are maybe not spending 100% of their time on Rust, for who the cost is higher. But we don't hear as much from them.

<comment><USER5> > What i find annoying about Rust's changes is that some of them are so > trivial - they change the language for such small improvements. async/await > is not in that category, for sure. But Ok-wrapping actually is. The need to > Ok-wrap results is a minor annoyance at most. Ditto a bunch of the problems > solved by match ergonomics changes.

So what? Then don't use them. The whole point of full backward compatibility is that you don't have to use new features. This perceived need to always use the newest feature is only in the head of some developers.

Neither in the blog post nor here do I see any reason to not make the experience better for people who want it. Even if it's just a "minor" (very subjective, I love the match ergonomics enhancements) annoyance that's fixed by it.

<comment><USER6> You still have to understand all the new stuff to read other people's code. And the old way, so you can read older code. And if there are other ways to do something that are or have recently been in common use, those too. You end up memorizing a bunch of crap for one actual operation.

<comment><USER7> Yep.

I think ruby (which in general I still love) has become a major offender of this. "If you don't like it don't use it" is not a good answer for exactly the reasons you explain.

<comment><USER5> I sense a goalpost moving here. The point of the blog post to which I answered to was: I have to redo all my programs to follow the "idiomatic" way.

Now we are at "other programmers could use new features, so I still have to learn them". And yes, that is true. And that will always be true as long as a language has new releases. Even if all those releases were library changes and not syntax changes/additions. The only way to stop this would be to stop all language development.

<comment><USER8> Even worse would be if someone pulled in a library... That requires much more cognitive load and doc-reading than something like try! -> ?

Or the worst of all possible worlds -- pulling in a macro-based framework

</comment></comment></comment></comment></comment></comment></comment><comment><USER9> I spent today updating some production Rust code from 2016. This was a partly automated process thanks to 'cargo fix'.

Some thoughts:

1\. Most of the superficial changes, like 'dyn' and Rust 2018, are easily handled using automatic tools.

2\. The original Rust 'Error' trait was clunky, and it lacked useful features like backtrace support. This led to a series of experiments and fads in error handling (e.g., error-chain, failure), which are only starting to calm down after recent enhancements to 'Error'. More conservative Rust users avoided this by sticking with 'Error' and living with the limitations.

3\. Updating depencies has been surprisingly easy, with several notable exceptions. Very early adopters of 'tokio' 0.1 had a fair bit of work to do once 'async' stabilized. And OpenSSL has been a constant thorn in my side, despite being a native C dependency.

One handy tip: Don't force yourself to constantly update your code to use all the latest features. Not everything needs to be async. And it's OK to have some rarely-touched modules that are written like it's 2015.

<comment><USER10> As someone newer to Rust who has been using error-chain because it was what I found at the time I'd be curious to hear what your preferred solution to errors in modern rust is.

<comment><USER11> [https://blog.yoshuawuyts.com/error-handling- survey/](https://blog.yoshuawuyts.com/error-handling-survey/) is a good summary of what's out there.

I think current rough consensus is anyhow/thiserr depending on if you're writing an application or library. I haven't actually used them myself, though. You don't _have_ to keep up with the cool new libraries.

<comment><USER12> Agree that there's consensus on anyhow for applications, but I think many folks now prefer vanilla std::error::Error for libraries (which itself got better as a result of all the experiments in the ecosystem).

<comment><USER13> The good thing with _this_error_ is that it's just a custom derive on vanilla std::error::Error.

<comment><USER14> I used to maintain a custom derive crate for errors before failure came out, but these days I just use manual impls of `std::error::Error` for libraries and `Box<dyn std::error::Error>` for applications. I can't be bothered to keep up with the Rust error-library-du-jour game, even if it so happens that today's darling custom derive (thiserror) would emit the same `std::error::Error` impl that I write by hand.

Manual impls may be tedious to write, but they change rarely after they've been written, enough that the con of adding one more dependency that may go away tomorrow outweighs the con of writing them manually.

<comment><USER15> This matches my experience as well. I want to write code that works for years (dependencies make this hard) and is understood by everyone. So explicit is best.

</comment></comment></comment></comment></comment></comment></comment><comment><USER16> I feel that the changes to date haven't been that significant. Adding `dyn` was almost completely automated, removing the need for `extern crate` was welcome and very easy to apply, likewise `try!()` to `?`. The changes to futures were a bit of a pain but futures were always known to be in flux. `impl Trait` is useful but failing to use it where you could is not ugly enough to irritate.

There are some upcoming improvements --- that I'd like to see! --- that are bigger and thus may be more challenging:

\-- Better `const fn` will make many existing `lazy_static`s become unidiomatic. Worth it, but annoying.

\-- Const generics will make a lot of existing code non-idiomatic. Again, well worth it, but annoying.

\-- Generic Associated Types ... probably similar.

The question is, if people decided those important features don't belong in Rust because they would cause too much churn in code that wants to be idiomatic ... then what? That would almost guarantee a new language --- perhaps a fork of Rust, perhaps not --- would eventually fill that niche. Wouldn't everyone be better off if that language was Rust itself, and people who don't want to write that "modern code" ... don't?

<comment><USER17> async is huge, and I'm worried about future similar changes.

Suddenly "x.y" means member access.. except for x.await, which has a magic different meaning I still don't really understand. And adding 'await' to a function declaration magicly mangles it in various ways.

<comment><USER16> Honestly I haven't found those things to be problems at all. ".await" really isn't confusing. I think you meant "adding 'async'" to a function declaration --- it seems fine, but I personally don't use it.

<comment><USER17> The .await is another thing one needs to teach, and fairly early on so that people reading code examples don't get confused by where the "await" member of structures are. It just seems like a really bizarre break in what was fairly clean notation.

<comment><USER18> For me, it helps that ".await" appears as a keyword because of syntax highlighting. It _is_ an odd syntax, but the alternative way of making await a prefix operator instead of a postfix operator would have been way worse for readability. Compare

      let bar = list_foos().await.first().list_bars().await.first();

vs.

      let bar = (await (await list_foos()).first().list_bars()).first();

</comment></comment></comment></comment></comment><comment><USER19> This a key difference between the Go community and the Rust community. Go is like C 2.0: it tries to be minimal and stable. Go usually ships with no language changes between releases. Rust is like C++ 2.0: it is constantly being revised and expanded, supposedly to improve power, performance, and ergonomics. When a new version of Rust is released, the core Rust devs write a blog post gleefully explaining all the new "features" the current version has. What these devs perhaps fail to appreciate is that not having new features can itself be a feature.

<comment><USER20> IMO Go is more like C people took a stab at making a Java. I really like go, and it's ethos, even if I haven't used it much in production. Go is not however a replacement for C in the way C++ and Rust can be. Of course Rust and C++ aren't a replacement for C in some key ways, so maybe I don't have a point here?

<comment><USER21> >IMO Go is more like C people took a stab at making a Java.

I haven't used Go beyond tutorials and some very basic programs, but I am pretty comfortable with Java. What about Go makes you feel it's relatable to Java? From what I've read the lack of generics is a hot topic in the Go community, but they're pretty crucial to most programs written in Java. Is this still true?

<comment><USER22> As a side note, Java also didn't ship with generics. Java was released in the mid 90s and didn't have generics until about 10 years later with version 5. This timing should feel familiar - Go first appeared ~10 years ago in 2009.

You may remember that in Java 1.4, `get`ting from collections (e.g. ArrayList) always returned Object, which you were expected to cast to their runtime type (or a class that their runtime type inherits from). I was young at the time, correct me if I'm wrong. Contrast this with Go's solution, which seems to be user-inaccessible compiler magic. I much prefer Go's solution to Java's, but I also like generics.

<comment><USER23> I _really_ hate user-inaccessible compiler magic. Java had its fair share of that, but Go seems to take it even further :(

<comment><USER20> I think compiler magic is pretty great. Hotspot is a pretty magical compiler. Go is less magical IMO because it is AOT compiled.

<comment><USER23> By compiler magic I really mean syntax reserved to the language itself; for example, Java's String having extra operator superpowers or Go's generics that are only available to a chosen set of standard collections.

</comment></comment></comment></comment></comment></comment></comment><comment><USER24> > The .await war was the final straw [...]

Interesting. I witnessed a constructive collaboration by which the Rust community chose (mainly) the syntax for it's async features. I thought of it as amazing, thoughtful, rather democratic and on point. Nothing war-like to me.

<comment><USER25> To be honest, reading mainly blog posts, RFCs and summarisation comments, it did look like a thoughtful and organised process. However, there has been a constant problem of tiresome work and "intellectual and emotional labour" of reading thousands pieces of feedback, some of which are emotionally charged, and many of which are duplicates or re-statements of similar ideas, and many of which have misunderstanding or mis-valuations of other ideas. I've heard that collecting and editing this huge amount of unstructured feedback into comprehensive and balanced summaries has been a huge drain of mental energy for the participants.

<comment><USER26> I wasn't involved at all in the discussion, but having dove deep into async over the past few months since async/await was stabilized, I definitely am happy with the result of that process. Writing code with postfix `.await` feels very natural to me and it fits it much better with the surrounding code I write than a prefix version would. I can sympathize that participating in that process might not have been fun, but I really hope that the results of future discussions make me as happy as this one has.

<comment><USER27> > Writing code with postfix `.await` feels very natural to me and it fits it > much better with the surrounding code I write than a prefix version would.

That's your subjective point of view, not everyone agrees with it. Part of the problem is that Rust team failed to find a solution good enough for the most people and failed to communicate this decision. In particular the switch to .await syntax happened just couple weeks before it was finally stabilized.

And await is not the only controversial decision made by the Rust team.

Even if 10% of people unhappy that's too much, because the next controversial feature will cause 10% more of unhappy people and so on.

I hope they will do better next time.

<comment><USER28> > Even if 10% of people unhappy that's too much

You realize this is an impossible standard, right? Literally impossible.

<comment><USER27> I might be wrong but for C++ for example every C++ fan seems to happy about every new release (at least happy with new features, not lack of desired new features).

Same for Java, IIRC the only controversial decision they made was the introduction of modules.

Python 3 was a mistake, but generally Python users are happy with Python changes.

10% is not impossible. Even if this decision is "right", communication could be better: more options to play with different syntaxes, more time to get used to new syntax before stabilizing are just two possible ways to deal with the angry mob.

<comment><USER29> How often is C++ adding features of that size though?

<comment><USER30> Major new features of this size in C++11 are lambdas, variadic templates, auto, and move references. C++14 adds generic lambdas. C++17 adds constexpr if and structured bindings. C++20 adds concepts, coroutines, and modules.

</comment></comment></comment></comment></comment></comment></comment></comment><comment><USER31> > I need to now change my code in order to keep it idiomatic

I'm not a Rust person so maybe I'm missing something, but why does the OP need to keep the code idiomatic? Can't the changing fashions in what's idiomatic be ignored?

<comment><USER32> > _Can 't the changing fashions in what's idiomatic be ignored?_

They absolutely can, but you might be stuck on an older "edition" of Rust. I've stuck with `try!()` for error-handling, because I think error-handling deserves more prominence than a single character. But that means my code is stuck on Rust 2015. If something I need is added to Rust 2018 or a later edition, I'll be forced to update or backport.

<comment><USER33> > But that means my code is stuck on Rust 2015.

...can't you upgrade and choose not to make that change? Did something happen to make that not compile?

(not a Rust user)

<comment><USER32> > _Did something happen to make that not compile?_

`try` became a reserved keyword in Rust 2018 and the `try!()` macro was dropped (edit: not dropped, see @boardwaalk's comment). I could copy the old macro to all of my code bases and give it a new name. The two things stopping me from doing that are (1) I don't have any reason to update to Rust 2018, and (2) I can't think of a good name for a replacement macro. I'm thinking `check!()`, but not sold on the name.

> _(not a Rust user)_

One thing to know about Rust 2015 vs 2018 vs future "editions" is that they're a distinct versioning mechanism from Rust 1.23, 1.24, etc. The latest version of the Rust compiler still supports Rust 2015 and I believe it's been promised to be supported in perpetuity. So it's not like I run a risk of being without a Rust 2015 compiler available.

<comment><USER18> > I can't think of a good name for a replacement macro

What about do_or_do_not!(). After all, there is no try!(). ;)

<comment><USER32> Heh. That's the argument that was made against using Rails' `try()` method at my last place of work. Made me laugh. Thanks. :)

</comment></comment></comment></comment></comment></comment><comment><USER34> I'm getting seriously concerned about feature-creep in Rust. I understand that there was an initial period of rapid growth as the community figured out what was needed, and that some of Rust's syntax sugar makes a very real difference in productivity.

But Rust is already not a simple language. It already has long compile times, and some of its syntax sugar already makes it harder to understand what's really going on when you invoke it. I think it's important that the Rust community start reeling in frivolous sugar, otherwise it may just become C++ all over again.

<comment> Ar-Curunir Can you name some examples of "frivolous sugar"? Also compile times have been a big focus of the compiler team, and have been going down YoY.

<comment><USER34> > Can you name some examples of "frivolous sugar"?

The one mentioned in the article seemed fairly frivolous to me. I don't know if I can name one that's already been accepted into the language which I would call _frivolous_ , per se, though they're all varying degrees of necessary. But most of the "sugar" syntaxes have made the language harder to understand for newcomers, even the ones that are arguably necessary. They all come with a cost.

The ? syntax for Results, for example, rubs me the wrong way a little bit. In that case it really does eliminate a large amount of code and is probably worth the trade-off. But now instead of Results just being a monad that can be picked apart like any other data structure, they become a Language Feature that gets special, magical treatment not expressible by the type system. You just have to _know_ what the question mark translates to underneath. Worthwhile or not, this makes me sad. Async/await is a similar case.

> Also compile times have been a big focus of the compiler team, and have been > going down YoY.

Yes but adding complexity to the language immutably increases the difficulty of that task. Even if only by a little bit, it adds debt that will have to be reckoned with for the rest of the language's lifetime.

<comment><USER35> > But now instead of Results just being a monad that can be picked apart like > any other data structure, they become a Language Feature that gets special, > magical treatment not expressible by the type system.

I believe, but please correct me if I'm wrong, that the try operator (`?`) does nothing which lies outside of the type system. It just transforms

      let v = expr?;

into

      let v = match expr {
          Ok(v) => v,
          Err(e) => return Err(e.into()),
      };

<comment><USER36> '?' is an almost completely useless language feature IMO.

The second block is much clearer and uniform. When reading the first you implicitly read it as the second, which introduces mental overhead.

The only upside of having '?' is to write less code, which is the worst kind of syntactic sugar: It makes the writer type less for a couple of seconds, but the result is harder to read.

Now even if one doesn't agree with the above it is still a bad feature. Why? Because the upside of it just doesn't outweigh the cost of having _any_ syntactic language feature like this.

And I don't just mean the energy invested in introducing it into Rust, but also the continuous cost of having to deal and respect it in future changes.

This is a bad case of hyper-optimization within a very narrow scope combined with bikeshedding.

<comment> Ar-Curunir I'm not sure how much Rust code you've actually written, but almost uniformly everyone in the Rust community prefers ? to try! and the explicit designating that you suggest. The fact that other languages are adopting this [1] suggests that your preference is not the popular one.

And I'm pretty sure there isn't "continuous energy" being invested in supporting this. It's primarily a one and done feature...

[1] See for example [https://news.ycombinator.com/item?id=20804247](https://news.ycombinator.com/item?id=20804247)

<comment><USER36> I made it very clear that this is my personal opinion. I'm aware of the fact that the feature made it into the language, because it had widespread support.

I still don't think it is a good feature.

> I'm not sure how much Rust code you've actually written

Only as much as someone who finds time on the side to learn the language. There are many things that make this process nice, for example the compiler messages, clippy, traits, the functional API on iterators and so on.

But I've read substantially more code than I wrote. And as I stated the ? operator seems to be primarily a feature that makes writing more convenient. Not easier, not clearer, just shorter.

The pattern matching syntax expresses what it does very clearly and explicitly in a nice, tree branching like structure. And it is also documenting the code more directly.

Again, even if you and "almost uniformly everyone" disagrees with this. There is still the more general point of: How useful does a feature need to be to be considered _at all_? "Most people find it nicer to write" is in my opinion too weak.

> And I'm pretty sure there isn't "continuous energy" being invested in > supporting this. It's primarily a one and done feature...

To be frank I find this to be shortsighted. Every syntactic feature adds baggage, that has to be dealt with continuously on _some_ level. The feature already was limiting the syntactic possibilities of async/await for example, which is in my opinion a much more important and impactful feature. This is the kind of evolution that is painful to see, especially since this is a repeating pattern with evolving languages.

I like, even admire a lot of things about the language but I feel the weak point of Rust is its syntax. Especially for such a young language there are already too many ways to express the same thing. And this might be the fundamental point where we disagree.

</comment></comment></comment></comment></comment></comment></comment><comment><USER37> Not really going to address the rest of the post but I wanted to point out that `impl Trait` hasn't really changed what's idiomatic. People still use generics in argument position, and while I've seen a couple instances of people using impl Trait in argument position it's not enough to call it an idiom shift.

impl Trait in return position has changed how people code; but that's because it made certain things suddenly possible, which isn't an idiom change as much as obsoleting some old bad workarounds.

I'm curious to know why you felt like you had to change your code to be more idiomatic with impl Trait.

\----

Nor does it seem like Ok wrapping is the kind of feature that would change what idiomatic Rust is.

<comment> Ar-Curunir This is an anecdote, but I'm someone who keeps up rather zealously with language updates, and even though I write a lot of generic-heavy code, I don't think my code contains a single instance of `impl Trait` in either argument or return position, across over 60,000 lines of rust code

<comment><USER38> I guess that depends on how you code.

Do you ever write code that returns, e.g., an `Iterator` ? e.g.

        fn my_map<T: Mul, I: Iter<Item=T>>(it: I, x: T) -> impl Iterator<Item=T> {
            it.map(|i| i * x)
        }

`impl Trait` in return position is the only way to write that kind of code, because you can't name closures. You can workaround this by re-implementing a custom `Map` iterator... Or if you are dealing with `Future`s, by writing a new custom `Future` type, but with `impl Trait`, you don't need to.

I use it a lot. What before required a lot of boilerplate, now is a one liner.

<comment><USER37> I address this in the second paragraph:

> impl Trait in return position has changed how people code; but that's > because it made certain things suddenly possible, which isn't an idiom > change as much as obsoleting some old bad workarounds.

this isn't a new idiom. this is code that wasn't possible before suddenly becoming possible, and people using it.

</comment></comment></comment></comment><comment><USER39> ,,The .await war was the final straw to make me stop watching the Rust community beyond what comes in the release notes.''

Regards the error checking syntax the article may be right, but as far as I saw, the await addition to Rust went perfect: it became stable when the decision was made (also a state of the art memory model was created for async calls), and nobody had to use it (or even follow it) before that.

<comment><USER40> Can you provide any links on references to a memory model for async calls, I would be interested in reading them.

<comment><USER39> I was referring to the fact that it is the only async implementation that I know of that compiles to a state machine that doesn't need to allocate new memory for each continuation. I think it will translate to extremely fast web services in practice.

Pinning is of course part of the elegant solution. There are some great videos about it:

[https://www.youtube.com/watch?v=lJ3NC-R3gSI&t=1710s](https://www.youtube.com/watch?v=lJ3NC-R3gSI&t=1710s)

[https://www.youtube.com/watch?v=skos4B5x7qE](https://www.youtube.com/watch?v=skos4B5x7qE)

<comment><USER18> > I think it will translate to extremely fast web services in practice.

In practice, it's probably not going to matter all that much because the average web service does way more time-expensive things like disk IO or SQL queries. The more significant effect is that async-await being really really fast enables you to use it in more places. For example, if you have a tight computation loop where different aspects of the logic are meshed together in a hard-to-read way, now you could try detangling it into several async actors talking to each other to make it more readable, without utterly destroying the performance characteristics.

</comment></comment></comment></comment><comment><USER41> Not sure I agree there. The language progresses with features that OP himself says he likes, and he also says that they DO maintain backwards compatibility, what more to ask for?

The author would be better or revisiting their code on a more relaxed cycle, for example every 18 weeks. Or whatever works for them, or just let go of the need to be using 100% of the latest best practices.

</comment><comment><USER42> One of the main features I look for in a language is stability. I just don't want it to change that much other than adding functionality to the standard library.

I know that's not the fashion currently, but it's probably one of the most valuable things to me.

<comment><USER43> Have you used Rust? Rust has made a strong guarantee to always be backward compatible.

We don't want dead languages, look at Java. It was stagnant for a long time, but has now shifted to a better delivery methodology of new language features. Rust is the same and continues to improve. Continues to make things easier and better to use without giving up its speed and low overhead goals.

<comment><USER44> Why does a language need changes to be alive? We don't ship languages, we ship code written in them. It's like claiming wood is dead because we have vinyl.

<comment><USER45> The comment you're replying to gave a good example - the history of Java.

If you're shipping code and modified code, you care about the language in which you can make those modifications. A frozen language means that either those modifications are harder (because potential improvements to the language are ignored) or they require writing components in an entirely new language and figuring out interop.

(If you're not shipping modified code, then you don't care if the language changes after you ship, anyway. You shipped, and then you're done.)

<comment><USER46> > A frozen language means that either those modifications are harder

I don't agree that it's harder. What is definitely harder is not being able to ship bug-fixes or modifications without ripping everything up because the language has moved on since your last release. And that is very common when developing for, as an example, iOS, since Swift is a fast-moving language that doesn't maintain backwards compatibility. The benefits of having some new language feature in Swift are far outweighed by the downside of existing codebases being invalidated. The various languages in the Javascript family suffer from this as well. The Python 2 -> Python 3 debacle was another example of this.

I have dusted off 20 year old Java code which compiled and ran just fine just fine. That is extraordinarily valuable to me, and requires a lot of discipline by the language maintainers. In fact, the new faster pace of Java iteration could be its downfall, time will tell.

A last note: how many language features from the past 20 years _really_ matter? How many really speed up development, improve maintainability, etc. I would say that there are very few. In fact, perhaps the only one that passes that bar might be async/await type threading advancements.

<comment><USER45> Yeah, there's a big difference when you're targeting platforms (iOS apparently and to a lesser extent the web) that move. But if you're writing Python, Python 2 works better today than it did five years ago. The most recent Python 2-compatible version of every library that existed five years ago works at least as well as it did then, if not better.

People move to Python 3 not because Python 2 is unusable - it was perfectly usable five years ago and the bits haven't disappeared from our world - <USER2> because there's lots of small things that make development easier, faster, more pleasant, and more robust. I don't think there's any single feature you can point to, but there have certainly been countless little things where, when I work on a Python 2 codebase these days, I say "I wish this were Python 3."

Anyway, Rust in particular committed to indefinite backwards compatibility when they released 1.0, and the "epochs" system has been a good (post-1.0) implementation of this. They realized they wanted some keywords that they didn't reserve, some syntax that they didn't define, etc., so they said there are two epochs, 2015 and 2018. The compiler handles both, but the newer syntax only works in the 2018 epoch. If you have code that was written pre-2018, it'll keep working indefinitely, even with new compilers.

</comment></comment></comment></comment></comment></comment><comment><USER11> I've been meaning to write a blog post on this topic. Maybe I'll do it tomorrow. But, I've been thinking about this question too, or at least a related one: how many new features does Rust get, and how often does it get them? I'd like to bring some data to this discussion.

In 2019, we had eight releases: 1.32 to 1.40.

\- 1.32: one language adjustment, finishing off previous module work

\- 1.33: const fn can do a few more things

\- 1.34: you can do a bit more with procedural macros

\- 1.35: a few minor details around closures

\- 1.36: NLL comes to Rust 2015. Not really a new feature so much as backporting it to an older edition.

\- 1.37: you can #[repr(align(N))] on enums

\- 1.38: no real language changes

\- 1.39: async fn! some adjustments to match. Some more borrow checker adjustments.

\- 1.40: #[non_exhaustive]. The 1.39 borrow checker adjustments are ported to an older edition. Macros can go in a few more places.

Really, 1.39 was a huge release, and other than that... all language changes were very minor, mostly sanding off some edge cases, making some things more orthogonal, stuff like that.

Most releases these days add some standard library APIs, maybe we have some toolchain improvements... but for all of 2019, we had one feature I'd call truly major.

I suspect that things were a lot more hectic previously, but the language has slowed way, way down recently. We have had two releases so far this year, and I would argue that the only real language feature was an expansion around match patterns. Which again, isn't so much a new feature as it is adding a little bit to an old one.

Churn is real. It's important to keep in mind. We've said for a very long time that Rust's churn rate would slow down. It's really pretty low at this point. Or at least, in the language.

One person on the lang team writing two blog posts fleshing out an idea does not mean the sky is falling.

<comment><USER34> My main concern is with new syntaxes. Expanding use-cases for existing ones, loosening restrictions that can be safely loosened, etc. are all well and good. But layering on new sugar-syntaxes that aren't truly necessary makes the language much harder to mentally grok over time. All of a sudden you can't just derive what's happening by studying the code, you have to add new pieces of arbitrary information to your mental toolbelt first. The Ok(..) one mentioned, from a quick glance, seems really unnecessary.

<comment><USER38> The language team member you are criticizing for exploring what Ok-wrapping could look like goes into your particular argument in quite some detail here: [https://boats.gitlab.io/blog/post/2017-12-27-things- explicit...](https://boats.gitlab.io/blog/post/2017-12-27-things-explicit-is- not/)

Your general concern, which is that "new syntax makes things less explicit, and is therefore bad", isn't logical.

Adding new syntax has many costs (not only one), but it can also have benefits (hence why it is being proposed), and the real question is whether the benefits outweigh the costs. That is, whether it is a trade-off worth making.

In the blog post, the author quantify the actual costs of not having Ok- wrapping on their own code, as well as the costs of adding Ok-wrapping to the language, and for them, their numbers suggest that the trade-off is worth it - so they went on and implement it as a proc macro, and are using it on their own code. They don't care whether anybody elses uses it, and they don't have to.

You could have disagreed with their quantification, maybe you have different numbers, and that leads to a different outcome of whether the trade-off is worth making or not.

Instead, you just disagree, without making an argument, and others are doing the same.

In my eyes, this kind of hurts your position, since it gives me the impression that those against Ok-wrapping can't really argue why. Whether they just can't argue in general, lack data to back their arguments up, or maybe even whether they are Rust users at all, is anybody's guess.

I can't imagine a Rust application writer that is using Result idiomatically and not doing _a lot_ of manual Ok-wrapping all over the place. I can't imagine anybody actually enjoying that manual Ok wrapping. Looking at servo, the Rust compiler, and all my applications, what people end up doing is writing their own one-shot local macros to hide that manual Ok wrapping. Having written some of these myself, it definitely did not happen because I was "enjoying it too much". On the contrary, once or twice per function is ok, but when I had to do it dozens of times per function, it was just too painful both for the people writing it and those maintaining that code.

<comment><USER47> it doesn't seem to me that your reading of brundolf's post is very generous. the post doesn't mention explicitness at all, but says that increasing the number of syntaxes that can be used for the same purpose increases mental overhead for reading code. also, the post says that this particular proposal "seems really unnecessary," strongly implying that the author does not believe the tradeoff is worth it.

personally, while I can't claim to love writing Ok around return values, I definitely value the enhanced readability that comes with it. rust is the most readable language I've ever coded in, and it's not even close. when I see the "throws" syntax that was proposed, I expect it would make it harder to read the code because the Result type is erased from the type signature. To me, whatever tradeoff I would gain in ease of writing code from this would be far outweighed by the cost in reading that code.

</comment></comment></comment></comment><comment><USER48> Given that rust is changing, I think they are managing the change well.

The question is: should it be changing?

I think the answer is yes. Rust is a new kind of language that is showing people (like me) things I never would have thought were practical. It's inevitable that ergonomics are going to evolve to make everything flow together.

</comment><comment><USER49> For those not familiar with the Rust drama, it should be emphasized that this blog post is very much a reaction to the linked blog post advocating for "Ok- wrapping": [https://boats.gitlab.io/blog/post/why-ok- wrapping/](https://boats.gitlab.io/blog/post/why-ok-wrapping/)

This is a subject that has provoked much drama in the past and looks like it will again.

</comment><comment><USER50> In general, programming languages will change over time, so what matters to me is how that change is managed. Cautious, small, gradual changes over time seem safer than big releases every year or so, but particulary because of Rust's approach to stability. When Rust has a new feature implemented, it does not immediately become part of the stable language. Instead, Rust only commits to stability for a feature once it has been properly tested. It's something I think PHP (which I have been a significant contributor to) and other languages could learn from, because there's no substitute for real-world experience to decide if there are remaining rough edges on feature, or whether it is good idea at all.

Moreover, unlike some other languages, Rust has chosen not to force people to adapt their code to new syntax and features! They can stay on an old version (edition) of the language forever, yet still use an up-to-date toolchain and have others be able to make use of their code. I wish every language was like that. Imagine if Python 2/3 had never happened.

</comment><comment><USER51> Does anybody change/update their C++ code to keep it "idiomatic"?

Not sure I really get the concept here.

<comment><USER16> Yes, large projects like Firefox and Chrome are constantly updating their code. The rate at which that change happens varies though.

Sometimes you do that because the new stuff is a significant improvement in its own right, but you also need to do it because using an "obsolete" dialect of C++ makes it difficult to incorporate third-party code, makes it unattractive to new contributors, and is generally just a code smell.

</comment></comment><comment><USER52> The same can largely be said of JavaScript:

* function as class -> class

* function() {} -> ()=>{}

* callback -> promise

* var -> let, const

Every year there's something else new that you are told you are doing wrong.

<comment><USER53> Well of course but Javascript is in unique position to do those kind of things, other languages have to be careful not to alienate its communities.

</comment></comment><comment><USER54> I appreciate that the language I'm using is evolving, as well as the libraries and frameworks in the ecosystem. If I fail to keep up because I'm focusing on making the most out of the tooling I committed to, that leaves opportunity for growth. I care about creating solutions, not keeping up with the ambitions of a large, diverse group of high achievers.

</comment><comment><USER55> Maybe it's just me, but every time I look at Rust I'm either turned off by the community or by this constantly shifting idea of what is best practice.

A lot of comments have talked about the idea of writing Rust like it is X year, which seems weird to me as I would imagine that a language with a strong ecosystem would not create a situation where five-year old code that was considered ok then is now looked back as bad code and a reason for derision. Besides the obvious learning better ways to do things as time goes on, shouldn't code written five years ago still be good if it works? Is code being a few years old the only excuse we need to rebuild it?

Maybe I'm wrong here, but what I want is to not have to think to myself a year after I build something "well, that was built in last years standard, time to rebuild in this years standard."

<comment><USER14> The "community" you're paying attention to is made up of enthusiasts, so it's to be expected that they tend to be in the camp of adopting new shiny things as soon as they're released. The same thing happens in C++; you'll often see reddit / stackoverflow telling you to stop using new/delete in favor of make_shared and make_unique, stop using loops in favor of functions from `<algorithm>`, and so on.

Regardless of whether the new additions make the language better or not (I believe they do, in both Rust's and C++'s case), adopting them immediately in the codebases you are responsible for is _your_ decision. You have to decide by yourself whether the pros from adopting the changes are enough to offset the cons of making changes. If you conclude that the cons outweigh the pros, and if it bothers you that the "community" derides you for not tweaking your code, then a valid solution is to stop paying attention to the "community" and get on with your life.

</comment></comment><comment><USER56> Meanwhile typescript people be like: oh I see you're still using the old style mapped quantum ensemble types introduced five weeks ago rather than the retro- causal discriminated union types which will be introduced five hours from now - how quaint.

</comment><comment><USER57> I can't keep up with it either, but that doesn't stop my code from doing what I want it to do. There are a lot of people who seem like they enjoy working on Rust as a hobby, the same way some people like playing video games. They still have a commitment to backward compatibility though, so who cares if a bunch of people geeking out on their favorite language are fine-tuning it and making superficial changes, the code I wrote before stil runs the same (or better) than it did when I wrote it. The compiler doesn't care if it's idiomatic, just that it's correct.

</comment><comment><USER58> Seems like it would be beneficial if codemods would accompany such features if possible.. is it possible in rust?

<comment><USER11> There are several ways of doing this, yes. Including one provided by the Rust project itself, "rustfix."

<comment><USER59> Is "rustfix" what is running behind-the-scenes when you run "cargo fix" or is it something distinct?

<comment><USER60> Yes, cargo fix just runs rustfix on all the files in your project and passes the same flags cargo does to rustc. (Similarly, cargo fmt runs rustfmt on all the files in your project.)

</comment></comment></comment></comment><comment><USER61> On the one hand, this is a predictable outcome if you are trying to shepherd a large codebase through a fast-moving language. Idiomatic Python 1.6 looks dramatically different to idiomatic Python 3.x.

On the other, Rust isn't the language I would want to write lots and lots of code in either. There are a few projects and organizations where it makes sense to do so(namely web browsers, databases, and other kinds of "deep backend, large surface area" types of projects), but most of the things it does well also act as a hindrance to feature development, compared with an idiomatic Java, C# or Go equivalent.

</comment><comment><USER62> I don't want a language full of special cases.

</comment><comment><USER63> C++ programmers, like what I do mostly, may have to do over and over with new standards, but don't have to for all code.

</comment><comment><USER64> I thought that not knowing what idiomatic Rust looks like was the most idiomatic thing about Rust.

</comment><comment><USER65> I recommend that this guy switch to javascript to truly understand himself.

</comment><comment><USER66> I feel this way about Swift.

<comment><USER67> It's better than Swift actually. The Swift compiler isn't even backwards compatible.

</comment></comment><comment><USER68> I recently had a thought, that language team should provide automated migration tools for such things. It woukd made python 2 to python 3 switch much easier and faster, that applies to rust even more.

<comment><USER69> They do: [https://doc.rust-lang.org/cargo/commands/cargo- fix.html](https://doc.rust-lang.org/cargo/commands/cargo-fix.html) It works much better than 2to3 actually.

</comment></comment><comment><USER70> just a big FAT WARNING here. C++ suffered for a long time from staleness because people detested change.

I think tools and technologies should prioritise the future and new users than focusing on the past and long time users. it is what is best for the survival of the language.

if you don't want to deal with the changes then don't update your code base. but don't update the compiler then resent the fact that it is updated.

</comment><comment><USER71> Rust is not the only language that changes over time. The changes in Rust are must smaller than say C++.

<comment><USER15> Not even close. C++ is a language that is over 30 years old. In comparison, Rust is way younger and has had many more changes and features added in a way shorter period of time.

For good or bad.

<comment><USER23> I think the rate of changes to C++ has accelerated recently as well. Until C++11 it wasn't actually that unreasonable.

<comment><USER15> Even if you add the recent additions, it is still less stuff than Rust already has. For instance, async.

The problem with C++ is all the bending backwards they do to keep old code compiling _and_ working, which is a major reason for its success.

<comment><USER72> "The problem with C++ is all the bending backwards they do to keep old code compiling and working"

Uh, that's not a problem, it's (as you say) the main reason people use it and why they burn out on flavor of the day languages like Rust and Go (as the OP illustrates).

<comment> Ar-Curunir This is funny, because with Rust you can almost certainly compile code from Rust 1.0, unless it was relying on a soundness bug. You can also seamlessly use dependencies that use newer editions of Rust; you don't have to adjust your code to do this.

</comment></comment></comment></comment></comment></comment><comment><USER73> So what? Did you ever look at a production codebase? You will be hard pressed to find an idiomatic codebase and nobody in the world is going to update anything to be "idiomatic" every 6 weeks. I mean maybe your manager doesn't fire you right away if you try, but you better be doing this in your spare time lol.

For academic and self-learning use? Sure go ahead, but then please don't complain that you can't keep up with it. Nobody should be using a feature for the sake of using a feature. If you don't need it, don't use it. If its old and not "idiomatic" there is literally ZERO reason to change it unless you ain't got anything better to do.

Get your priorities straight.

</comment><comment><USER74> This is what happens when a bunch of web developers are in the core team of a supposedly "systems programming" language. Web developers are used to moving to a new framework every week.

</comment><comment><USER75> Totally agree. Rust is complicated for doing simple things.

<comment><USER54> This is true, as is the fact that work often demands one not do "simple things" and in this space Rust shines

</comment></comment><comment><USER76> Avoiding rust atm myself. Just seems too clever for its own good.

</comment><comment><USER77> Just use C99. No need to keep up with anything.

<comment><USER78> Personally, I stick with K&R C. I haven't gotten around to update all my with function signatures. whats is the thing with putting (void) all over or specifying the return type of my functions? Really, these explicit function declaration are just code duplication that serious programmers don't need as they know their code. (/s)

<comment><USER79> You're being sarcastic, I know, but you just unironically exactly described an entire decade or more of early C programming.

</comment></comment></comment><comment><USER80> Why not just add a fold function to Option (as all monads should have a fold)?

<comment><USER45> Fold isn't an operation on a specific monad, it's a generic operation over any monad. Adding it to Option defeat the whole point of thinking about Option as a monad, i.e., the ability to apply generic algorithms that work on any type constructor that follows the monad laws.

(If the question is why no generic fold over any monad exists in Rust, the short answer is that Rust isn't Haskell. Which is great, it means Rust can specialize in things Haskell can't and vice versa. Personally my favorite example is that Haskell avoids shared mutable state by avoiding mutable state, and Rust avoids shared mutable state by avoiding shared mutability. Both have their downsides but each works better for different applications.)

<comment><USER81> > Fold isn't an operation on a specific monad, it's a generic operation over > any monad. Adding it to Option defeat the whole point of thinking about > Option as a monad, i.e., the ability to apply generic algorithms that work > on any type constructor that follows the monad laws.

Having the same function exist with the same name helps communicate with other programmers, even if you can't express the fact that it's actually the same function at the language level. Just like in a language without generics you might still have add(int, int), add(decimal, decimal), add(string, string) and add<T>(list<T>, list<T>) functions. Rust already offers a function called "and_then" on most of its monadic types, and a programmer can see and understand that these are all in some sense "the same function" even though there's no way to abstract over that.

<comment><USER82> But 'fold' isn't very useful over option types as there aren't really any non- trivial operations that you can perform on something that's either Nothing or Just x. I think OP was probably thinking of folding over a list of option types, which you can do easily enough in Rust.

<comment><USER81> That's the opposite of my experience; fold is probably the main way I consume options in Scala. It's pretty much the only thing you ultimately want to do with an option, after you've finished transforming and composing.

<comment><USER82> I'm really puzzled by this. Which Haskell 'fold' function would I ever want to apply to a Maybe type? I think there must be some kind of terminological variation in the use of 'fold' here.

 _edit_ : Ah yes, I see that Scala chooses to use the name 'fold' for what is essentially the 'maybe' function in Haskell.

I don't think there is any very useful generic notion of 'fold' that corresponds to this usage. (I see how the operation is a kind of fold, but the type signature of the function isn't flexible enough to be used for any foldable type.) So that is why Rust and Haskell don't name this operation 'fold'.

<comment><USER45> And here we see _exactly_ why implementing a specific function on a specific instance of a monad isn't the answer - two users of two different, well- respected functional languages can't communicate.

<comment><USER81> That's completely backwards - the confusion here is precisely because the function is not implemented, if it was present in Rust (with a type signature) then there would have been no misunderstanding. (There was also a mistake in the original statement - fold is nothing to do with monads)

<comment><USER82> The function is implemented for option types in Rust, it's just not called 'fold', because there's no universal convention according to which functions with that signature are folds.

[https://doc.rust- lang.org/std/option/enum.Option.html#method...](https://doc.rust- lang.org/std/option/enum.Option.html#method.map_or_else)

</comment></comment></comment></comment></comment></comment></comment></comment></comment><comment><USER83> Now imagine when it gets to the 40 years of C++ existence, or 25 from Java, 20 from .NET, then one learns to value why enterprises care about backwards compatibility.

More breaking changes are on the way, until error handling and async/await get properly integrated into std, instead of having a couple of incompatible crates each going its own way.

<comment><USER84> Please allow me to share my view of the conversation up to this point:

Boats: Here is an approach I use in my personal projects that has proven to be ergonomic, consistent with other language features, and could possibly even unlock future optimization opportunities long down the road.

OP: That's it, I'm DONE. The language moves too quickly and I can't keep up.

You: More breaking changes are on the way. They never learn.

\-----

Would you agree that this escalated way, way too quickly?

Boats didn't "move" the language with a blog post, it's not even a pre-RFC. As pointed out elsewhere in this thread, the language hasn't been moving at all since 1.0 - you could say the frontier has been inching forward, but that's what frontiers do; nobody's forced to fight on the front lines all the time. And then the cherry on top - "more breaking changes on the way", when 1) prior changes weren't breaking; 2) it's not clear there will be any new ones; 3) if there will, those won't be breaking either.

<comment><USER83> Please let us know how async/await is not going to be a breaking change, when even Fuchsia just decided to create their own async runtime, because surely we still don't have enough of them.

So I wonder how std will incorporate a runtime implementation that happens to be compatible with all ongoing runtime flavours, so that those breaking changes don't happen.

<comment><USER84> Well, either the language will leave async runtimes in the domain of third- party libraries, which is the current approach. Or, the potential blessed one in std will be an alternative that you may or may not want to use in your code.

When I think of breaking changes, I think removing sun.misc.Unsafe. Which, yes yes, was never supposed to be used, but still was. Evolution of best practices and introduction of alternative implementations doesn't break anything.

<comment><USER83> It does break, because those libraries need to interoperate and async/await doesn't work without linking to one of them.

<comment><USER85> I might be misunderstanding, but the third party libraries won't be going anywhere, right? No one will be forced to use the runtime in std, if it's added.

<comment><USER11> That is correct. It's not clear that we'll add one to libstd, but even if we do, it will have zero impact on folks using external runtimes. If we do add one to libstd, it will probably be a very simple one, mostly for convenience and prototyping, rather than something that tries to compete with the bigger runtimes.

<comment><USER83> And what is the interoperability story across libraries that dependent on different runtimes?

<comment><USER11> It depends. The major pain point right now is that there's no common API for spawning new tasks. Not every library does that though.

It's still not clear what this has to do with being a "breaking change" though. Like, if I were to use the serde-json crate in my project, the fact that the json crate exists, but has a slightly different API, does not mean that somehow this is a "breaking change." Moving between two or three different libraries is not the same thing.

</comment></comment></comment></comment></comment></comment></comment></comment></comment><comment><USER86> They're _still_ fussing with the preferred error handling syntax?

Most of the hacks for not having exceptions seem to end up being worse than exceptions.

<comment><USER87> Not it didn't. Rust error handling is glorious comparing to exceptions.

Rust community is just full of perfectionist and we love to argue endlessly about how to improve stuff even more, which is very refreshing. In many other PLs people just keep their heads down and crawl in the mud.

<comment><USER88> > _In many other PLs people just keep their heads down and crawl in the mud._

Or, as I would put it, programming is a job for them and not also a hobby. They have other things to spend time on, so banging out an ugly codebase in JavaScript is "good enough" to let them clock out.

Either is fine, but I don't think it's realistic to assume everyone can or should seek perfection in their tooling.

</comment></comment></comment><comment><USER89> Sad to see that rust is heading towards a wrong direction. I think everyone in the core team should be stopping what they are doing and write Haskell for a year. This way they can appreciate the benefit of Haskell, and know what to avoid when they implement those ideas in rust, and anyone who trying to make the language and the philosophy more like c++ or java should be banned from the rust community

<comment><USER11> Several folks on the language team know Haskell well.

<comment><USER80> I'm sure they do, but even you must admit that Rust has gotten less 'functional' in nature as time goes on. New syntax or ad-hoc abstractions are being created to handle problems that have well known FP solutions. Take this matching on an Option business. The easy solution is to just add a fold method on the option type. Problem solved, now you never will need to match an option ever again! The harder solution would be to implement HKT and add a real monad trait, but let's not get into that. Another example are the async/await syntax. Why does this syntax need to exist? What value does it provide? Why can't a future just be a regular old class?

A long time ago I thought Rust was going to be a flexible and innovative general purpose language. While it still is undoubtedly innovative, it seems like the target audience has shrunk considerably. And as GCs improve and get more tunable, I think that target audience is going to get even smaller in the future.

<comment><USER11> > even you must admit that Rust has gotten less 'functional' in nature as time > goes on.

I don't think this is true, especially when you look at long timescales.

> New syntax or ad-hoc abstractions are being created to handle problems that > have well known FP solutions.

They have known solutions when you have a GC and no control over memory layout. They do not have known solutions in a language like Rust.

> Take this matching on an Option business. The easy solution is to just add a > fold method on the option type. Problem solved, now you never will need to > match an option ever again!

Sorry, I do not understand what you're talking about. (I coded in Haskell most a decade ago, I'm not on the lang team.) What would fold do on an option, specifically? Fold is usually a list operation, but an option is a list of zero or one... so it would be a no-op?

> The harder solution would be to implement HKT and add a real monad trait, > but let's not get into that

Again, this is "we don't know if this is possible in a language like Rust" territory. Which is why you don't want to get into that.

> Another example are the async/await syntax. Why does this syntax need to > exist?

Specifically because of the previous statement. It is not clear that a more abstract option is possible. We could wait for more years until maybe it's proven possible, or we could implement a useful feature today that we know is.

It's also _more_ significant in Rust than other languages due to borrowing. [http://aturon.github.io/tech/2018/04/24/async- borrowing/](http://aturon.github.io/tech/2018/04/24/async-borrowing/) is a bit out of date but the concept is the same.

> Why can't a future just be a regular old class?

Rust doesn't have classes. Futures are a regular old typeclass.

> While it still is undoubtedly innovative, it seems like the target audience > has shrunk considerably.

We have seen a _massive_ uptick in adoption over the past few years. async/await, for example, has been a feature that a lot of folks have said "I'll start using Rust once that hits stable."

<comment><USER23> > What would fold do on an option, specifically? Fold is usually a list > operation, but an option is a list of zero or one... so it would be a no-op?

Presumably the fold takes advantage of the fact that the default, "accumulator" value is chosen if the Option is empty and the collapse function just runs what would be the Some arm of the match statement.

<comment><USER11> Oh, duh. Thanks.

Thats [https://doc.rust- lang.org/stable/std/option/enum.Option.html...](https://doc.rust- lang.org/stable/std/option/enum.Option.html#method.map_or), I think?

<comment><USER23> If the team had just written Haskell for a year they would have picked the obviously superior "fold" name for this operation. (I think you can actually use fold here if you _really_ wanted it, since Option implements IntoIter?):

       Some(0).iter().fold("some", |_, _| "none")

<comment><USER35> For people coming from a functional programming background, `fold` might be the superior name. But setting aside monads, `map_or` expresses the intent much better I find.

<comment><USER23> (I was being mostly sarcastic.)

<comment><USER35> Rereading your comment I wonder how I could miss this!</comment></comment></comment></comment></comment></comment></comment></comment></comment></comment>


Time travel: An isochronic map of travel times from London circa 1914 - <AUTHOR> http://www.intelligentlifemagazine.com/places/cartophilia/time-travel <comment><USER2> Ooh, I've been investigating this lately, and I can't sleep. Here are some entries from my bookmarks:

* BART map, one minute per hexagon - [http://transitmaps.tumblr.com/post/133579339455/lopato-bart-...](http://transitmaps.tumblr.com/post/133579339455/lopato-bart-time-scale)

* Mapnificent, covering dozens of cities - [http://www.mapnificent.net/](http://www.mapnificent.net/)

* OneBayArea, including housing prices - [http://maps.planbayarea.org/travel_housing/](http://maps.planbayarea.org/travel_housing/)

<comment><USER3> Huh. Mapnificent is exactly what I've been looking for recently after a change-up in local transit routes. It would certainly make it easier to eyeball "short trips" when considering the intersection of multiple transit modes, assuming it's accurate enough.

<comment><USER4> It's a nice idea, but London is hopeless - looks like they've missed out the rail network completely. I guess other cities may be better, but you really only need to miss out one key route or mode and you change the map completely

<comment><USER5> I reckon it is because tfl is the data provider, and the rail network isn't a part of that?

I still found it very useful when looking for central accomodation with short commutes (<20') to centrally located places.

</comment></comment></comment></comment><comment><USER6> Awesome. But that's a low res scan. You can see a very high res scan here:

[http://www.davidrumsey.com/luna/servlet/detail/RUMSEY~8~1~24...](http://www.davidrumsey.com/luna/servlet/detail/RUMSEY~8~1~248974~5516374:Isochronic- Distance-Chart,-1904--Av)

Also, a scan of Galton's original isochronic map from 1881 is on Wikipedia; see:

[https://en.wikipedia.org/wiki/Isochrone_map](https://en.wikipedia.org/wiki/Isochrone_map)

</comment><comment><USER7> I've always liked these maps that capture the ground truth for a single point in time. Here's another one I found a while back showing "Everywhere you can go in an Airplane", circa 1918, also with journey times:

[http://www.blogabond.com/CommentView.aspx?CommentID=8226](http://www.blogabond.com/CommentView.aspx?CommentID=8226)

(I actually pilfered it for that post from another source, but can't find the original now).

Growing up, we had a World Atlas in the house that was printed in the early 1940s. It had a little leaflet in the back with a card you could send in for an updated set of maps after the war was over.

</comment><comment><USER8> Here is a similar map for the Roman world: [http://journalofdigitalhumanities.org/wp- content/uploads/201...](http://journalofdigitalhumanities.org/wp- content/uploads/2012/08/iph1_800.png).

</comment><comment><USER9> If anyone's particularly interested in unusual maps I'd recommend following @frankjacobs on Twitter. He's a collector of strange maps and tweets links to new posts on his blog. Enjoy

[https://twitter.com/frankjacobs](https://twitter.com/frankjacobs)

[http://bigthink.com/articles?blog=strange- maps](http://bigthink.com/articles?blog=strange-maps)

<comment><USER10> or /r/MapPorn

</comment></comment><comment><USER11> The smallest unit listed - _within 5 days journey_ \- gives an interesting perspective on the world of travel at that time.

What would we choose nowadays for an equivalent unit of "not worth listing anything below this?" Within an hour?

<comment><USER12> Within 5 hours would get you most of Europe.

<comment><USER13> I would put that at 8 hours. Unless Spain is especially badly connected, you are quickly at least 2 hours away from the airport. So that would be at least 4 hours slow transit + flight time.

Of course, by population density, you are probably 5 hours away from most people in Europe.

</comment></comment></comment><comment><USER14> An important dimension missing in this type of map is cost of travel. If you are willing to spend sufficient money, my guess would be you could reach pretty much any spot of land on earth within about 48 hours, with the appropriate combination of helicopter and private jet... But if you limit yourself to, say, 2000 Euros, you could probably make it to many places, but it would take significantly longer.

<comment><USER15> I think you're missing the fact that this is ~1914. I bet chartering a private jet and/or helicopter back than was... difficult.

</comment></comment><comment><USER16> New York based isochronic map: [http://quod.lib.umich.edu/g/genpub/abl7462.0001.001/390?view...](http://quod.lib.umich.edu/g/genpub/abl7462.0001.001/390?view=image&size=400)

<comment><USER17> This is particularly interesting because it shows the advance over time.

</comment></comment><comment><USER18> It's interesting that you could get all the way to Hawaii quicker than you could get to the west coast of South America. There doesn't seem to be a technical impediment here, I guess there just weren't scheduled ship routes at the time?

<comment><USER19> I suspect that it simply took longer to sail around Cape Horn in South America (a dangerous and time-consuming journey) to get to the west coast of South America than it did to sail to New York, take a train to California, and hop on a ship to Honolulu.

<comment><USER18> I had assumed that a trip to Hawaii would transit the Panama Canal, but you may be right about the route. WP says the canal opened in August 1914, so it might not be included here. I wonder how different a map made just a few years later would be.

</comment></comment></comment><comment><USER20> I think it's interesting that 100 years later, you could replace "days" with "hours" and the mail would look (roughly) the same.

I wonder what the next 100 years will bring...

<comment><USER21> Maybe someone will invent a real (not dup) teleporter and then perhaps it will be seconds. I've always wondered what the world would be like if you could go anywhere in seconds.

<comment><USER22> Isn't it bland and homogenous enough already?

(And then there's the risk of suicide bombers with access to teleportation pads...)

</comment></comment></comment><comment><USER23> Does anybody have an idea how I could get a print of this?

<comment><USER24> Someone posted a link below to this map on the David Rumsey map collection ([http://www.davidrumsey.com/luna/servlet/detail/RUMSEY~8~1~24...](http://www.davidrumsey.com/luna/servlet/detail/RUMSEY~8~1~248974~5516374:Isochronic- Distance-Chart,-1904--Av)). You can get a high-res version there, or order a print directly.

</comment></comment><comment><USER25> It would be fun to see same iso-chronic map for today, 100 years since original. :)

<comment><USER26> My rough guess is that, if the units were hours, and if concorde still flew, then the map would look much the same?

<comment><USER27> I suspect a modern version would have more discontinuities.

Areas near airports would be fast to reach, but onward travel from the airports wouldn't be so much faster than 100 years ago.

And the oceans would look different - it still takes a long time to reach the mid-atlantic!

<comment><USER26> So travel time doesn't count using a private jet and a parachute?

<comment><USER28> Even if it counted it won't be the smallest one with the time it will take to get bail in most countries.

</comment></comment></comment></comment></comment><comment><USER29> For Europe by train see [http://emptypipes.org/supp/isochrone_london/](http://emptypipes.org/supp/isochrone_london/)

</comment><comment><USER10> I wish the guys from [http://www.rome2rio.com](http://www.rome2rio.com) see this and make a more precise modern version

</comment><comment><USER30> Nice coincidence that it takes about 80 days to go around the world.

<comment><USER31> Reading the history of circumnavigation makes this seem like a bit of an overestimate -- Around the World in 80 Days was written in the 1870s, in the 1880s someone actually did the trip in 72 days, and in the early 1900s someone replicated it in 54 days.

<comment><USER32> Maybe this map represents more of an everyman's estimate. How long to get there using conventional transportation systems. The equivalent today being flying commercial and car/buses vs chartering a private jet and helicopters.</comment></comment></comment>


How Apple Really Screwed Up With New License - <AUTHOR> http://sheddingbikes.com/posts/1271015736.html

<comment><USER2>
        I actually predict that this will be a major problem for Apple in the
        future, but probably won't impact their bottom line for their mobile
        platforms. Programmers never forget things. They are notorious for
        not updating basic knowledge they believe and for spreading myths
        and rumors about technology for decades. I can actually see a situation
        building where programmers who maybe wouldn't have worked on an
        iPhone application would still avoid targeting Apple products simply
        because of the stories about Apple doing "A Section 331" on them.

This.

Despite my personally benefitting from the new policy change, (I write Obj-C comfortably and will benefit from the reduced competition,) I think Apple is making a grave mistake trying to extend their review checking process in a manner that can only be done in reality by visiting each and every developer. I'm not convinced Apple's in-house analysis tools will be able to capture violations in a manner consistent with their current license wording.

It's just going to degenerate into a cat-and-mouse game with the larger and/or more tenacious middleware developers, leading Apple to waste resources and R&D money on license enforcement, driving down profits and adding significantly to the large pile of ill will Apple has accumulated in the last few years. Apple is _still_ living down past quirks and excess of their platforms, like "Cult of Apple evangelism" and "one-button mice," that are no longer true, but hang around their necks like a long decaying albatross. In short, this could help cause Jobs to lose control of his platform's message to the masses if the people able to recommend their hardware and platforms keep sticking "asterisks" to their recommendations.

<comment><USER3> I don't think Apple have any interest in strictly enforcing this rule. It's meant to be a catchall clause. Most likely App store reviewers will first use some subjective criteria like whether an app feels like a native app or whether it fits certain performance requirements. If an app fails to match the subjective criteria it will be submitted for further inspection. And just then, if it fails to pass that one too, it will be "objectively" rejected for a subjective reason.

<comment><USER4> _I don't think Apple have any interest in strictly enforcing this rule._

Stupid rules are not improved by selective enforcement. The randomness, the unfair application of them makes it worse.

<comment><USER3> I'm not defending the rule or the inconsistent enforcement of it. I'm just pointing out why DLWormwood's apocalyptic prediction of "a cat-and-mouse game with the larger and/or more tenacious middleware developers, leading Apple to waste resources and R&D money on license enforcement, driving down profits and adding significantly to the large pile of ill will Apple has accumulated in the last few years" will most likely not come true.

</comment></comment></comment></comment><comment><USER5> I can't get the taste out of my mouth about 331. To the point that this is actually making me study other platforms because of the spookiness of Apple's propensity to be arbitrary. I'm two weeks into developing a game I had hoped to port over to Android after releasing for the iPhone. Now, I'm looking harder now at WebKit and Android (and have glanced a little at Windows Phone, gasp).

</comment><comment><USER3> Although I am amongst the first to disagree, maybe not necessarily with Apple's goal, but certainly with the language they are resorting to to achieve that goal, I have to object to the following statement:

 _What I believe programmers are truly angry about is that Apple broke their long standing promise of supporting multiple languages when they originally attracted them to the platform. They're really saying:

"You told me if I bought a mac, and an iPhone, and an iPad, that you would create LLVM and MacRuby and Python bindings so I can code in my favorite language. You lied!"_

Nobody is really saying that because neither Apple nor any of their employees have ever told anyone such a thing. On one hand the ban of interpreted code, except for Javascript, has been there since day one, so no sane programmer has had the illusion that they can use Ruby, or Python, or whatever to write iPhone apps. And on the other hand there is absolutely nothing preventing Apple from amending that clause in the license agreement once the technical limitations, e.g. garbage collected Objective-C runtime, behind toll-free, ahead of time compiled wrappers like MacRuby disappear. Especially since MacRuby in particular is an Apple run project.

<comment><USER6> The ban that was there since the beginning wasn't against all interpreted code, was it? It was against being able to run interpreted code _that wasn't originally shipped with the app._ So I don't think (before the recent 3.3.1 changes) that Ruby or Python would have been against the rules. Please correct me if I'm wrong.

<comment><USER6> Commodore 64 app is still on the App Store. It was taken off briefly when it was found to be able to run interpreted code that wasn't originally shipped with the app (specifically, code the user typed into the emulated C64's BASIC interpreter).

So it's hard for me to see why an app that was written in Ruby or Python would have been disallowed before the recent changes.

And it seems the C64 app (the one that's up now, that can't run arbitrary code) will be disallowed after these changes go into effect.

<comment><USER7> Lots of other games are ports using VMs. Escape from Monkey Island is one notable example. Another is the Frotz (interactive fiction) port for the iPhone.

<comment><USER6> Yeah. It's going to _have_ to be reworded ... or, at the very least, a statement issued clarifying what's meant to be included vs. what isn't (a Steve Jobs "executive signing statement").

I'd sure like to hear ideas of how that could be worded. I strongly doubt they'll back down and allow the Flash compiler at this point. But they obviously want to keep Monkey Island, and perhaps even Unity 3D. How could they possibly word a new version of the clause to make this distinction clear? _Can_ a formal distinction be made?

</comment></comment></comment></comment></comment><comment><USER8> _In this case I think they could be sued or investigated the same way Microsoft was regarding their unfair business practices in licensing._

No, they can't, because the predicate for the Microsoft enforcement action was their monopoly position in the desktop market, and the cause of action was their attempt to use that monopoly to create _new_ monopolies.

Apple has nothing close to a monopoly on smart phones (they are crushed by RIM).

I'm also confused by the thesis of this blog post, which seems to be that there was a bait-and-switch pulled on the Apple dev community writ large. The vast, overwhelming majority of iPhone apps are written in ObjC, and Ruby is no more a second-class citizen on OSX today as it was last year.

</comment><comment><USER9> Are we still on this?

The curtain has closed; Apple is now evil... move on.</comment>


Disaster in New York does not require the same policy everywhere - <AUTHOR> http://blueberrytown.com/index.php/2020/03/22/disaster-in-new-york-does-not-require-the-same-policy-everywhere/ <comment><AUTHOR> Key points

"As of approximately 4 pm CDT this afternoon, Italy has the highest confirmed per capita infection rate of any substantial country. There are 978 Italians confirmed with COVID-19 for every million people. Switzerland is not far behind, at 864 per million."

"New York State has a whopping 810 cases per million residents, closing in on both Italy and Switzerland fast. And the vast majority of those cases are concentrated in the City and nearby commuter counties. Franklin County, in the Adirondacks (and where your Editor has been known to spend some time) has not yet had a single confirmed case."

"By contrast, the other 49 states combined, including such hot zones as Washington and California, are at 54 cases per million residents. That puts the per million infection rate in the "other 49" just between Australia and North Macedeonia."

"The vast difference in the apparent rate of infection between downstate New York and the rest of the country (and the considerable differences among the remaining 49 states) suggests that we need not apply precisely the same policies in every jurisdiction. Even in New York State, we do not understand the logic, beyond mere political calculus, for imposing the same burdens on the already poor towns of the Adirondacks as are the bare minimum, if that, in the boroughs."

"We are doing enough damage to the economy as it is without doing more than is necessary by treating everywhere, even everywhere in New York State, as if it were the Times Square subway station. Poverty kills as surely as Covid-19, and it may be the one thing we are producing as fast as virus particles."

"Fearless state and local leaders, please use a scalpel, not a hacksaw, even if the Manhattan-headquartered national media demands a universal, maximum response everywhere."

</comment><comment><USER2> Major cities are first due to travel and busy airports. The spread of the epidemic is in different phase in different areas.

Other areas have still time to prepare.

</comment><comment><USER3> tl;dr: 'I'm incapable of understanding that doubling every six days means a case rate of 50 per million becomes 1000 per million in ~25 days if nothing is done.'</comment>


Drawing Map Routes on IPhone using unofficial Google Maps Api - <AUTHOR> http://blog.kadirpekel.com/2010/05/30/drawing_routes_onto_mkmapview_using_unofficial_google_maps_directions_api

<comment><USER2> I've used this before and it's also available in XML format by using the KML format. What's not mentioned and is an extra bonus is that this doesn't require a Google API key. This is just calling a public URL.

NSString _startingLoc = [NSString stringWithFormat:@"%f,%f", starting.latitude, starting.longitude];

NSString _endingLoc = [NSString stringWithFormat:@"%f,%f", ending.latitude, ending.longitude];

NSString *dirURL = [NSString stringWithFormat:@"maps.google.com/maps?saddr=%@&daddr=%@&output=kml, startingLoc, endingLoc];

(I took off the http: from the string because the text editor insisted on turning it into a url and ended up hiding the interesting output=kml part)</comment>


Ask HN: What terms and conditions do you expect when asked to be on call? - <AUTHOR> <comment><USER2> \- get the time back - so if you are oncall during a night, you should get a day off even if nothing happened.</comment>


MacOS: How to investigate high kernel task memory usage? - <AUTHOR> http://apple.stackexchange.com/questions/178281/how-to-investigate-high-kernel-task-memory-usage <comment><USER2> I've had this issue many times over the years on and off with a late 2011 mbp and a late 2009 mbp. After trying all of the suggestions on the thousands of threads out there about this (google: "osx kernal_task") there was one comment I finally found after all these years ([https://discussions.apple.com/message/27901055#message279010...](https://discussions.apple.com/message/27901055#message27901055)) that has so far been my fix for the past year or so on both. I used to always keep them plugged in to an outlet but now I only use them un-plugged until ~30% then charge back to 100% and un-plug again. I haven't seen the issue since so I figured I'd put this here since it's not a common solution posted to the "osx kernal_task" term.

Relevant bit from the comment "Eventually I realized that the issue seemed to be related to heat. The kernel task spins up CPU cycles to stop heat generating processes from maxing out the CPU and overheating the macbook. About the same time I also realized that the problems seemed to start happening about the time my battery reached 1000 cycles. I have still not replaced the battery so I am not sure it will fix the issue completely. I do know that when the power is not plugged in the kernel_task seems to stay relatively low on the CPU usage list. My battery only lasts about 30 minutes now on low usage so I keep it plugged in all the time. When the kernel_task process pegs my CPU I unplug the power and the process drops back down to normal."

</comment><comment><AUTHOR> Condensed list of many Mac OS tools and methods to gather deeper info on where your machine resources are spent.</comment>


Ruby on Rails Application Monitoring Tools - <AUTHOR> https://hixonrails.com/ruby-on-rails-tutorials/ruby-on-rails-application-monitoring/ <comment><USER2> Do you think Cloud66 is better than Heroku for deployment? Because i have the feeling that it's the same just one is more expensive than the other one.</comment>