[HN Gopher] I love building a startup in Rust but wouldn't pick ...
___________________________________________________________________
I love building a startup in Rust but wouldn't pick it again
Author : aisrael
Score : 197 points
Date : 2023-02-17 15:21 UTC (7 hours ago)
(HTM) web link (www.propelauth.com)
(TXT) w3m dump (www.propelauth.com)
| eYrKEC2 wrote:
| We love using rust on the backend at
| https://mayhem4api.forallsecure.com/ and in our CLI. If I were
| the decider, I'd choose it again. Rust is a hurdle to learn, but
| the confidence you gain from the type system is fantastic. I've
| worked in other projects with different, looser-type'd languages
| (no names! no flames!) and despite good testing coverage, the
| confidence on release to prod is not as high.
| AceJohnny2 wrote:
| > _Perf is easy when you have AWS credits._
|
| I get that the point of this article is that launching >
| sustaining.
|
| But I have a horror story about AWS credits for startups: a
| friend's startup got their account suspended for a couple days
| when their Credits ran out, they started getting billed 5 digits
| (as they expected), and _Amazon 's fraud detection detected this
| as an anomalous billing pattern and suspended them!_ For
| _transitioning from AWS credits to billing!?_
|
| Considering all their operations were running in AWS, and they
| were providing a HW-critical service to their customers, it was
| _bad_.
|
| This was late last year. This was despite getting reassurances
| from their AWS rep that the transition would be smooth.
| ISL wrote:
| If those reassurances are in unmistakable writing, a letter
| from the startup's corporate attorney may yield a quick refund
| and compensation.
| AceJohnny2 wrote:
| Sure, but in the life of a startup that's just one extra
| thing they'd rather not have to deal with, and the damage
| isn't just financial.
| TuringTest wrote:
| Rust is a systems language, not a business language.
|
| If you're building an operating system or a software platform, to
| for it; the robustness will pay for itself in time to fix hard-
| to-find errors.
|
| But if you're iterating fast to find out what the program should
| be about to begin with, use a prototype-friendly language
| instead. With garbage collection.
| drdaeman wrote:
| Well, I had some difficulties writing a tiny init program for a
| container because process and signal handling are currently in
| a pretty weird place in Rust.
| rrishi wrote:
| I think if you've captured the essence of the discussion on the
| usability of Rust really well.
| rattray wrote:
| This is something I hear a lot from other founders.
|
| Spinup time of new engineers is like 6mo+, some devs who can
| churn out normal CRUD product work just fine in Rails or React
| ~never become productive with Rust, and hiring skilled Rust devs
| is just crazy hard (though maybe now that Blockchain/Solidity
| things have cooled there may be more supply).
| dochtman wrote:
| N = 1, but at startup scale we have definitely not had a hard
| time hiring skilled Rust devs. Just go on /r/rust and advertise
| your (non-crypto) job and get a lot of inbound.
|
| (We were specifically looking for remote folks near EU time
| zones, maybe local in SF is harder?)
| rozgo wrote:
| 6mo+ is spot on. This is true for most dev work that deviates
| from the CRUD path. Like gaming, simulation, robotics. We might
| as well use the time to train them in Rust too.
| unshavedyak wrote:
| > and hiring skilled Rust devs is just crazy hard (though maybe
| now that Blockchain/Solidity things have cooled there may be
| more supply).
|
| Sidenote, we hire Rust at a small shop (~30 devs?). Ironically
| i've found it _easier_ to hire for Rust. You're totally not
| wrong, BUT, the quality of the candidates that apply is quite
| high in our experience. I suspect it's because we get a lot of
| passionate people. We don't have to weed out as many
| candidates.
|
| With that said we don't aim for super senior devs. We're happy
| to hire a junior, etc. I care much more about the quality of
| the person than raw experience.
|
| With that said traditional hiring avenues have not been
| fruitful for us. Word of mouth, Rust community job posting, etc
| have been most fruitful by far. Probably due to exactly what
| you said.
| secondcoming wrote:
| > With that said we don't aim for super senior devs. We're
| happy to hire a junior, etc. I care much more about the
| quality of the person than raw experience.
|
| Being young and cheap is a good quality, I suppose.
| Experience is overrated.
| unshavedyak wrote:
| Well, hiring only super experienced people in a niche
| talent pool feels arbitrarily difficult. Young devs can be
| just as good, and we all need to build experience somehow.
|
| One rule of thumb for me is that the more young a developer
| we hire is, proportionally we also need to hire an equally
| senior. Ie we don't want a huge amount of developers
| lacking experience.
|
| However if you have enough senior developers to mentor the
| young ones? Seems a net win for all involved, to me at
| least.
| nathan11 wrote:
| Lets be happy when someone says they're hiring juniors.
|
| The poster sounds like someone who invests in people and
| doesn't rule them out based on years of experience on their
| resume. From all of the "where are the seniors?" threads
| I've seen, the industry could use more of that.
| alfalfasprout wrote:
| > Being young and cheap is a good quality, I suppose.
| Experience is overrated It's "overrated" until it isn't.
| And then you learn very, very expensive mistakes.
| Unfortunately it takes experience to learn why this
| viewpoint is nothing more than hubris.
| ReflectedImage wrote:
| If you are writing high performance code use Rust. (Slow
| development times, high performance)
|
| If you are writing a typical business application use Python.
| (Fast development times, low performance)
|
| Or if you want to be clever do a hybrid of both. Create Rust
| modules for your Python code.
|
| This is just about selecting the right tool for the right job.
| npn wrote:
| I picked Crystal so I didn't have to choose.
| ReflectedImage wrote:
| That's in the C / C++ / Rust bucket due to the typing system.
| pjmlp wrote:
| I would rephrase it as follows,
|
| If you are writing high performance code where a tracing GC
| isn't an option, and there are SDKs available use Rust.
|
| Otherwise an AOT compiled language is a better option, and if
| not, and there are only C and C++ SDKs available, also factor
| in the development cost of creating wrappers in Rust, before
| doing the actual development activities.
|
| If there is too much money being burned in wrapper libraries,
| maybe that isn't the best option as well.
| dmillar wrote:
| Perhaps not the case here, but there are a couple of things I
| would add to this sentiment.
|
| First, if you love Rust uniquely, I'd argue it might still make
| sense to use Rust to build your first product iterations. If your
| initial team commonly loves Rust, and can't agree on "love" for
| another common language, perhaps Rust is the best language.
| Burnout will happen exponentially faster if developers are
| lamenting the language (n.b. Rust is commonly lamented). I think
| there are enough language/platform options these days for this to
| be an unlikely scenario, but this is to say don't discount your
| passion for a language because it doesn't iterate fast enough.
|
| Second, if the problem your startup is trying to solve is solidly
| in the performance and security realm, it makes sense to start in
| Rust. If your pitch is something like "pandas but fast and memory
| efficient" it also makes sense to start your project in something
| like Rust.
| synergy20 wrote:
| Maybe nowadays we should all use glue-script + compiled-ffi to
| iterate fast while keep performance under control?
|
| e.g python+cffi, or python+pyo3(for rust), or even lua+capi?
|
| do we really need code everything in compiled language these
| days? the cold path can be dealt with by scripting languages, and
| let the c/c++/rust/etc to handle the performance critical path
| instead.
| pjmlp wrote:
| Nowadays?
|
| That is how AOLServer used to be, and all the other scripting
| languages developed as Apache plugins, back in the 2000's .com
| wave, like mod_perl and PHP.
| synergy20 wrote:
| Maybe scripting language was overused down the road? i.e. to
| use it for everything, and use them like a compiled
| language(ruby in rails, php framework, django,etc) that made
| things slow?
|
| point here is that to restrict script languages to glue logic
| for the most part, and always remember to use ffi for heavy
| lifting, not sure how to balance both yet.
| pjmlp wrote:
| That is why PHP eventually got a JIT, initially thanks to
| Facebook experiments compiling to C++, and later the JIT
| proving being capable to generate similar performance.
|
| The problem was exactly that overused, without JIT/AOT in
| the box, with many people shying away from writing native
| extensions, instead adding more boxes.
|
| The difference between doing JavaScript in node with native
| extensions in 2023, and Perl/TCL with native extensions in
| 2000, is exactly that, a JIT.
| cneu wrote:
| The main reason why server-side stuff is slow is poor use
| of the database. Doing e.g. nested loops in a compiled
| language uses way less CPU than a scripting language, but
| it should be done in the DB in the first place.
| dcow wrote:
| I don't agree. I think the author is conflating two things:
|
| 1. learning Rust, and 2. using Rust.
|
| If you take away "Rust made us slow because our team had to learn
| how to use it and thus we had slow iterations and it's harder to
| find hires with Rust knowledge" from the equation, then you
| aren't left with much argument against using Rust early.
|
| The iteration time issue with Rust is solved by experience. We
| use Rust and our iteration times are average. What we gain is not
| performance, that's not a reason we use Rust (for an early stage
| startup, totally agree you burn credits until you can afford to
| care). We gain correctness. And at an early stage, correctness
| without paying for a massive QA team is a huge boon.
|
| There are definitely more mature tools for quickly standing up
| CRUD APIs. If you want a framework that can bootstrap you into an
| OpenAPI with docgen, swagger, all the bells and whistles, Rust
| doesn't do that. But Rust will help force you to write correct
| code that never crashes and handles edge cases it's easy to
| forget about when moving fast in a duck typed language.
|
| The only language we seriously considered over Rust was Swift.
| But Swift's just wasn't quite there yet. It might be today. If I
| was starting something from ground zero today, I'd probably lean
| towards Swift and need to be argued down back to Rust or Python.
| ReflectedImage wrote:
| Well Python code will on average will be more correct than Rust
| code.
|
| I'm not sure why you feel Rust code would be more correct than
| Python code but it certainly isn't true.
| tcfhgj wrote:
| I strongly believe that if I would code anything significant
| my Rust could would be more correct.
|
| The reasons are types and rusts multi threading guarantees,
| which become even more helpful when doing refactorings
| dcow wrote:
| Curious: have you written Rust in a serious capacity before?
| Sodman wrote:
| The author touches on why it matters in the article - either
| you have to restrict hiring to folks who are already rust
| experts (much smaller hiring pool, also usually meaning higher
| comp expectations) - or you have to consider the cost of
| training new/existing staff on Rust. Rust has a notoriously
| difficult learning curve, especially to folks who don't have a
| background in C/C++. As the author mentions, you may be looking
| at 6+ month ramp up time until new hires can comfortably write
| non-throwaway tech-debt free production code. For many startups
| looking to iterate quickly, that's just too slow.
|
| Conversely if you are looking to hire Java folks, you'll have
| an enormous pool to pick from, or if you need to train somebody
| in eg Go - you can do that significantly quicker than you could
| with Rust.
| dcow wrote:
| I was putting that argument aside because that's an argument
| you can make for any language and it changes depending on who
| you know, what circles you're in, etc. It's and externality
| not specific to Rust. You can say the same for Erlang, or
| Swift, or C#, or ...insert language that isn't JavaScript.
|
| What I'm saying is that, disregarding the externalities, I've
| found Rust to be quite a boon and not _inherently_ a bad fit
| for an early stage. YMMV.
| julianeon wrote:
| I find it mystifying that one of the reasons you can supposedly
| pass over Rust, and avoid performance concerns, is to "take the
| free money." Literally.
|
| That is, the free money, in credits, that allows you to not worry
| about performance for a while.
|
| The obvious problem being... "What happens when the free money
| runs out?"
|
| It's not addressed, but the implied answer seems to be "Well, by
| then it'll be six months later, and..."
|
| And? And what? It's still a problem! It didn't go away.
|
| The money deflected the perf concerns for some time, maybe a year
| - but then it's back, bigger and badder than ever.
|
| Rust solves that by not requiring that outlay ever, by being more
| efficient.
|
| Seems like a very poor reason to not choose Rust, to me.
| globalreset wrote:
| At that point startup has revenue so can pay or is dead so it
| doesn't matter.
| dom96 wrote:
| I have the same impression of Rust: great for software that is
| well scoped/defined and needs to be stable and efficient, not so
| much for quick iterations (which for startups is important) and
| software that doesn't need top performance.
|
| I think in general that the Rust hype has outgrown what it's good
| for. If you're writing a web app in Rust then you may want to ask
| yourself if you're making the right choice.
| jeroenhd wrote:
| For simple applications, Rust is actually pretty easy to work
| with in my experience. You don't get a lot of comforts other
| languages provide, but you don't always need those.
|
| The performance difference between a Rust server and other
| languages are incredible, especially in terms of RAM usage and
| concurrent connections per second.
|
| That said, if your program is going to need tons of entities
| stored in a database, I wouldn't even consider a language or
| framework without a solid ORM. Rust has some ORM-lite libraries
| but I'd end up picking a garbage collected language in practice
| just because of the difficulties that low level programming
| bring to such middleware.
|
| Iterating in Rust isn't that hard as long as you don't try to
| cheat your way out. Instead of returning null for methods that
| you haven't implemented, add a todo!, etcetera. You have to do
| things _somewhat_ right the first time. I think that 's good,
| because there's nothing as permanent as a temporary proof of
| concept. You can clone/copy your way out of most annoying Rust
| restrictions at the cost of performance you'd otherwise
| sacrifice by picking a higher level language anyway.
|
| If your startup doesn't know what it's building, you have
| bigger problems than the language you choose.
| dom96 wrote:
| > The performance difference between a Rust server and other
| languages are incredible, especially in terms of RAM usage
| and concurrent connections per second.
|
| Really depends on what "other languages" are here. If you're
| comparing against Python then sure, but if you're comparing
| against Go then the difference isn't that incredible.
|
| > That said, if your program is going to need tons of
| entities stored in a database, I wouldn't even consider a
| language or framework without a solid ORM.
|
| This is actually what I used Rust for recently and honestly
| the ORM situation is pretty good. The language itself is just
| too rigid for this kind of work for too little payoff.
|
| > If your startup doesn't know what it's building, you have
| bigger problems than the language you choose.
|
| That's true at a high-level, but iterating on small
| features/changes fast is what makes or breaks most startups.
| tcfhgj wrote:
| > If you're writing a web app in Rust then you may want to ask
| yourself if you're making the right choice.
|
| ok, I did ask myself this, still going with Rust there ;-)
| japhib wrote:
| For pattern matching and expressiveness in a backend language
| that lets you iterate quickly, I'd highly recommend Elixir.
| innocentoldguy wrote:
| I would reach for Elixir, Phoenix, and LiveView for any new web
| development. We were using Java before and were running into
| major productivity issues. After extensive testing with Elixir,
| Node, Clojure, Go, and a handful of other languages, Elixir won
| out, we rewrote our entire stack, and our productivity
| skyrocketed. I can't say enough good about it.
| twsted wrote:
| "Building a startup in Rust".
|
| I know the hype around Rust, but this is really exaggerated: you
| build a startup for creating a product or giving a service, not
| to have something written in Rust. Your customers should care
| about what you are offering, much more than about which language
| do you use.
| kilgnad wrote:
| Rust is weird. It has high level features that make is superior
| to high level languages like go and python. But the low level
| features like default move semantics inevitably make it harder.
|
| IMO there is merit in making a language that is equivalent to
| garbage collected rust by default with ownership rules similar to
| python. Then the classic rust based ownership and allocation
| schemes are all opt-in syntax-wise in the same way Box is opt-in.
| cultofmetatron wrote:
| Reading this makes me reaffirm my decision to build my startup in
| elixir. At the time, it came down to 3 compelling choices
|
| 1. typescript - I already had 6 years of full stack js
| experience. The ecosystemis full of issues but its all issues I'm
| used to. 2. rust - new kid on the block. the type system and
| speed were compelling but it was still being developed and the
| learning curve was brutal. Plus I was under the gun to get the
| mvp up. we needed to get a working piece of software up and test
| out business assumptions.
|
| In the end I went with elixir. Realtime sync was a huge killer
| feature we were aiming for and phoenix came with the best out of
| the box support for it. Overall productivity was on par with
| javascript while the functional aspects made certain types of
| bugs non issues in elixir. runtime performance has been more that
| adequate. after 3 years in production, we have only recently
| rolled out rate limiting and caching and only as a precaution as
| we've been expanding quickly.
|
| Echoing the author's sentiments, I can definitely see places
| where rust could be better and thanks to tools like rustler,
| we'll be able to bring those in piecemeal as needed.
|
| I'm sure our product would be even faster and more efficient on
| resources if we did it in rust but I'm pretty sure we would have
| more likely run out of runway before that happenned.
| pjmlp wrote:
| Really, unless one needs deployment scenarios where any kind of
| automatic memory management is not an option, there are several
| compiled languages with Rust like type systems and much better
| workflows.
|
| Go pick OCaml, Haskell, Scala or Kotlin with GraalVM or OpenJ9,
| F# with NativeAOT, Swift, Nim, D, whatever.
| mixmastamyk wrote:
| Yes, many times "typing supremacists" and pedantic folks will
| recommend this course of action but it is not a great idea much
| of the time as the piece illustrates. Getting things _perfect_ on
| a code-level up front is rarely what a new project needs.
|
| A more effective strategy for business is to instead prototype in
| something like Python--that's what it's for. This was known back
| in the 90s, and been somewhat forgotten. Django too. Like a
| flexible clay to rapidly sculpt to a first approximation. Then:
|
| 1) Get to product market fit, keep iterating until you do. Do not
| go to step 2 until that happens.
|
| 2) Get the fundamental data models right, get your fundamental
| software design right. Keep iterating until you do. Do not go to
| step 3 until that happens.
|
| This stuff is easier in Python as it gets out of your way. Yes
| use pyflakes, a few tests, and a code formatter to keep you
| honest. But not much more that that. Pycharm for example, if you
| need a helping hand.
|
| 3) When step 1 and 2 are a looking good, then rebuild the
| foundation of your gleaming skyscraper with the steel girders of
| rust, java, and/or other bdsm languages with an already good
| product and design.
|
| Step three may not even be needed if you have a CRUDdy project.
| Complete the typing at that time.
| bayesian_horse wrote:
| How much more performance do you need to get from Rust over
| Python (even Cython, PyPy, Numba, etc) to justify the extra
| development cost?
|
| A 2x gain is certainly not worth it. A 10x gain? Maybe. But that
| is hard to achieve when much of your "compute" is spent on the DB
| side of things. How many startups actually scale out of needing a
| few non-db instances?
| soggybutter wrote:
| My team helps run and deploy a python service that is entirely
| CPU bound. It accepts an input, performs some computation, and
| returns a result without any sort of I/O outside of the
| initiating HTTP request. In the past week it's averaged around
| 144 req/s with a p95 latency of ~1s.
|
| We average ~80 "instances" to maintain this level of
| performance. I have very little doubt that, if given the
| opportunity to rewrite this in rust, we could smash 10x perf
| improvements. Could we also get more perf out of tuning our
| python code better? Definitely. Do I think there's 10-20x
| improvement waiting to be uncovered? No.
|
| Unfortunately (fortunately?) we're at a stage that it makes
| more sense to throw ludicrous sums of money at it than it does
| to ground up rewrite.
| adastra22 wrote:
| Rust easily gets 10x improvement in performance over Python in
| a lot of applications. This is absolutely my experience.
|
| A better statement is that it doesn't get 10x improvement over
| Go, or other ergonomic compiled languages.
| steveklabnik wrote:
| Also in the context of cloud spend: way way way less RAM,
| which can translate directly to dollars.
| ReflectedImage wrote:
| It will be 25x gain on average and your development costs will
| triple. Is that worth it? Depends on what you are building....
| rwaksmunski wrote:
| I don't know, I haven't had a fight with the compiler in a long
| while now. On the other hand a $42 dedicated box benchmarked my
| project's REST API at 270,000req/s. I don't even use a DB, just
| structs serialized in JSON to a disk and a NAS once every few
| seconds. One pet IPv6 only server to manage + CloudFlare (Domain,
| DNS, Cache). Beats today's peak complexity setups, hands down.
| rozgo wrote:
| In startups and projects where Rust is a premature optimization
| this makes sense. But, some startups and projects are all about
| the competitive advantage created by optimizing from day one. In
| these cases, choosing Rust and other early optimizations is the
| main enabler of a unique product.
| rdtsc wrote:
| It's great when wanting to play with cool new technology combines
| with implementing a viable product to sell to customers. But
| those two things don't necessarily go together. Quite often they
| are at odds with each other, and then you have to pick one or the
| other: either we spend resources playing with cool technology, or
| deliver a product customers will buy. Neither is wrong if it's
| your own resources, it's just important to understand that there
| is a trade-off involved.
| dcow wrote:
| Exactly. "Rust wasn't the right choice because we spent too
| much time and resources playing with it." is not an argument
| against Rust. It's an argument against learning a new
| technology while looking for PMF. There's nothing inherent
| about Rust that makes it a _poor_ choice to build a first
| iteration of a product with.
| tegiddrone wrote:
| I worked with a shop that wanted to use Rust for their shiny new
| MVP. And they did... and yes we were not really good at training
| nor could prioritize/attract rust-experienced devs. The Lead rust
| dev left due to personal reasons and then we were left with a
| codebase nobody really had the knowledge/insights to support
| while rapidly iterating. We smiled and rewrote it in node.js.
|
| I think devs get burned when the MVP turns into forever code and
| somehow are not given room to refactor/rewrite once validated...
| or they are surrounded by devs who are used to pain/bug-cycle and
| they (or the business) will accept doing things haphazardly as a
| cost of doing business. Fred Brook's Second-System effect comes
| to mind.
|
| Ah ha! Rust! Now we HAVE to write good code because rust has so
| many protections!!
| tijsvd wrote:
| Never combine new tech with new functionality. If you want to
| learn new tech, use it to rewrite an old project that was due
| anyway. If you want to build new functionality, use tech that
| you know.
|
| This has nothing to do with Rust. I've seen the exact same
| thing happening with golang in a C++ only environment. Long
| project, took forever, failed slowly, took a week to rewrite in
| C++.
| jeroenhd wrote:
| I can't fathom why a company would write code in a language
| that most of its developers aren't at least somewhat
| experienced in.
|
| If you're writing a program in Rust, hire Rust devs or invest
| heavily in educating the devs you do have first.
| hardwaregeek wrote:
| I write a lot of Rust. I think you can do a startup in rust but
| you need to explicitly go against the natural inclinations of
| rust. Rust is a great language partially because it cares about
| the details. It'll do stuff like distinguish between Path and
| String because it treats the edgecases as important. In a startup
| that's not really a priority. In fact focusing on edgecases and
| doing things the "right" way is completely not the point of
| writing code in a startup. Rust is also a great language to
| refactor, something that's also not ideal for a startup to be
| spending cycles on.
|
| Would I do a startup in rust? Maybe. It'd depend on the idea. But
| I'd take measures to avoid the natural orthodoxy of Rust.
| unshavedyak wrote:
| So.. i'm going to disagree, Rust _(or any language!)_ is fine for
| prototyping. The trick is don 't experiment when you're needing
| to rush a product out. Pick what you and your team is most
| comfortable in.
|
| Avoiding allocations in Rust, on purpose, and being uncomfortable
| with how to solve design challenges caused by hyper optimizing
| your code .. is not a Rust problem. Or an any language problem.
| Rust gave you rope and you hung yourself with it.
|
| If you're stubborn and you want to use Rust but aren't familiar
| with the ways to avoid this; Allocate. Use Arc, Rc, Clone, etc.
| It won't hurt, it won't be terribly slow, and it almost assuredly
| won't be slower than your prototype languages.
|
| Some might reply "Well then why use Rust!?", to which i would
| reply because i like it! I love Rust, but if i'm prototyping code
| i'm not going to write insanely abstract generics either. Why
| would i? I don't know the problem i'm solving yet, so how can i
| write truly generic abstractions to solve said problems?
| Performance is similar. I'll use lifetimes will prototyping in
| the simple cases, which is most to be honest, but beyond that
| don't hyper optimize.
|
| To summarize: Choose your favorite language at crunch time. Even
| if your favorite language gives you rope to hang yourself with
| you probably don't need to.
| dgb23 wrote:
| > Use Arc, Rc, Clone, etc. It won't hurt, it won't be terribly
| slow, and it almost assuredly won't be slower than your
| prototype languages.
|
| I very much doubt that. It's likely true for straight up
| wasteful languages but very unlikely for more optimized
| runtimes.
| maleldil wrote:
| > It's likely true for straight up wasteful languages but
| very unlikely for more optimized runtimes.
|
| What are you comparing it to? I believe parent meant that
| even if you clone everywhere, your code is still more likely
| to be faster than Node/Python, and potentially Go/C#/Java.
|
| One thing to note is that C++ code tends to allocate all over
| the place from copy assignment and constructors, and it's
| still very fast. Rust only forces you to be explicit when
| cloning, but memcpy is still a fast operation, unless you're
| cloning large structs.
| dgb23 wrote:
| > your code is still more likely to be faster than
| Node/Python, and potentially Go/C#/Java
|
| Python very likely, Node probably too, not sure. I doubt
| it's true for the others. My guess is you're going to use
| less resources (memory etc.) but you're not going to beat
| their runtimes with hand-rolled GC (ref counting) and
| allocations all over the place.
| unshavedyak wrote:
| Really depends on what you're doing.
|
| The thing is if you know enough about why cloning is slow
| - like a really fat string or a tight loop - you probably
| also know enough to avoid that. At least in my
| experience.
|
| There's a ton of rope in Rust with lifetimes, generics,
| etc. Most if not all generic bounds have implications
| about the user and caller. Choosing which type of methods
| you use to avoid allocation while prototyping can be
| exceptionally difficult to do and be correct.
|
| Refcounting is not that bad imo, and is very very easy.
| The moment you're at "well we need to beat the
| performance of X" is probably when you can make
| better/intelligent decisions about how you allocate,
| whether to use Arena/Bump/etc.
|
| Also, if you wanted to be in Go/C#/etc you just would.
| You're using Rust (in this discussion) because you wanted
| to. When performance is a concern, you can deal with it -
| but the basic allocation tricks (Arc/etc) don't represent
| such a significant performance loss that suddenly your
| Prototype no longer functions.
| dgb23 wrote:
| Right, I missed the broader point. When you choose to use
| Rust but need to advance quickly, you are going to be
| fine with some of these techniques.
| jmull wrote:
| Since safety was the first reason given for using rust, I'll just
| point out:
|
| There are other safe languages.
|
| I think it's a really useful thing to have from day one, but it
| doesn't particularly point you to rust.
|
| Also, performance is really about learning what your bottle-necks
| are, profiling them and optimizing them. You probably have no
| idea what those are when you start, so it's not really the right
| time to try to solve it. (There's a decent chance, e.g., that
| your inner loops won't even be in code you write, like the
| database.) Probably the best thing you can do for long-term
| performance up-front is to try to stay flexible, and try to keep
| your architecture simple.
| ReflectedImage wrote:
| Rust does a bit more on the safety front than typical
| programming languages.
| dcow wrote:
| Really? I guess if your typical programming languages are C
| and C++.
|
| Otherwise Rust just has semantics that allow more control
| over memory, as is often needed in lower level programs,
| while preventing pointer aliasing. The majority of languages
| in existence are memory safe--some even more so than Rust.
| They're just not as flexible.
| ReflectedImage wrote:
| It's much better than Java, Kotlin and C#.
|
| The borrow checker detects the majority (~95%) of
| concurrency problems. We don't have that many single core
| CPUs lying around anymore.
|
| It's got a story on high performance, high concurrency
| programs which is significantly better than anything else
| I've seen so far.
| dcow wrote:
| I'll give you that.
|
| The reason I questioned is because in my experience with
| those languages the 95% problem is not the actual data
| consistency rather it's locking and synchronization hell
| that results from needing to make your program threadsafe
| to ensure data consistency. Rust says, don't get yourself
| in a situations where you need to do that in the first
| place, it's not safe. Just clone the data or leak it read
| only or Cow it.
|
| What Rust does is great, it sets you up so you're never
| sharing references across threads unless you try really
| really hard. And that's the source of needing manual
| synchronization the majority of the time. However, when
| you do need locks, Rust doesn't do anything to help. In
| other words, if you copied a Java program to Rust with
| object instance pointers all over the place, I bet it
| would feel just as bad in Rust.
|
| So I tend to think of that more as "thread safety" than
| "memory safety". But we might just be arguing semantics
| at this point. I agree Rust is far more of a pleasure to
| work in than Java and C#.
| royjacobs wrote:
| My biggest pain point with Rust (in a startup context) is that
| Rust works really well, until you get to anything related to
| threading or async.
|
| Yes, the claim is "fearless concurrency" but you'll still
| deadlocking mutexes and once you're heavily into async you need
| to start using language constructs that feel REALLY awkward, like
| pinning, runtime checks like RefCell, and so on.
|
| IMO if Rust could make that whole aspect of the language more
| elegant, it'd be much easier to scale up to a larger org.
| dcow wrote:
| I honestly think Swift nailed it. Swift's async/await is a
| pleasure to work with and has the required
| language/runtime/stdlib support to feel natural and empowering
| instead of ridiculous and suffocating.
| Aissen wrote:
| Crazy to think that cloud credits, in addition to distorting the
| hosting competition, might also distort the language choice
| competition...
| ReflectedImage wrote:
| The first hit of cloud is free but once they have you hooked
| they charge an arm and a leg afterwards.
| ParetoOptimal wrote:
| > I can't get it why people would prefer to add "?" to everything
| instead of just having exceptions which automate that behavior.
|
| Good question... Maybe...
|
| Because with exceptions it's easy to end up with missing cases or
| unhelpful catch-all exceptions.
|
| Typically with optional values I find that this is not the case
| for some reason.
|
| Other interesting links I've yet to consume that may help us get
| closer to an answer this:
|
| https://news.ycombinator.com/item?id=22225170 - "You're better
| off using exceptions"
|
| https://softwareengineering.stackexchange.com/questions/4050...
|
| https://dannyvanheumen.nl/post/why-i-prefer-error-values-ove...
| legerdemain wrote:
| In my experience with Palantir "alums," none of the crotchety
| perfectionists I knew ended up working with Rust after leaving. I
| guess AI (as the author of this post is affectionately known)
| beat the trend by starting his own company!
| andrewstuart wrote:
| "I find myself missing match in pretty much every other language
| I go to."
|
| Python has match, is this the same thing?
|
| https://blog.teclado.com/python-match-case/
| weavie wrote:
| I've been writing Rust professionally for a few years now and if
| there's one thing I've learned it's that if you ever write a
| function that takes a parameter of `impl Fn(&Vec<&'a str>) -> &'a
| str` you are going to be in for some pain. Just make it `impl
| Fn(&Vec<&str>) -> String`. It is highly unlikely that the extra
| allocation is ever going to be noticed in the performance.
|
| Just because Rust pretty much forces you to be explicit about
| your allocations doesn't mean you have to avoid them at all
| costs.
| jossclimb wrote:
| A lot of programmers will look at '`impl Fn(&Vec<&'a str>) ->
| &'a str`' and think what the hell is that, alien hieroglyphics?
| ModernMech wrote:
| > It is highly unlikely that the extra allocation is ever going
| to be noticed in the performance.
|
| I had almost this exact scenario, and yes there is pain in
| writing it with explicit lifetimes. But I can't agree the
| performance improvement is negligible; maybe in isolation, but
| I saw about a 100x speed increase for my application when I
| switched away from Strings. For me it was because I was doing
| many of those extra String allocations in a loop, so it killed
| my performance.
| estebank wrote:
| This is not an uncommon pitfall when working with strings in
| all languages. In Java for example it is drilled into people
| to use StringBuilder instead of concatenating with + on
| String if you do it in a loop, precisely because of this
| exact issue.
| weavie wrote:
| For sure, optimise when necessary. Rust lets you do this.
| estebank wrote:
| One day I need to get around to figuring out how to detect when
| people are going in circles with lifetime errors and have rustc
| open https://keepcalmandcallclone.website/ for them.
| tjdetwiler wrote:
| You can still return the str reference; callers can easily do
| the copy if they need while allowing for zero-copy for simpler
| usages.
| BaculumMeumEst wrote:
| [flagged]
| bruce343434 wrote:
| thanks for running this through chatgpt for me
| BaculumMeumEst wrote:
| Hacker News has never allowed bots or generated responses
| on the platform. All content posted on Hacker News should
| be generated by humans, and any form of automated or
| algorithmic content creation is not allowed. This policy is
| in place to ensure that the content on the platform is of
| high quality and relevant to the community.
|
| Edit: Please stop downvoting me. I'm trying to contribute
| to the discussion, and I think my perspective is valuable.
| bryanlarsen wrote:
| I disagree, I believe that Rust is a fabulous language for early
| prototypes.
|
| Sure, if you're going to throw away your early prototype there
| are better languages. But nobody ever does that.
|
| Instead your prototype evolves into your product and early
| expedient decisions you made that were appropriate for a
| prototype aren't appropriate for your product and you have a
| significant refactor.
|
| And Rust is the best language I have ever encountered for
| refactoring. Just bang away changing the code until it compiles,
| and it's quite likely that once it compiles it actually works.
| That's not an experience I've had in any other language. Usually
| a significant refactor exposes some foot-guns that don't fire
| until significantly later. So you avoid refactoring and your code
| ends up a right mess.
| mike_hearn wrote:
| Have you tried something like Kotlin? It has the same
| experience IMO of being very easy to refactor, especially
| because the IDE can do so many refactorings for you very fast,
| and because the compile turnaround time is so low.
| jay-barronville wrote:
| > _Sure, if you 're going to throw away your early prototype
| there are better languages. But nobody ever does that._
|
| You can't be serious. I've seen prototypes get thrown away all
| the time, _especially_ at startups. In fact, I'd say that's
| more common than not.
| hinkley wrote:
| One of the things I've vowed to do for my next interview cycle
| is set myself up an empty project with test, and it is
| appalling how many interviewers assume that implementation
| without any tests is something a senior developer won't simply
| laugh at the suggestion and leave the room.
|
| It takes too long to do these basic steps and then copy them to
| new projects. And generators only work once, if then, which
| means they are most useful in languages that have stopped
| iterating, which is not that compelling.
|
| I'm hoping the next version control system solves the rerere
| problem and we can build our projects by forking a template
| project, then pull commits from upstream as necessary.
| Sodman wrote:
| You have to remember though that coding interviews !=
| production code. Taken to the extreme, are you also adding
| logging, metrics, performance benchmarks, etc?
|
| TDD is great if you can get it working in a tight interview
| time schedule - they can also reveal any misunderstandings of
| requirements before the actual solution is implemented!
|
| On the flip side however, many interviewers have experienced
| countless folks who spend the majority of the interview time
| on tests and setup, only to run out of time on delivering the
| solution to the actual presented problem. When I feel like
| somebody's spending too long on these things I'll try to
| nudge them towards wrapping up the tests and moving onto the
| solution. You would be surprised though by just how
| frequently it's met with open hostility, by candidates with
| only 10-15 mins left in an hour-long interview and no
| solution started!
| hinkley wrote:
| And in a real situation I have all of these tools set up
| and running, so I shouldn't need to spend more than a
| minute faffing about with them. I'm just writing
| exploratory tests to make sure that I've got the bits right
| before I put them together. Even in an hour task those
| tools can be a force multiplier, once you figure out how to
| make them work instead of fighting them constantly.
|
| What's happening in interview loops is that we're
| implicitly or explicitly selecting for people who prefer to
| YOLO instead of writing tests, and then we are surprised
| how hard it is to get new and existing hires on board with
| mature testing processes. The people you need don't work
| here, they work somewhere else.
| crispinb wrote:
| > But nobody ever does that.
|
| Please don't report your own experience samples as plain
| universal facts. It is one of the more common means by which
| falsehoods spread. I have no doubt that's not your intention,
| and you believe what you write, but you cannot have a basis for
| such a bald statement, and it happens to be false.
|
| I have seen prototypes built and discarded very frequently.
| Indeed in an earlier incarnation it was my own professional
| focus.
|
| I have no idea how common it is in your country, or globally,
| or in specific industrial sectors. Usable stats in tech are
| hard to come by (in large part because of its ubiquity). But
| your statement is just false, and commonly repeated.
| CharlieDigital wrote:
| > I believe that Rust is a fabulous language for early
| prototypes.
|
| The problem is that TypeScript is an even better language for
| early prototypes.
|
| zeroxfe has the right answer:
|
| > If your answer is something like Go or Node.js, then Rust is
| probably not the right choice.
|
| > If your answer is C or C++ or something similar, then Rust is
| very likely the right choice.
|
| The only reason one would choose Rust over TypeScript is if one
| would have chosen C/C++ instead.
|
| Then if you need higher perf/throughput: Go, Java, and C# in
| particular are all options that I'd consider before C/C++ or
| Rust. C# in particular is highly congruous to TypeScript [0].
|
| JavaScript, TypeScript, and C# have been converging, IMO (and
| that's a good thing). Seems really natural that if you're a
| startup finding PMF, start with TypeScript for iteration speed.
| If you need higher throughput, C# is a stone's throw away from
| TypeScript syntactically and it's pretty easy to hire for
| (compared to Rust). [1]
|
| Pick Rust if you're building something highly performance and
| memory sensitive. Pick TypeScript and C#/Go/Java for almost all
| other cases.
|
| [0] https://github.com/CharlieDigital/js-ts-csharp
|
| [1] https://raw.githubusercontent.com/CharlieDigital/js-ts-
| cshar...
| packetlost wrote:
| I think it depends on what you're doing. I'd argue statically
| typed Python (ie. with type hints) is also good for an early-
| prototype language and has the benefit of being able to swap
| out _parts at a time_ via C FFI with Rust or something like
| PyO3. Pypy with asyncio (so FastAPI?) is what I 'd choose for
| a web framework these days, personally.
| CharlieDigital wrote:
| I agree; Python is a great choice especially if whatever
| you're building is heavy in math and/or ML. The ecosystem
| is just better so it makes sense then to build your backend
| stack with Python.
| throwawaygal7 wrote:
| People who are really interested in rust tend to be top-tier
| developers. I don't think they're consciously lying about their
| experiences working with the language but they may not hit the
| speed bumps that normal people would. My personal abilities make
| me competent in golang, ruby, python, java, c++. I love the
| quasi-functional styling of rust but whenever I've tried to build
| small projects in it I've gotten bogged down in fighting with the
| compiler in ways I never do in the former. It is fast as all get
| out tho!
| PaulHoule wrote:
| I can't get it why people would prefer to add "?" to everything
| instead of just having exceptions which automate that behavior.
|
| In the bad old days of C there were two kinds of programs:
| programs without correct error handling, and programs where half
| the loc are unhappy paths that do what exceptions do... with a
| huge amount of work.
|
| Today people are repeating the same mistakes of the past, putting
| a "?" on everything is a lot better than what you had to do in C,
| but why do that when you can just use a language with exceptions?
|
| It is like somebody showed cavemen fire (exceptions) and they
| decided it wasn't worth anything and went to go screw around with
| other things.
| User23 wrote:
| Exceptions make it considerably harder to reason about state by
| reading the program text. As the notion that programmers should
| have some actual understanding of what they write slowly
| becomes less unfashionable, language features that make
| understanding code needlessly harder are losing some of their
| appeal even though they speed up writing the code.
| PaulHoule wrote:
| What really makes code hard to read is having multiple paths
| to disentangle. There is one little error deep in the call
| stack but you have to vandalize the 10 functions above it in
| the call stack to carefully separate the error and non-error
| paths -- what's the probability that you will end up cleaning
| up properly in both paths when it isn't done for you with
| finally? What's the probability that somebody looking at this
| code is really going to find the subtle error in the error
| path or an error in the happy path caused and hidden by the
| complexity of the unhappy path?
|
| I think the first C program I saw was a type-in terminal
| emulator from Byte magazine around 1985 and I was struck by
| the akwardness of the error handling in the C stdlib, spent a
| lot of time looking at the code when I realized the author
| had "spaced it" at one point such that the error handling was
| wrong and thought "this sucks" but learned how to write C
| programs with 3x the LOC because of all the alternate paths I
| had to put in to handle errors.
|
| When I saw exceptions for the first time I felt strongly
| liberated because I got for free what I was working for so
| hard in C so I got to spend more time thinking about
| algorithms, the needs of the customer, things like that.
| adamnemecek wrote:
| They are not the same. Errors force you to explicitly handle
| unexpected conditions. Exceptions don't. And "?" is for making
| error handling not take up half of loc.
|
| Read up on how exceptions work in C++ implementation-wise. It's
| not pretty.
| PaulHoule wrote:
| That's C++. It puts the C in Cthulhu.
| saurik wrote:
| That's the problem, though, right? 99.999% of the time you
| absolutely should not be "handling" an error: you should
| merely propagate it so it gets closer to code that has actual
| intent. Languages that force you to try to "handle" errors--
| which includes Java, due to their botched concept of checked
| exceptions--both encourage the wrong behavior in the
| developer and cause the code to be littered with boilerplate
| to implement the propagation manually.
|
| Meanwhile, they manage to encode the concept of "can fail"
| into not merely the type signature of a function but into the
| syntax used to access it, when--like other monadic behaviors,
| including "requires scoped allocation"--this is the kind of
| thing you tend to need to refactor into a codebase at a later
| time: instead, the code should always be typed as if
| everything can fail and everything can allocate (not just
| memory, but any resource); languages that get this right--
| such as C++ and Python--thereby deserve their stickiness.
| veqq wrote:
| > you absolutely should not be "handling" an error: you
| should merely propagate it so it gets closer to code that
| has actual intent
|
| Why?!
|
| There are 2 types of errors:
|
| - an error in your program logic, which you need to fix
|
| - an error from something out of your control (network
| down, disc errors, faulty input... Which you certainly must
| handle
|
| What's the alternative? Let errors trigger undefined
| behavior and corrupt your DB? Not pretty.
| taeric wrote:
| > and programs where half the loc are unhappy paths that do
| what exceptions do... with a huge amount of work.
|
| This made me laugh harder than makes sense. I'm sure I've been
| guilty of doing said code, as well.
| jakelazaroff wrote:
| Exceptions come with their own weirdness. Usually, if you want
| to handle an exception, you need to wrap the code that could
| generate it in a block, which means any variables declared
| there won't be available in the parent scope. I'd much rather
| have the ability to just write normal code and deal with the
| error on the spot, along with some syntactic sugar (such as
| "?") to return that error to the caller.
| flohofwoe wrote:
| The problem with exceptions isn't the syntax, but the hidden
| control flow (they are essentially a goto in disguise).
|
| Error union return values make _a lot_ more sense, the rest is
| just syntax sugar details (and that 's where opinions differ I
| guess).
| gpderetta wrote:
| Exceptions are not a form of gotos, they are both less
| powerful as they are structured and more powerful (as they
| are nonlocal). They desugar to continuations, but so does
| rust option type handling and ?. In fact they are pretty much
| equivalent.
|
| I'm not terribly familiar with either language, but I don't
| see any particular difference between swift and rust error
| handling for example, swift will also mark fallible function
| calls with try, similarly to ? in rust.
|
| For what is worth the author of the swift standard library
| believes that try is a mistake: as most functions can fail in
| practice it just becomes noise. It might be more useful to
| mark can't fail regions.
| jstimpfle wrote:
| If you consider the case where you call a function that
| throws an exception without you expecting it -- then the
| control flow will skip your code, and this is indeed not
| very structured, like a goto, and in fact less local than a
| goto.
| vore wrote:
| I think the nonlocal part is the scary part: it becomes
| very scary to figure out which parts of the code can fail
| and how, especially when failures can come from an
| arbitrarily deep call stack.
|
| Maybe checked exceptions could be more useful to explicitly
| annotate allowed failures, but at the same time we all know
| how that's going in Java world.
| kcartlidge wrote:
| My two main languages are C# and Go.
|
| * C# uses exceptions, and when I code it feels exactly the
| right choice
|
| * Go uses error return values, and when I code it feels
| exactly the right choice
|
| For some reason both feel very much ideal in use. Maybe it is
| because in each case the language syntax/ethos fits very well
| with the choice made, and so is frictionless when developing
| in the flow (and if used properly of course)? Maybe some
| other reason. Hey ho.
| [deleted]
| larusso wrote:
| How would an exception automate the behavior of ,,?"?
|
| What ? does in rust is to unwrap the result check if it is err
| and return from the function with an error result. On top of
| that it will auto-convert the error type (if the type has the
| from/into traits implemented)
|
| So it would do:
|
| try { //the code that may fail } catch (error) { //do we just
| throw the same error? //or convert the exception to a custom
| other exception }
|
| If I see an API that throws me an low level exception without
| context I go mad. Like an file not found exception etc when
| executing an API that does multiple file IO operations.
| Conscat wrote:
| Exceptions make it difficult to find failure-points in the
| code. The ? annotates that at its call site, which improves
| discoverability by a lot and reduces readability by only a
| little.
| lenkite wrote:
| > Exceptions make it difficult to find failure-points in the
| code
|
| My experience doing Java, Go and Rust has been completely the
| opposite. Exception stack traces in Java are _amazingly_
| wonderful things - they _exactly_ pin-point the failure
| points in the code. The amount of hunting I need to do to
| find out where something failed in the call stack in Go /Rust
| is tedious. You _need_ a module /crate for error tracing or
| you up waddling against a strong current of despair.
| pclmulqdq wrote:
| There's some subtlety here:
|
| 1. Exceptions have very high performance costs (equivalent to a
| longjmp which is very slow), so if you expect to have
| exceptional cases, it's probably a lot more efficient to not
| use exceptions.
|
| 2. Exceptions break the linear flow of the code when you read
| it, so now you have to read a lot more code to figure out what
| the exception paths are and where and how they are handled.
| planede wrote:
| > Exceptions have very high performance costs
|
| On the sad path. On the happy path they are faster than
| explicit error checking.
| pclmulqdq wrote:
| Kind of yes, and kind of no. On the happy path, if errors
| are very very rare, the check is also basically free thanks
| to branch prediction. They start to cost something when you
| start to add a higher frequency of errors, which
| incidentally is where exceptions cost a lot more.
| mike_hearn wrote:
| The cost is higher because of all the branches that are
| scattered everywhere to check return codes. With
| exceptions there's a check at the place the error is
| thrown, but that's inevitable. There aren't checks
| scattered throughout the rest of the code, which would
| otherwise reduce icache utilization.
| pclmulqdq wrote:
| Arguing about icache utilization is a little silly here -
| the code will be laid out for you as though the branches
| are not taken (or you should force it to do so). In that
| case, the only "waste" of icache is the CMP and JMP, an
| additional 4-8 bytes per return, and literally 0 cycles.
|
| When you do take an error, each RET takes you 1 cycle,
| plus the 10-15 cycle mispredict for the CMP+JMP because
| there's a stack engine in the CPU that tells you the
| address to return to. It's counterintuitive that doing "a
| lot" of things is cheaper than doing fewer things, but
| it's true.
|
| In comparison, an exception involves taking the one
| control flow break to some cold control code (maybe page
| faulting), figuring out where to go using a jump table
| (slow), restoring the old state from that context (slow),
| figuring out the type of the thrown object (in many
| languages, also slow), and then handling accordingly.
| Each of these steps can easily take 100+ cycles, and may
| be more.
|
| The math does not work out in favor of exceptions.
| Neither do the benchmarks in most cases. You do 1 slow
| thing to avoid doing 20 things that are trivially fast.
| mike_hearn wrote:
| The checks you're talking about are duplicated more or
| less per statement in some types of code. Every single
| call site ends up with an `if err != nil` or moral
| equivalent. It can add up, also consider the extra
| register pressure. The return values aren't valuable
| anymore, they're just error signalling.
|
| The compiler doesn't necessarily know what your error
| types are, it can try to use heuristics to move those
| blocks around but it's not like an exception where the
| types are a part of the language and the compiler can
| know that. We're talking about startup code here, nobody
| will be annotating their error branches with manual
| predictor probabilities, so we're limited to what the
| compiler can do.
|
| Yes the act of throwing an exception is more work but
| it's exceptional, so doesn't matter. The slowest part is
| calculating the stack trace anyway and that's of huge
| value, which you don't get with error codes anyway.
| pclmulqdq wrote:
| There's no register pressure - CMP EAX, EAX // JNZ
| $ERROR_HANDLER is the instruction sequence we're talking
| about. Most error types are enums where 0 = "good" and
| any nonzero value is not good. This is the inverse of the
| "null pointer check" in C. It consumes no registers and a
| negligible number of code bytes.
|
| There is obviously a sparsity of exceptional cases where
| error-handling code like this is worse than using
| exceptions. I would claim that it's a lot more sparse
| than you think. Many people use exceptions for things
| like "file not found" or "function failed for whatever
| reason," (my favorite) "timeout," or "bad input from the
| user." These cases are often not that exceptional!
| codethief wrote:
| > Exceptions have very high performance costs (equivalent to
| a longjmp which is very slow)
|
| Could you elaborate on why they are so slow, compared to
| passing around/returning error objects explicitly?
| pclmulqdq wrote:
| They are slow because you need to restore context from an
| unknown/unpredictable place in the code, you have a table
| lookup (from a very cold table) to get the next program
| counter value, and you have to save and restore register
| values, while the callstack and the calling convention
| handle all of that complexity for you if you don't break
| the natural flow of the program.
| gpderetta wrote:
| 1. Exceptions as commonly implemented in C++ have high
| overhead in the exception path. But that's just an
| implementation strategy. There is no reason why it wouldn't
| be possible to generate exactly the same code as for an
| optional type if desired (and in fact it was proposed for c++
| cf. Herbceptions).
|
| 2. So do returns, but we have long settled that SESE is
| undesirable.
| marcosdumay wrote:
| > It is like somebody showed cavemen fire (exceptions) and they
| decided it wasn't worth anything
|
| Oh, it absolutely can not be that the Rust way is more powerful
| and you didn't understand it yet. No way. It's all those other
| people that don't understand the old concept that almost all of
| them know.
| oconnor663 wrote:
| I mean, ask the C++ community. They've had exceptions forever,
| but a large chunk of them forbid exceptions in their codebases.
|
| I think there's a pretty good rule of thumb in modern systems-
| ish language design: If Go and Rust and Zig all do a certain
| thing, that thing is probably a great idea. These languages
| have very different priorities, but often they overlap.
| ngrilly wrote:
| Zig, unlike Go and Rust, provides an error return trace
| showing how the error bubbled up. This is a really
| interesting idea.
|
| https://ziglang.org/documentation/master/#Error-Return-
| Trace...
| chomp wrote:
| It's mostly philosophical, are you fine with blowing up with an
| exception, or would you rather have your functions return known
| values for the unhappy path? I personally like exceptions in
| exceptional cases, but much rather having functions with
| explicit contracts (e.g. "this will return either True or False
| in all input cases", not "this will return either True, or
| Exception in all cases when $foo doesn't exist in the database,
| and woe unto the programmer that forgets to catch this.")
| MaulingMonkey wrote:
| In theory, I like exceptions. In practice, I hate them. Few
| languages statically check exception handling - e.g. Java, and
| even then only partially - leading to stability-ruining edge
| cases leaking into production in the most unexpected of places
| caught only by QA if you're lucky. Exception handling codegen
| can also be rather atrocious, leading to unavoidable
| performance degredation when third party middleware throws
| unavoidable exceptions, even when you _do_ fix the stability
| bugs. They 're also a nasty and reoccuring source of undefined
| behavior when they unwind past a C ABI boundary, an issue I've
| encountered in multiple codebases with multiple exception-
| throwing languages. In my personal experience, programmers are
| also rather terrible at writing exception-safe code.
|
| Result and ? force you to think about - or at least acknowledge
| - the edge cases. For a throwaway script or small scale easily
| tested program, that might be a drawback. For MLOC+ codebases
| where link times alone are sufficient to start impeding testing
| iteration times, it can be a big help for correctness and
| stability, while still being relatively lightweight compared to
| other manual error handling.
|
| Finally - Rust _has_ exceptions. They 're called panics. They
| can be configured to abort instead of unwind. This helps set
| the tone - they're really meant for bugs, and _exceptionally_
| exceptional circumstances. They cause all the problems of
| exceptions, too - unconsidered edge cases, undefined behavior
| unwinding past C ABIs, the works. Fortunately, it 's reasonable
| in Rust to aim to eliminate all panics but bugs.
| PaulHoule wrote:
| See
|
| https://gen5.info/q/2008/07/31/stop-catching-exceptions/
|
| and
|
| https://gen5.info/q/2008/08/27/what-do-you-do-when-youve-
| cau...
|
| It's very important to minimize the burden of handling errors
| in code with simple control flow. Frequently I see people
| _try very hard_ to handle errors with monads in languages
| like Scala at the micro level and they are so burned out by
| this that they don 't put any effort into handling errors
| properly at the macro level.
|
| If you make the micro level as automatic as you can it is
| possible devs will address the macro level, and what is
| necessary at the micro level is not dealing with a crisis
| that prevents the compiler from building your code, but
| rather cleaning up the environment consistently in both
| normal in error conditions and giving the macro level
| sufficient context for the error that it can do the right
| thing.
| MaulingMonkey wrote:
| Micro and macro are both important.
|
| I've built crash collection and deduplication systems, I've
| heard of triage that helps discount crashes generated by
| hardware failures or overeager overclocking. I've collected
| telemetry and setup symbol servers and source indexing to
| streamline bug squishing, and helped build systems which
| verify game content up-front to discover even non-code bugs
| before they're shipped to users, and to properly attribute
| said errors to the content that generated said errors in an
| easily navigatable and fixable way. I've helped engineer
| error-tollerant systems that won't require handholding by
| engineering to recover from bugs. Plenty of focus on the
| macro.
|
| But all it takes is a single uncaught exception slipping
| past QA to cause one to consider a recall of physical
| product, even in this era of ubiquitous internet, for a
| handheld console game for something as trivial as a missing
| or corrupt sound effect. If things at the micro level are
| neglected too much, and nothing you do at the macro level
| can really mitigate that in a sane manner... except use
| tools that check you're doing things right at the micro
| level. And I have yet to see exceptions handle that micro
| level particularly well.
| duped wrote:
| fn foo () -> Result<(), E1> { .. } fn bar () ->
| Result<(), E2> { foo()?; }
|
| This requires `bar` to have a function signature that notes it
| may error, `E2` must implement `From<E1>`, and the caller of
| `bar` must use the result or explicitly silence the warning.
| Meaning if a program creates a Result the error must be handled
| - you can't silently let errors bubble up through the call
| stack.
|
| `Result` implements some common combinators like `.ok()` to
| convert to `Option`, `map`, `map_err`, `or_else`, etc to
| reflect the common cases of error handling.
|
| And finally, since Result doesn't require non-local control
| flow like exceptions you know that `drop` will run as the
| functions return back up the callstack.
|
| And if you want to use Result like exceptions... you can. But
| you can't hide it from callers, and callers are still free to
| handle them elegantly.
| Larrikin wrote:
| Despite what CS and SE classes try to drill into you, null
| results or failure cases are nearly always better handled right
| when they happen instead of passing them up with layers of
| exception handling. Log it, pass null up, and just immediately
| handle it. Fail early and none of the rest of the function
| matters.
|
| Even types of exceptions are rarely useful results outside of
| reading the logs or sometimes in libraries outside of your
| control.
| 8note wrote:
| The most important considerations for errors is whether they
| can be retried, and who needs to change something to fix it.
|
| The types can be useful for communicating this
| orthecreedence wrote:
| > I can't get it why people would prefer to add "?" to
| everything instead of just having exceptions which automate
| that behavior.
|
| Exceptions? Which exceptions? How do you know which exceptions
| you're supposed to be handling and where they come from or when
| they happen?
|
| I prefer the control flow of the program and the exact types of
| errors I'm handling to be explicit.
| jeddy3 wrote:
| IMHO both exceptions and error handling in Rust (and others)
| have their upsides and downsides.
|
| Personally, I much prefer Rusts solution, being both more up
| front and at the same time more terse.
|
| The metaphor is kinda stupid though, the "cavemen" in our
| scenario knows very well that exceptions exist.
| nemothekid wrote:
| I prefer having extra work done _writing_ code (adding "?")
| than having to do extra work _reading_ code. Exceptions are
| functionally invisible control flow; it isn 't clear to the
| reader that a function may blow up if the exceptions are
| unhandled.
| jb1991 wrote:
| In Swift, at least, the possibility that a function can throw
| must be marked as part of its signature, and the exception
| cannot be ignored if it is thrown so the call requires
| explicit syntax as well, so there is no way to miss that
| something could "blow up" when reading the code.
| eunoia wrote:
| It's a little old at this point, but I find the Swift Error
| Handling Rationale design doc to be absolutely fascinating.
| It cites other language's error handling paradigms
| (including Rust) if you're curious:
|
| https://apple-
| swift.readthedocs.io/en/latest/ErrorHandlingRa...
| jb1991 wrote:
| Fascinating, looking forward to reading this later today!
| Have used a handful of languages over the years, and I
| don't have any academic perspective in different error
| handling techniques, but there's no doubt that the way
| swift does it feels particularly natural, safe, but still
| gets out of your way. I love all the options for handling
| errors in a meaningful way.
| Jensson wrote:
| In Java functions declares Exceptions in its type signature,
| so it does all of that automatically. Then you get a compile
| error if you don't handle it in the function, or you need to
| declare the function throws it, so it is type safe.
|
| Note that people now consider that as a mistake, people
| prefer having Exceptions be hidden instead of explicit and
| requiring handling like that.
| orthoxerox wrote:
| Java isn't generic over exceptions. You can't write a
| method that takes an instance of Foo and says "my method
| throws whatever Foo.bar() throws" or even "my method throws
| iff Foo.bar() throws".
|
| And this means that your method either always demands to be
| wrapped in a try-catch, or you migrate to unchecked
| exceptions.
|
| Rust makes errors a part of the regular type system, so
| they automatically benefit from all its features.
| mike_hearn wrote:
| > You can't write a method that takes an instance of Foo
| and says "my method throws whatever Foo.bar() throws" or
| even "my method throws iff Foo.bar() throws".
|
| If you could it'd mean altering the implementation would
| automatically alter the API, which would be rather
| unexpected.
|
| That's why the Java approach is to wrap exceptions and
| propagate causal chains. The underlying errors thrown by
| the implementation can change but the advertised
| exceptions don't, but no information is lost.
| auno wrote:
| > Java isn't generic over exceptions. You can't write a
| method that takes an instance of Foo and says "my method
| throws whatever Foo.bar() throws"
|
| If you bend over far enough backwards, and squint a bit,
| you can _kind of_ do that... interface
| Runner<E extends Throwable> { public void run()
| throws E; } class Test {
| public static <E extends Throwable, T extends Runner<E>>
| void test(T runner) throws E { runner.run();
| } }
|
| It compiles. I haven't tried running it though.
| jb1991 wrote:
| > Note that people now consider that as a mistake, people
| prefer having Exceptions be hidden instead of explicit and
| requiring handling like that.
|
| Well, Swift is a much newer language than Java, and
| exceptions in Swift cannot be hidden either. And some
| people do rather like this.
| rom-antics wrote:
| The mistake was not "explicit errors". It was having a mix
| of error types, some explicit and some implicit, with no
| convenient way to combine them, plus the interface
| complications.
|
| Note that most newer languages are choosing explicit
| errors. This includes at least Go, Rust, Swift, Zig, and
| Odin.
| hinkley wrote:
| The second mistake was only flirting with Bertrand
| Meyer's work until the Gang of Four showed up and wrecked
| Java forever.
|
| Meyer + functional core nets you a great deal of code
| with no exception declarations and an easy path for unit
| tests. If it hurts to do stuff it might not be the
| language that sucks, it might be you. Pain is
| information. Adapt.
| theptip wrote:
| Don't know Meyer's work - any suggestions for good
| starting points?
| steveklabnik wrote:
| Learn Eiffel. From their own explanation:
| https://www.eiffel.org/doc/eiffel/Learning_Eiffel
|
| > Remember that Eiffel, unlike other programming
| languages, is not just a programming language. Instead,
| it is a full life-cycle framework for software
| development. As a consequence, learning Eiffel implies
| learning the Eiffel Method and the Eiffel programming
| Language. Additionally, the Eiffel development
| environment EiffelStudio is specifically designed to
| support the method and language. So having an
| understanding of the method and language helps you to
| appreciate the capabilities and behavior of EiffelStudio.
|
| I read "Object-Oriented Software Construction" to do so,
| but it was long enough ago that I googled "The Eiffel
| Programming Language" because my brain had substituted
| that title instead because IMHO, it's more accurate.
|
| The above link should have many current resources for
| you.
| hinkley wrote:
| There's the Design By Contract work of course, but I'm
| still trying to cite what I thought was his best advice
| which is to separate decisions from execution, which is
| compatible with but I find to be subtler than the
| functional core pattern.
|
| Often we mix glue code and IO code with our business
| logic, and that makes for tough testing situations.
| Especially in languages that allow parallel tests. If you
| fetch data in one function and act upon it in another,
| you have an easy imperative code structure that provides
| most of the benefits of Dependency Injection. Your stack
| traces are also half as deep, and aren't crowded with
| objects calling themselves four times in a row before
| delegating. if
| (this.shouldDoTheThing()) { this.doTheThing();
| }
|
| Importantly with this, structure, growth in complexity of
| the yes/no decision doesn't increase the complexity of
| the action code tests, and growth in glue code (auth
| headers, talking to multiple backends, etc) doesn't
| increase the complexity of the logic tests.
|
| A big part of scaling an application is finding ways to
| make complexity additive or logarithmic, rather than
| multiplicative. But people miss this because they start
| off with four tests checking it the wrong way, and it
| takes four tests to do it the right way. But then later
| it's 6 vs 8, and then 8 vs 16, and then it's straight to
| the moon after that.
| PaulHoule wrote:
| We are in the distributed systems age. If systems are
| composable, operations can fail for reasons that are
| completely unfathomable to the client. It's not reasonable
| to have a SharkBitTheOpticFiberCableException and 100,000
| other ones that handle every reason why an operation
| failed.
|
| What the client should know is how an error affects what it
| is doing, it wants answers to questions like
| * Is it likely this error will recur if I retry
| immediately? in 1 minute? in 1 day? * What is the
| scope of this error? Does it affect the entire system?
| Does it affect a particular database record? * What
| do I tell the user? * What do I tell the system
| administrator?
|
| Actual improvement in this area won't come from information
| hiding but it could come out of attaching some kind of
| ontology to exceptions where exceptions are tagged with
| information of the above sort, that it is not about having
| names for them and a hierarchy, but in about having rather
| arbitrary attributes that help the exception management
| framework (somewhere high in the call stack!) do the best
| it can in a bad situation.
| tgbugs wrote:
| I had a similar thought a while back [0]. Developing a
| sane ontology of error types and their implications is a
| hard problem, but I think it could be done. The subset of
| errors that is the most frustrating and hard to deal with
| are ones where, as you point out, the client will have no
| way to estimate how long a failure mode might persist, at
| which point you resort to exponential backoff (actually
| probably an s-curve).
|
| The issue is that sometimes the solution to the issue
| would require the client to get up and get out a shovel,
| and go dig somewhere or something. When the abstractions
| break down that hard there isn't really a way for the
| developer of the code to handle that unless they somehow
| stuff a full blown AGI into their program, and even then
| it would be a stretch.
|
| 0. https://github.com/tgbugs/idlib/blob/master/docs/ident
| ifiers...
| adamc wrote:
| While I think this is a good point, a lot of the answers
| cannot be determined by the generator of the exception.
| Your SQL library cannot know what the implications of an
| error are -- is this a minor part of the system for which
| the error can be logged but mostly ignored, or is it
| critical? Etc.
|
| People want error handling to vanish so that they can
| follow the "normal" flow, but in fact error handling is
| one of the critical things code does.
| pythonaut_16 wrote:
| This is sort of what HTTP codes get at though.
|
| The server doesn't know what you want to do with a 400
| but it knows that the problem is with the request for
| example.
| [deleted]
| PaulHoule wrote:
| Actually there is somewhat standardized set of SQL error
| codes and they can be put into a hierarchy like the HTTP
| codes.
|
| For instance, you can have a SQL error because the syntax
| of your SQL is wrong. If you're not doing "dynamic SQL"
| you know this is a programming error (it doesn't matter
| what input was supplied to the functions.) One common
| error is "attempted to insert a row with a duplicate
| key", frequently you want to catch that SQLException and
| rethrow all the rest.
|
| The ideal SQL library for Java would expose the hierarchy
| implicit in SQL errors as a class hierarchy.
| eternalban wrote:
| > Note that people now consider that as a mistake
|
| Correction: Some people. Java's checked and unchecked
| exception approach is quite nice if used judiciously. It
| certainly beats checking for error after every function
| call (default: mostly people ignore error codes) and you
| even get typed errors so you can trivially incorporate
| exception handling in the conceptual design as a first
| class design element.
|
| I am frankly not sure how people get confused about
| "control flow" and exceptions. (In decades of Java
| programming the only thing that can still cause minor
| reading/writing nuisance are generic types and type erasure
| in over elaborate generic code.)
| PaulHoule wrote:
| The greatest secret of exceptions is that in most cases
| you don't need to catch them. What should really be on
| your fingertips is try { ...
| something ... } finally { ... clean up
| ... }
|
| this (plus try-with-resources) is the genius of
| exceptions. The tragedy of exceptions in Java is that
| checked exceptions convert the above to
| try { ... something ... }
| catch(ACheckedExceptionThatHasNothingToDoWithThisCode x)
| { throw new
| SomeOtherCheckedExceptionToPleaseTheCompiler(x) }
| finally { ... do what has to be done ...
| }
|
| with the variations of throw new
| AnUncheckedExceptionSoIDontVandalizeMyCodeMore(x)
|
| and catch(...) { // i forgot
| to rethrow the exception but at least the compiler isn't
| complaining }
|
| as well as // i forgot to add a finally
| cause because I was writing meaningless catch clauses
|
| As much as I think checked exceptions are a mistake in
| Java, it is not hard to make up your mind about rethrows
| and apply them in a checked or unchecked form with little
| or no thought.
|
| The unhappy path that you get for free with exceptions is
| correct for code with ordinary control flow. Most of the
| code has no global view of the application and is no
| position to handle errors. On the other hand, for many
| simple programs, the correct behavior is "abort the
| program, clean up resources, display an error message"
| which a sane exception system gives you _for free_
| (except for the finally which cleans up the happy path
| too)
|
| For a complex control flow there is something high up in
| the call stack that has global responsibility. Imagine a
| webcrawler which is coordinating multiple threads that
| call fetchUrl(url) fetchUrl doesn't need to catch
| exceptions at all, just clean up with finally. What it
| may need to do is tag exceptions with contextual
| information that will help the coordinator make
| decisions. That webcrawler in particular will deal with
| intermittent failures all the time and only the
| coordinator is in a position to decide if it wants to
| retry and on one schedule.
| newZWhoDis wrote:
| > Note that people now consider that as a mistake, people
| prefer having Exceptions be hidden instead of explicit and
| requiring handling like that.
|
| What people? Please tell me where they're at so I can tell
| them they are wrong (lol)
|
| But seriously, I could not disagree more.
| lenkite wrote:
| The designers of the Java functional and stream library
| for one. None of the functional contracts have throws. So
| you are forced to have un-checked exceptions for
| everything, unless you want a truly mind-boggling amount
| of try-catch everywhere which will rapidly exceed your
| normal code by factor of 2x-3x.
| mike_hearn wrote:
| In Java, yes. Note that the JVM doesn't enforce checked
| exceptions. It's a language level thing. So in Kotlin for
| example, where all exceptions are unchecked, you can use
| the streams library without needing try/catch.
| PaulHoule wrote:
| ... or you can just use a sane FP library like
|
| https://github.com/paulhoule/pidove
|
| Some people don't like the Lispy signatures so I did
| start coding up a version with with a fluent interface
| but didn't quite finish.
|
| Overall I would say the implementation of lambdas and
| method references in Java 8 was genius, but the stream
| library was a big mistake. Part of it is that has this
| cumbersome API that in principle would let it optimize
| query execution by looking at the pipeline as a whole but
| doesn't really take advantage of it.
| taeric wrote:
| I get where you are coming from, but imagine if every other
| "to the human" process description we had was done this way.
|
| I actually think this would be a fun one. How to make
| scrambled eggs, but where all failure cases are covered.
| Would be the "Hal fixes a lightbulb" in prose.
| sowbug wrote:
| That gets to the original promise of computers, doesn't it?
| That they'd perform repetitive tasks quickly and reliably.
|
| Meanwhile, every time I make scrambled eggs, there is a
| small but very real chance that my house burns down. And we
| accept this because _to err is human_.
| taeric wrote:
| Sorta? But a lot can be packed away in "other
| directions." Most recipes, for example, assume that
| setup/teardown is intrinsic to the kitchen. As such, to
| know the procedures to do those things, you would look
| somewhere else.
|
| That is, you aren't accepting a risk that things will go
| wrong. You have moved what to do about many exceptions to
| somewhere else.
| PaulHoule wrote:
| Exceptions always work the same way. You learn how to read
| code with exceptions pretty quickly.
| frodowtf wrote:
| How does an explicit raise operator like '?' work any
| different than that? You can learn how to read it pretty
| quickly.
| wvenable wrote:
| Assume all functions can throw and there is no extra work
| reading. A function that has no possibility of error is so
| uninteresting in the context of error handling.
|
| Furthermore, handling errors has little to do with where the
| error is actually caused. In general, you can only do two
| things with errors: log and kill the operation or retry the
| operation. Neither of these has anything to do with the leaf
| function 20 items down in the stack that actually made the
| network call that failed.
| ModernMech wrote:
| > A function that has no possibility of error is so
| uninteresting that focusing on that is the wrong thing.
|
| I disagree, a function that has no possibility of an error
| is a proper function, and what we need for performance
| optimized code.
|
| Proper functions by definition are just mappings from a
| domain to a range. That mapping really shouldn't be
| predicated on any other state, so it should never fail if
| the inputs are valid within the domain.
|
| We _need_ to focus on such functions if we want
| performance, because we can only achieve too speeds by not
| worrying about checking the function result for
| correctness. Given a proper function, we should just be
| able to compute the result and move on to the next
| function.
|
| Therefore it's of great benefit to us (as authors of
| performant code) to separate our fallible functions from
| our infallible ones. Keep the fallible ones iutside of hot
| loops, only infallible ones inside, and that's a recipe for
| mechanical sympathy of the sort that results in great
| performance.
| nemothekid wrote:
| If I am in the business of writing robust code; then
| "assuming all functions can throw" means at the very least
| forcing every function call to be surrounded by a try/catch
| block? It almost always make sense to handle an error
| locally if you can; for example if I want to retry the
| operation (let's say I'm writing a distributed database
| client), it may make sense for me to retry another node
| rather than unwinding to the application level that has now
| lost all context.
|
| > _A function that has no possibility of error is so
| uninteresting that focusing on that is the wrong thing._
|
| I spend a lot of time debugging errors in code that has 0%
| chance of failing. It tends to involve a lot of matrix
| math. This isn't something you can say is universally true
| especially given all the hype around AI now.
| quietbritishjim wrote:
| > It almost always make sense to handle an error locally
| if you can
|
| This is highly presumptuous. I have written many programs
| that did not need to handle errors locally, and so
| exception handlers were only at the very top level (or,
| actually, _just below_ the top-level usually - but the
| point is that there were generally few and I had
| flexibility to decide where to put them). Perhaps you and
| I write very different applications. But the fact remains
| that the "almost always" in your statement doesn't hold.
|
| Alternatively line of reasoning: if this was always true
| then there would be little point to Rust's ? as it would
| be so rarely used.
| azov wrote:
| _> It almost always make sense to handle an error locally
| if you can_
|
| Yes, but "if you can" does a lot of heavy lifting here.
| In most cases you can't, and this is when Rust's ? is
| used.
| wvenable wrote:
| > If I am in the business of writing robust code; then
| "assuming all functions can throw" means at the very
| least forcing every function call to be surrounded by a
| try/catch block?
|
| No, absolutely not! You only care about errors where you
| can retry/ignore or log and terminate so you only have
| try/catch in those areas. So maybe one or two.
| sanderjd wrote:
| What you're describing here are unchecked exceptions, which
| Rust has in the form of panic. There are other kinds of
| errors that can be handled closer to the point where they
| occur.
| jeroenhd wrote:
| "Assume all things can throw" is what I've seen people do
| in Java code that adds a million try catch wrappers around
| everything just in case something may go wrong at some
| point.
|
| The end result is either completely unreadable or
| impossible to figure out. "How do I return fallback data
| for FooBarService.wiggle()" often ends up in digging
| through (incomplete, outdated) documentation or with code
| that breaks unexpectedly, sometimes even in production.
|
| Note that Rust has the same issue, any method can panic and
| allocation may just fail at some point. There are very few
| ways good ways to handle those problems correctly, which is
| why this "everything may kill your program" approach is
| often criticised.
| yetihehe wrote:
| > There are very few ways good ways to handle those
| problems correctly, which is why this "everything may
| kill your program" approach is often criticised.
|
| In Erlang, "everything may kill your program" is typical
| method of operation, and there should always be some kind
| of path to reset your state from known good values.
| wvenable wrote:
| Don't get me started on Java and checked exceptions. If
| you don't have checked exceptions, you should not have a
| million try/catch blocks. In fact, just the opposite.
| Since you only care about errors when you can retry (or
| ignore) you should only have a small number of try/catch
| blocks. Ideally one or none.
|
| My best example of this is a UI application that I built
| that had a single try/catch block around the event loop.
| It just displayed the error message to the user and
| returned to the event loop. If they tried to save a file
| to a network and failed, they got the message, and could
| just hit save again for somewhere else. No other code
| needed.
| erik_seaberg wrote:
| We have to be deliberate about where we retry, and how
| quickly. It's all too easy for layers to create a death ray
| of n factorial requests.
| einpoklum wrote:
| You may prefer that, but everyone else who has to read your
| code - doesn't.
|
| Yours is an approach which is likely to ensure your code is
| discarded and has to be rewritten relatively quickly.
| jbellis wrote:
| Error handling in Rust is actually a lot worse than you think.
| In fact it may be the single worst aspect of the language.
|
| Fundamentally it is difficult to impossible to fix bugs without
| knowing what code caused it. Java-style exceptions give you a
| backtrace for free, which is a huge head start. With Rust you
| have to do a lot of manual plumbing with something like
| error_stack to get similar functionality, out-of-the-box Errs
| do NOT capture this.
|
| Far more productive to work in an environment that does the
| right thing "for free" vs having to do it manually.
| dalyons wrote:
| Ugh that's one of the worst parts of go too. Stackless errors
| are so useless and hard to debug.
| [deleted]
| mamcx wrote:
| > Perf is easy when you have AWS credits. One reason that you
| might pick Rust is for overall performance.
|
| Interesting: Rust save money but that mean effort!
| marcosdumay wrote:
| Even on the cloud, Rust will only save you money if you have
| enough users. But the effort is upfront.
|
| Unfortunately, the cloud isn't a very good environment for
| mixed-languages deployments (unless you stick to the most basic
| services), so you have to make a decision on the very beginning
| and stay with it.
| zeroxfe wrote:
| If you're thinking about building something in Rust, a good
| question to ask is, "what would I use if Rust didn't exist?"
|
| If your answer is something like Go or Node.js, then Rust is
| probably not the right choice.
|
| If your answer is C or C++ or something similar, then Rust is
| very likely the right choice.
|
| Obv, there are always exceptions here, but this helps you work
| through things a bit more objectively. Rust can be a fantastic
| language for many purposes, but it has a very high development
| cost.
| richardwhiuk wrote:
| Not sure I agree with Go vs Rust.
|
| I think if you would choose Java or Python or C#, then Rust
| might not be the right choice.
| throw14082020 wrote:
| Go is in a sweet spot where it is often used to compete with
| both groups: [Rust, C/C++] and [Node, Python, Ruby, etc]. The
| reason GP said it is probably because of Garbage collection.
|
| I've done a bit of Rust in my job, and there are some basic
| things that Rust doesn't have going for it:
|
| - steep learning curve (this means for the first 6 months,
| you or your colleagues are unproductive, write bad Rust which
| your company then builds upon over time).
|
| - bad error messages (even though that was a focus for the
| rust team!)
|
| - frustratingly complex for setting up test coverage
|
| - Slow analyzer speed (*super laggy* on Clion, though this
| might be a jetbrains issue)
|
| - Slow compilation times (I heard somewhere that "Go just
| goes". I've also written some Go in my free time, and
| compilation is fast. Well IMHO, "rust will rust" - it's very
| slow. Generics can make compilation event slower.)
|
| - Verbose. I've seen a just few lines of JS get replaced with
| hundreds and thousands of Rust.
| alfalfasprout wrote:
| Unfortunately, I'm inclined to agree.
|
| Rust lives in this interesting spot where, on paper, it
| should be superior to anything... but in practice, it's not
| a good choice in most cases.
|
| It's very easy to ramp up someone in Go that's had a
| standard CS education and written C/C++ before. It's also
| simple enough syntax-wise for someone who knows python well
| enough to understand references, etc. Its stylistic
| restrictions and not being OOP-first also mean that
| codebases are generally readable. Compilation is also
| extremely straight forward.
|
| With Rust, I've found even very experienced C++ folks have
| a long ramp-up period, the development toolchain is slow,
| and the ecosystem is limited.
|
| Sure, for example there are projects to enable Rust usage
| with CUDA. But few are inclined to actually bother
| implementing a new BLAS and GPU accelerated tensor library
| with Rust.
|
| I do think 10 years from now Rust will start getting more
| adoption as the ecosystem and tooling improve.
|
| But it's hard to argue with Go where you'll typically get
| results that are faster or at worst comparable to Java
| without the OOP design pattern gobbledygook, simple
| concurrency model, and simple build process. It's "good
| enough" for 99% of use cases.
| ModernMech wrote:
| > With Rust, I've found even very experienced C++ folks
| have a long ramp-up period
|
| I've found C++ folks _especially_ have the hardest time
| with Rust, because they approach it using C++ idioms and
| habits, then get frustrated when they can 't do things
| the way they're used to.
|
| I've had better success teaching Java people Rust. They
| find it much easier to learn than C++, and I can get them
| writing idiomatic Rust code quickly, while C++ devs are
| still trying to get their coding habits past the borrow
| checker.
| worik wrote:
| I think everybody has a hard time starting with Rust.
|
| Even when you get confident it is still a longer process
| writing code than C/C++. It makes you think very hard
| about what you do carelessly in C.
|
| But having spent the last few years debugging a lot of
| Swift code, and a bit of Rust code, that time is worth it
| I say.
|
| Where Rust shines is in the debug cycle. Less of it.
|
| Once you learn to surrender to the compiler, you will
| find true bliss,....
| zozbot234 wrote:
| Go has bad interop with C/C++ and languages that use the
| C/C++ ABI (including Rust). You can use cgo as a
| workaround but it's clunky. So that makes an interesting
| case for other high level, novice-friendly languages like
| Nim, Crystal or Val/Vale/Vala.
| estebank wrote:
| > - bad error messages (even though that was a focus for
| the rust team!)
|
| I would love to hear more! (If you have the time.)
| pdimitar wrote:
| Not the fault of Rust compiler per se but in my case the
| errors that mismatching trait impls from async libraries
| yield can be downright suicide-inducing.
|
| I recognize this is not entirely on rustc though.
| steveklabnik wrote:
| esteban of course gave you an excellent response already,
| but just another bit of like, context here: while it may
| not be on rustc, the developers want to go beyond the
| norm here. rustc understands if you write async/await
| syntax like JavaScript, and then directly proposes that
| you switch to the Rust syntax: pub
| async fn foo() -> i32 { unimplemented();
| } pub async fn bar() { let f
| = await foo(); }
|
| gives error: incorrect use of `await`
| --> src/lib.rs:6:13 | 6 | let f =
| await foo(); | ^^^^^^^^^ help:
| `await` is a postfix operation: `foo().await`
|
| It isn't on rustc to understand this either, but it helps
| a bunch of people, so the team does it anyway.
| pdimitar wrote:
| Check sibling reply. Sadly I never wrote those down. :(
|
| I'll definitely do so going forward.
|
| The problem is with that is the impostor syndrome: I
| legitimately can't tell if I am an idiot and skipped some
| basic Rust training, or the error messages are truly
| confusing and unproductive.
|
| But your messages help. I'll just write those down and
| send them to GitHub's issue list.
| steveklabnik wrote:
| I'm not working on Rust anymore, but the previous stated
| position on this, which as far as I know is still the
| case, is that if it's confusing, you should file. Worst
| case scenario is "sort we can't fix that" but it's not an
| imposition to file issues. More is better. Because
| exactly as Esteban said, information is valuable. Even
| duplicates are valuable: they indicate that more than one
| person has run into this, and therefore it's more
| valuable than an obscure issue only one person sees.
| estebank wrote:
| Having examples of these is useful to see what we _could_
| get rustc to do. The general case might be impossible to
| deal with in a generic way, but we can target specific
| patterns libraries use and emit custom errors for them.
| The problem with these is we have to be reactive: if we
| don 't see a problematic patter ourselves (or it isn't
| reported to us), we can't do anything about them.
| pdimitar wrote:
| Unfortunately last I tried these code snippets was months
| ago, was rushing like mad because it was a startup and I
| couldn't afford to just stop and write everything down
| and... yeah, priceless info was lost.
|
| Just recently I am making a comeback to rewriting a tokio
| 0.1 library to the latest version so I'll likely have a
| few examples that I can post... where? In GitHub issues?
| estebank wrote:
| GitHub works great for it, for diagnostic tickets in
| particular you can file them at https://github.com/rust-
| lang/rust/issues/new?assignees=&labe...
|
| Even if it is an "it hurts when I do this" without more
| context it can be useful to bring the problem to our
| attention (but the more context you provide the higher
| the change we'll fix the problem).
| dcow wrote:
| > - Verbose. I've seen a just few lines of JS get replaced
| with hundreds and thousands of Rust.
|
| Please, more detail (=
| afavour wrote:
| JS: new HTMLDivElement()
|
| Rust: struct WebBrowser { ...
| steveklabnik wrote:
| Instantiating an object vs defining one? Yeah definition
| would be longer.
| throw14082020 wrote:
| I should've been clearer, sorry.
|
| The verbosity and complexity of
| `wasm_bindgen`/serialization between JS and Wasm (written
| in Rust) is primarily the thing I am frustrated at here
| when I see hundreds and thousands of Rust code. A
| concrete example: creating a Websocket client in
| Javascript/Typescript vs in Rust/Wasm.
|
| In general though (outside of Wasm), Rust is less
| readable.
|
| And with regards to Rust errors, I've found Rust errors
| related to Tonic and Diesel to be quite
| annoying/unreadable. The Diesel docs seem to blame Rust
| for this (can't find the docs for it right now).
| justinclift wrote:
| Isn't this due to wasm having to access browser things
| mostly _through_ browser JS interfaces?
|
| eg Browsers provide JS functions that are intended for
| JS, which are not directly exposed to Wasm. So when your
| Wasm wants to access DOM things, access DOM functions,
| (etc) it needs to go through a JS shim layer instead of
| being able to call them directly.
|
| If the browser dev's (or some W3C type of body?)
| introduced those same functions, but had them be directly
| accessible from wasm, then the JS shims wouldn't be
| needed.
|
| The JS dev's for each of the browsers though would
| probably try and stop it ("security risk!" excuses, etc)
| though, as that would potentially cut into "their
| territory" and allow other languages to compete. :(
| justinpombrio wrote:
| > - Verbose. I've seen a just few lines of JS get replaced
| with hundreds and thousands of Rust.
|
| I'm curious to see those few lines of JS!
| pleb_nz wrote:
| I wouldn't group python with java and c# either. Quite
| different beasts
| ntonozzi wrote:
| Go belongs in the exact same bucket as Java and C#.
| FpUser wrote:
| Performance wise yes. As for language features - not
| really. Code in Go would likely have way more LOC
| tptacek wrote:
| Ergonomically, yes. Logistically, no.
| mike_hearn wrote:
| For server binaries they're typically being dropped into
| Docker containers not scp-d to servers directly, and the
| moment you go there you can just use jib and get a JVM
| container easily so there's no difference in logistics.
|
| For CLI tools whilst a single binary can be convenient,
| native-image lets you get those for JVM programs too
| these days. But it's not always the case that it's
| enough. In practice you will often hit the need for:
|
| a. Cross platform / cross builds.
|
| b. A way to easily update them for your users (that isn't
| "everyone mount this NFS/SMB drive")
|
| c. Ability to ship other files e.g. third party libraries
| written in other languages, config files, data files,
| readmes ...
|
| d. Possibly, avoiding virus scanners and Gatekeeper if
| you have users on Windows/macOS.
|
| Conveyor [1] does support distributing CLI tools (in any
| language) that can then be updated via apt-get, the
| Windows package manager or Sparkle on macOS. If your
| language/runtime supports cross-building then it can do
| it all from your developer laptop, you don't need each OS
| to build for. The resulting artifacts are single files
| (deb, msix/exe, zip) and it supports both self-signing
| and regular signing if you want that.
|
| It provides a few other neat features on Windows:
|
| * One click install that immediately adds new tools to
| every single terminal session without needing restarts.
|
| * If you want, silent background updates Chrome-style. If
| you don't, manually triggered updates.
|
| * For JVM apps specifically it automatically configures
| the Windows terminal to support ANSI escapes, Unicode and
| other modern features so you can use all the same stuff
| as on UNIX without needing to futz around with win32 or
| wrappers.
|
| Unfortunately the little default GUI that lets you
| trigger updates and add CLI tools to your path on macOS
| isn't officially launched yet, because it only works for
| JVM apps and not other types of program. But if anyone
| wants to try it just let me know, it's easy to activate.
|
| If you don't need any such features then yes, a single
| binary can be a bit more convenient than a zip. But the
| number of situations where it breaks down is pretty high
| and it's not so hard to handle multiple files.
|
| [1] https://hydraulic.software/
| tptacek wrote:
| I want to be careful not to recapitulate every
| conversation I've ever had with a JVM person about this.
| I'm not claiming it's impossible to deploy JVM
| applications; obviously, tons of people do. I'm just
| saying people use Go and Rust because they work well in
| situations where you want to distribute and directly run
| a simple binary without additional tooling. That's not
| every situation; obviously, if you can use Docker,
| there's not much difference between a JVM app and any
| other kind.
|
| Your comment is super interesting, don't let me sound
| like I'm trying to shoot it down. I'm being deliberately
| terse to avoid creating receptors for language war
| antigens to bind to.
| mike_hearn wrote:
| Sure. Given the choice of one file or 50, one file is
| clearly better all other things being equal.
|
| My feelings on this changed over time. About 10-15 years
| ago I thought single executable output was a critical
| feature for a language, because everywhere I went I saw
| people saying how important it was for them, how much
| simpler it made deployment. I figured, OK, people know
| what they want so that's what they should get.
|
| Then Docker came along. Docker images aren't single
| files, they're the polar opposite. They aren't even
| things you directly manipulate using the filesystem at
| all. Yet people loved it and it took over the world.
| Clearly what all those people demanding single-file
| executables were actually wanting in 95% of cases was
| simpler deployment, and they were phrasing it as single
| executable because that was concrete and understandable
| whereas simpler deployment is a very vague concept so who
| knows what you'd get if you asked for it.
|
| For people who are selecting Go or Rust or Graal native
| images primarily because of single-file output, I'd
| actually really appreciate a chance to ask a few
| questions or interview them quickly to learn more about
| the deployment context. Conveyor is all about deployment
| and it's good to understand more about how people are
| doing things and what could be better.
| ntonozzi wrote:
| Why do you say logistically no? The challenges of
| distributing the runtime?
| kcartlidge wrote:
| There's no runtime to distribute with modern C#.
| schemescape wrote:
| Are you referring to the "compile to a big executable"
| feature?
|
| I'd love to use C# without having to deal with
| distributing the runtime, so I'd like to hear more!
| kcartlidge wrote:
| > _I'd love to use C# without having to deal with
| distributing the runtime, so I'd like to hear more!_
|
| In the later versions of DotNet there are a couple of
| common ways to distribute (I'd suggest either DotNet 6
| [LTS] or preferably DotNet 7 [current]).
|
| You'd usually use the _dotnet publish_ command, which
| ideally produces one of three things, all of which are
| self-contained and can be deployed to a clean server
| without any framework. Ordered by worst-first (in
| relation to your requirement):
|
| 1. The halfway house from _dotnet publish_ is a folder
| with your app /site/api alongside all the dlls needed
| from the standard library and/or nuget. This is a
| standalone folder, though messy.
|
| 2. With an extra couple of options on the _dotnet
| publish_ command you get it all as a single binary which
| is exactly what you say: a big executable.
|
| 3. There is another option available on the _dotnet
| publish_ command which will use magic (probably tree-
| shaking but I can 't remember) to produce a smaller
| single binary by removing unused code.
|
| As an aside, it's also worth noting a couple of extra
| points:
|
| * The _dotnet publish_ command can cross-compile ready-
| to-deploy outputs for any supported platform (eg Mac or
| Linux, using x86, AMD64, or ARM64) just by specifying the
| combination of platform and CPU as command line options.
|
| * Within C# you can mark your assets as embedded
| resources (like an embed FS in Go) and they will also be
| included in your output.
|
| The final result varies in size depending upon what your
| code does (and hence included libraries), and some code
| (eg reflection) _may_ interfere with the tree-shaking (or
| whatever) of option 3 - but it warns you whilst it
| generates the output, and you can either ignore it or use
| option 2.
|
| Generally speaking the option 3 builds are between 1.5
| and 2 times the size of a Go one, but you're looking
| about 20MB to 30MB for useful stuff. Not tiny, but still
| quite small these days. Option 2 builds probably double.
|
| In use (and this is subjective) they consume a bit more
| memory than Go, but seem more consistent/stable in that
| usage.
|
| Also note that within that 20MB-30MB build, for an api or
| a website you get a built-in web server that can sit
| behind nginx etc as usual, but is also good enough to
| expose directly.
| schemescape wrote:
| Yes, "dotnet publish" is what I was thinking of. Wow, I
| didn't realize it could cross-compile!
|
| I can't quite tell from the .NET SDK repository -- any
| idea if this stuff works on Linux (i.e. building on
| Linux, perhaps for Windows)? I see mention of MSBuild, so
| I'm guessing maybe not.
|
| I love C#, but I abandoned it a while ago because I
| wanted to only rely on open source tools (just to ensure
| my code is usable in the future). Then, of course, they
| open-sourced a bunch of stuff (including the compiler).
| If I at least had the option to develop C# on Linux (with
| support for cross-compiling to Windows), that would be
| great (and honestly something I would have never expected
| 10 years ago).
| tptacek wrote:
| Yes. It's a reason people pick Go and Rust for things.
| galangalalgol wrote:
| C# sure, but unless you are doing something pretty close to
| the core purpose of some giant java framework java is slow
| and verbose
| tasubotadas wrote:
| Slow and verbose compared to what?
| ntonozzi wrote:
| Java, Go and C# (and node) have very similar performance,
| e.g. https://benchmarksgame-
| team.pages.debian.net/benchmarksgame/.... For all of
| them, the key to writing high performance code is
| avoiding allocations and boxing. Go and C# both do this
| slightly better than Java, but in most domains where
| these languages are used, this is not a big difference
| (and this is where you might use C/C++/Rust instead).
| I've found Go to be more verbose than Java, but I haven't
| used Go much since generics were released.
| maleldil wrote:
| It's amazing how the "Java is slow" myth survives to this
| day.
| johnny22 wrote:
| i just read "java is slow" as "java is slow to startup"
| and that helps.
|
| Java is slow(er) to to startup, but once it's going, it's
| pretty good.
| maleldil wrote:
| That doesn't matter if you're writing a REST api. If
| you're writing a CLI app, then I agree that's a problem.
| dboreham wrote:
| Sometimes matters, e.g. when you deploy new code.
| oauea wrote:
| Not really, just do a rolling deployment like you should
| be doing anyway. No one cares if the new version takes 1
| millisecond to start up or 3 seconds because they
| literally won't notice.
| dboreham wrote:
| Rolling deployment is a hack imho. Adds complexity and
| hence yet more potential failure modes.
| oauea wrote:
| Hardly, it's a fantastic guardrail when combined with
| health checks. You can say "you don't need it", but
| everyone makes mistakes sometimes. Make those mistakes
| not matter. You also take backups, right? Same idea.
| imtringued wrote:
| But 3 seconds isn't on the table. It is more like 20-30
| seconds on a medium sized app and 8 seconds for a small
| one.
| bzzzt wrote:
| If your Java app takes half a minute to initialise it's
| the app's problem, not Java. Modern Java frameworks have
| moved from a dynamic deployment model to statically
| compiled and can start in milliseconds. (for example, see
| the benchmarks on https://quarkus.io/blog/runtime-
| performance/)
| dividedbyzero wrote:
| How would real-world JVM startup times matter in
| deployments?
| smolder wrote:
| JVM startup times make using it in Lambda or scaling
| container clusters awkward. Scaling can't happen fast
| enough for traffic spikes when the startup time and cold
| start performance is crap.
| dboreham wrote:
| You exec a process expecting it to begin operating,
| providing some networked service, in a reasonable time.
| Instead it doesn't do that. It spends tens of seconds,
| sometimes minutes, running JIT and other sundry startup
| overhead.
|
| You may not have seen this if you haven't used Scala...
| thefaux wrote:
| Yeah, Scala is absurdly bad for startup time because of
| poor modularization of the standard library. It's a
| decent language with a terrible standard library.
| dividedbyzero wrote:
| Genuinely curious, what kind of application are you
| running? Which JVM are you using? Are you aggressively GC
| tuning? Very low on memory? I've used Scala from 2.8 up
| to 3.0, for microservice systems, monoliths, data
| pipelines, machine learning (way back), desktop apps for
| research using Swing, an Android app (worst idea ever),
| highly imperative to very functional, and I don't think
| I've ever seen anything remotely as bad as that even on
| genuinely big codebases. Hundreds of ms, sure, but
| minutes just getting the JVM up and running? I can see
| how that would be problematic.
| imtringued wrote:
| You reboot and suddenly your CPU is at 100% for 20
| minutes starting every web service...
| pgwhalen wrote:
| If your CPU is at 100% for 20 minutes starting every web
| service, that is definitely your problem, not Java's
| problem.
| galangalalgol wrote:
| I meant slow to develop in.
| marcosdumay wrote:
| Whatever the absolute merits (or lack of them) of Go, the
| fact is that if it's a good (enough) option for you, then
| it's almost certain that some language will fit your problem
| better than Rust.
| Night_Thastus wrote:
| I think it's dismissive and overly simplistic to say that Rust
| is almost always a better option than C or C++. They're
| different languages with different strengths.
|
| One strength of C++ is that it is _far_ more established than
| rust - and that comes with a lot of advantages:
|
| * It has a larger number of people who know how to work with it
|
| * It has a huge catalog of established, fully functional
| libraries for everything you could imagine from UI to game
| development to embedded systems to simulation to anything else
|
| * It has broad support in developer toolsets in general like
| editors and IDEs, static analysis tools, formatters, pre-commit
| hooks, etc
|
| If I'm starting a new project with C++, I can immediately know
| that there's a huge landscape of programming already carved up
| and ready to work with. I can't do that as easily in Rust. The
| language, the libraries, the tools are all younger. Some of it
| isn't as fully featured, some of it isn't nearly as stable.
|
| That will improve with time, but it's a huge advantage to C++
| right now.
| Animats wrote:
| > One strength of C++ is that it is far more established than
| Rust - and that comes with a lot of advantages:
|
| I'm painfully aware of this. Typical Rust problem, from a
| reply I made to a posting on Reddit:
|
| * WebGPU dev: WGPU updated to 0.15!
|
| * Me: Might want to hold off on upgrading for a bit. See (bug
| report on related package)
|
| * WebGPU dev: Good to know. I'll keep this in mind if someone
| has any issues when following my tutorial
|
| * Me: I'm using Egui/rend3/wgpu/winit/vulkan cross platform
| on Linux and Windows, with cross-compiling. Getting all those
| crates to play well together is not easy. Every time
| something in that stack changes, it's days or weeks of
| trouble.
| KMag wrote:
| That's not the argument the GP is making. The GP is basically
| saying that if C/C++ aren't your second choice of language,
| then it's a sign your reasons for picking Rust are suspect.
|
| They didn't say Rust is almost always better than C/C++.
|
| There's perhaps the implication there, but it's certainly not
| explicit in the GP's comments.
| aisrael wrote:
| This is really great way of putting it. Node/Python/Go were the
| obvious alternatives for us.
| autophagian wrote:
| I feel like this is probably on the money, at least when it
| comes to building a startup. I often use Rust where before I
| would use Go/NodeJS/Python, but mostly because I like the type
| system and velocity on side-projects isn't as important.
| wyager wrote:
| Precisely. If you like what you see in Rust but you don't need
| to worry about extremely strict hardware/memory/realtime
| constraints (i.e. you could use a memory-managed language),
| consider Haskell instead.
| galangalalgol wrote:
| Rust is a high development cost compared to node.js python or
| julia, but I'd say it is about the same as go or c#. Maybe a
| little better than all of those if you consider time getting
| test coverage. But if you are prototyping you probably aren't
| doing that. I'd say rust is a much lower development cost than
| c++ or java.
| adastra22 wrote:
| Golang absolutely has a faster development cycle than Rust.
| Unless you're a Rust expert who never touches Go, but then
| it's an issue of familiarity. Go devs hit the ground running
| and the ergonomics are streamlined, and the borrow checker
| and other rust restrictions don't get in the way.
| galangalalgol wrote:
| Given my downvotes you seem to be with the consensus on
| this one. I had 30 years of c++ development going into rust
| and I never found myself fighting the borrow checker.
| Golang seemed the same, just started coding and stuff
| worked mostly. But, the complexity of rust was familar
| coming from c++ with generics and macros but without some
| of the footguns, so it just seemed like power, not clutter.
|
| I like go, but I wouldn't prototype in it, I'd pick julia
| or python. And if I'm familiar with the problem and want to
| code for production, rust really doesn't seem any slower to
| develop in than go to me and perhaps a bit less verbose.
| But in retrospect I think that is because of the direction
| I came at rust from means my habitual coding style lined up
| more closely with what rust expects. Its not a harder
| coding mindset, just a different one than someone who came
| from java would be used to.
| adastra22 wrote:
| 30 years of C++ can inoculate you to the idea of hideous
| amounts of boilerplate, or worrying about memory
| allocation timelines and such. I'm a 25 year C++ veteran
| myself.
|
| I recently wrote an asynchronous microservice in C++,
| because it needed to use a C++ library I'd already
| written. Took about two weeks of effort, and clocked in
| at 1500 loc, not counting tests or the half-dozen
| external dependencies. I rewrote it in 100 lines of
| idiomatic Go using nothing except the standard library a
| few days ago. That's a 10x reduction in both lines of
| code and development time, although it's a bit unfair
| because I had already done the C++ version first. That is
| after giving up on a Rust version that was already
| weighing in at ~1000 LOC in an unfinished state.
|
| After this experience, I don't think I'd ever use C++ or
| Rust again for a concurrent web service, unless there was
| hard real-time latency requirements. Golang is just so
| much better streamlined for that application, and the
| standard library is batteries included.
| galangalalgol wrote:
| Go was designed from the ground up for that sort of
| thing, so that makes sense. And anecdotally asymc/await
| is a pain in rust. I've only used rust async through
| other libraries, and not that very often. I usually use
| plain threads.
| lenkite wrote:
| 30 years of C++ development experience means you aren't
| going to find any PL difficult and therefore your views
| on easy/difficult a PL is to learn and get going cannot
| be taken seriously. :)
| galangalalgol wrote:
| While my overinflated ego enjoys your assessment, I want
| to reiterate that the patterns that minimize friction
| with the borrow checker aren't harder than standard
| patterns you'd see in garbage collected OOP or Functional
| focused languages, just different. Anecdotally here on HN
| it seems like people who came from ocaml or f# find rust
| even easier to adapt to than c++ people.
| JamesSwift wrote:
| That really is a great way to think about it, and my previous
| experiences with the "wrong choice of Rust" seem so obvious
| when filtered through this lens.
| avinassh wrote:
| Three months ago I had made exactly similar comment, it felt
| nice to me to see the same thought echoed!
|
| https://news.ycombinator.com/item?id=33845045
| [deleted]
| Animats wrote:
| > If your answer is something like Go or Node.js, then Rust is
| probably not the right choice. If your answer is C or C++ or
| something similar, then Rust is very likely the right choice.
|
| I've been saying that for a while. If you're building web
| backends, Rust is not a good choice. Go is so much easier. The
| green thread system gets rid of the thread/async distinction,
| garbage collection means you don't have to obsess over memory
| management, and the libraries for web backend stuff are the
| same things Google uses internally, so they're well-tested.
|
| A big problem with Rust, long-term, is that the kind of
| programs that really need it are somewhat out of today's
| mainstream. It's not that useful for webcrap. It's not that
| useful for phone apps. The AI people use Jupyter notebooks and
| Python to drive code on GPUs.
|
| Where do you really need Rust? Heavy-duty multi-threaded
| programming. Operating systems. Compilers. Routers and network
| infrastructure. Robotics, maybe. Hard real time. It ought to be
| used more for high-performance games, but the game
| infrastructure isn't there yet. Unreal Engine is C++ and Unity
| is C#. Rust has Bevy and Rend3, but they're not AAA title
| ready.
|
| Perhaps Rust is fighting the last war - the mess inside C++.
| pcwalton wrote:
| > A big problem with Rust, long-term, is that the kind of
| programs that really need it are somewhat out of today's
| mainstream. It's not that useful for webcrap. It's not that
| useful for phone apps. The AI people use Jupyter notebooks
| and Python to drive code on GPUs.
|
| One thing this is missing is that Rust is useful for
| libraries callable by many different languages. You may or
| may not want to use it to build an actual Web app (I
| personally think it's a solid choice, but reasonable people
| can disagree). But for building, say, the Python cryptography
| library [1], which is used as a part of "webcrap", Jupyter
| notebooks, and in many other domains, Rust is clearly an
| excellent option. Nobody is going to build core Python
| infrastructure in Go or Node, and without the plumbing
| libraries none of the higher-level applications can function.
|
| [1]: https://github.com/pyca/cryptography
| huijzer wrote:
| You mean to link against Rust binaries or can you make
| library files too? Compared to, say, SQLite as a single C
| file, I thought that Rust projects are not super easy to
| use as a dependency
| ameliaquining wrote:
| Rust can output library files that use the C calling
| convention, either static or dynamic. Doing this entirely
| by hand is pretty annoying, because your API surface has
| to be C-compatible (so can't contain a lot of Rust's
| useful language features) and because you still have to
| do the other half of the FFI to use the library from the
| other language. However, it's possible to develop
| automated language-specific tooling to make this easier,
| with PyO3 being a particularly impressive example.
| f_devd wrote:
| Depends on how you link rust, using PyO3 makes it
| arguably easier to do link python code to rust than any C
| construction I could think off. Linking a single C file
| into python is quite difficult (if not using JIT like
| cppyy) because you need to make bindings & conversion
| often on both sides for each exported function.
| lumb63 wrote:
| They are out of the mainstream, but only because "systems
| people who have exchanged any hope of losing their virginity
| for the exciting opportunity to think about hex numbers and
| their relationships with the operating system, the hardware,
| and ancient blood rituals that Bjarne Stroustrup performed at
| Stonehenge" "SOLVE THE BEAR MENACE" [0].
|
| [0]:
| https://www.usenix.org/system/files/1311_05-08_mickens.pdf
| usgroup wrote:
| You're right. I think that it replaces C/C++ for many use
| cases. I'm a quant, and I use it to write fast algos for
| research. It won't be long until Rust has good high level
| SIMD primitives like the faster crate offered. I can't see
| myself using anything else thereafter for performant code.
|
| You may be underestimating the amount of need there is for
| performant code though. Its everywhere.
| hot_gril wrote:
| > If you're building web backends, Rust is not a good choice
|
| This heuristic wouldn't work for my department because we
| build web backends in C++. I keep telling the most senior
| devs here that nobody does this and for good reasons
| (velocity etc), and their response is "who cares what the
| rest of the world does, they're just bad at C++."
| Animats wrote:
| Google developed Go specifically so they didn't have to use
| C++ in high-volume web backends, which is what they did
| previously.
| Klonoar wrote:
| _> I've been saying that for a while. If you're building web
| backends, Rust is not a good choice. Go is so much easier.
| The green thread system gets rid of the thread/async
| distinction, garbage collection means you don't have to
| obsess over memory management, and the libraries for web
| backend stuff are the same things Google uses internally, so
| they're well-tested._
|
| The thing here is that _most_ web backends are basic CRUD
| bullshit, and you fundamentally will not hit the thread
| /async distinction, nor need to care about whether there's
| garbage collection or not. Microsoft has used actix-web in
| production as far as I know, it's not like the Rust web stack
| isn't battle tested.
|
| _> Where do you really need Rust? Heavy-duty multi-threaded
| programming. Operating systems. Compilers. Routers and
| network infrastructure. Robotics, maybe. Hard real time._
|
| These are all the things that sit adjacent to a web
| framework, and once you step outside that CRUD happy path,
| Rust fits very well - and in this case just "bolts on".
|
| _> It's not that useful for phone apps._
|
| This is more tangential but I know of more than a few
| companies who have written or are writing their cross-
| platform logic in Rust instead of C++. This is really akin to
| how some projects back Python modules with Rust: it's easy to
| have it backing things and it beats the hell out of dealing
| with C++.
|
| And look, I'm not even saying don't use Go/Python/JS/<insert
| your preferred language here>. You do you, your startup will
| live or die by so many other things than choice of
| programming language.
| WJW wrote:
| There is probably a good space for Rust in writing the
| databases, caches and all sorts of proxies as well. I agree
| though, for most of the stuff I need for $DAYJOB the speed is
| nice but hardly required. It doesn't really matter if I can
| generate a HTTP response 50 microseconds quicker if the
| response then has to travel over the internet for 20+
| milliseconds.
| zozbot234 wrote:
| It does matter if you're using cloud autoscaling FaaS
| (previously known as CGI) and paying for those HTTP
| responses by the microsecond (and by RAM usage as well,
| which is also typically quite low in Rust).
| WJW wrote:
| Not really, the connection won't close until you are done
| sending it all and have received the relevant TCP ACK
| messages from the other sides. Being on autoscaling FAAS
| or not does not matter for that.
|
| In any case, if you are trying to optimize microsecond
| usage in AWS lambda I hope you have a truly gargantuan
| amount of traffic and/or have incredibly cheap engineers
| or the money saved will barely match up to the cost of
| the engineering hours sunk into them.
| ozten wrote:
| NodeJS kind of muddies the waters. It ate a lot of use cases
| that would have previously been done in Java. That created
| conflict between backend teams that wanted statically typed
| code and a "boring" tech choice against "full stack" developers
| creating a backend service.
|
| I think Rust will see a lot of adoption in web services that
| are glorified CRUD APIs. It would have been a poor choice to do
| many of these workloads in this in C or C++ (despite the data
| point of Amazon 1.0 LOLz).
| spullara wrote:
| The latter use case is terrible for Rust.
| dirheist wrote:
| Wouldn't you just use go/python/node for a simple crud API?
| fastapi for python is pretty performative if you use gunicorn
| as your runtime and time to iterate is must faster than it is
| in rust.
| mcronce wrote:
| It depends exactly how simple that CRUD API is. If there's
| any business logic, I'd rather get all the cheap
| correctness guarantees that Rust provides. I don't find
| myself making many truly dumb CRUD APIs.
|
| Time to iterate is also only much faster in certain
| situations, e.g. local development; if you have to e.g.
| build a container image, push to a registry, and redeploy
| to a k8s cluster somewhere, those savings become somewhere
| between less significant and nonexistent.
| nawgz wrote:
| > Time to iterate is also only much faster in certain
| situations, e.g. local development; if you have to e.g.
| build a container image, push to a registry, and redeploy
| to a k8s cluster somewhere, those savings become
| somewhere between less significant and nonexistent.
|
| Can you expand on what you mean here? I know you're not
| implying Rust is faster to move thru a CICD pipeline, so
| can you tell me what you do mean? I seem to be unable to
| make a different reading
| helsontaveras18 wrote:
| "Time to iterate" is measuring how quickly you can get an
| idea, build it in code, deploy it to your customer, and
| get feedback.
|
| If Rust is helping you make prototypes and iterate
| quickly, I'd love to hear how you're using the language.
| brimstedt wrote:
| I've really tried to give js/ts in backend a go. Both by
| nodejs and deno. And by kickstarting my own projects as well
| as diving into experienced nodejs developers' code.
|
| I really don't see how anyone choses nodejs/deno to anything.
|
| Java imo gives you much less trouble, is more stable, has a
| working (!!!) Unit testing setup and exceptional runtime.
|
| Next on my list is to give rust a go, since I'm intrigued by
| its features, but if I was to go fast I'd go with java any
| day.
| ye-olde-sysrq wrote:
| "I really don't see how anyone choses nodejs/deno to
| anything."
|
| This is going to sound mean but I don't really know how to
| phrase it more nicely. People building backends in js/ts
| are doing so because either they, or a critical mass of the
| people they expect to code in it, don't know any better
| backend languages.
|
| I don't mean for this to be judge-y. People have different
| skillsets. A nodejs backend can be the right choice if
| you're a full-stack dev or a solo dev and you mainly know
| js and you get a lot of agility and correctness by _using
| what you know_ instead of trying to use a "better" choice
| but one that _you_ yourself are less likely to use
| correctly or quickly in your own use case.
|
| It can also be the right choice if you're a big backend
| java/etc guru but you know you want to set this thing up
| but then just monitor/oversee frontend/fullstack devs being
| the ones who do incremental modifications to it.
|
| But yeah - without additional outside constraints and
| everything else being equal, it doesn't make a lot of sense
| to use nodejs as opposed to basically anything more boring
| - be it java, rails, etc.
|
| The thing that surprises me the most about node based
| backends is that they forego both the platform maturity and
| static-safety of java AND the ridiculous amount of
| batteries included into django and rails, _just_ to be able
| to use javascript, of all things. What you could rails-g in
| a minute you could instead spend a day looking for an npm
| package that won 't be abandoned in a month or spend
| eternity rolling your own everything and then maintaining
| it.
| tekkk wrote:
| Heh heh, well maybe in some cases but since TS/JS is
| kinda the lowest common denominator in web development,
| it's just the most convenient choice. We humans are
| limited in our capacity to learn and take time to get
| good at things. So it makes a lot of sense to pick a tool
| that can be used to build the whole app with.
|
| And for all of its faults, NodeJS can be fun compared to
| something like Java which feels more like doing taxes.
| Maybe it's the danger. Maybe it's the fact there are so
| many packages and libraries out there - everyone can
| contribute! Who knows, but I won't waste my time learning
| say Rails just to use a "better" backend framework. It's
| good enough even though I know better. There are way more
| important things.
| strokirk wrote:
| Is there any statically typed HTML templating language,
| for non-node languages? Genuine question.
| steveklabnik wrote:
| crates.io for Rust has 213 crates tagged "template-
| engine" https://crates.io/categories/template-engine
|
| handlebars, terra, askama, and maud are examples I
| recognize from high up on that list.
|
| Maud example: (chosen because it's the most "native Rust"
| in a sense and is designed for HTML specifically so I
| believe it's the closest to what you're asking for)
| html! { h1 { "Hello, world!" }
| p.intro { "This is an example of the "
| a href="https://github.com/lambda-fairy/maud" { "Maud" }
| " template language." } }
|
| https://maud.lambda.xyz/
| legerdemain wrote:
| This comment is presumptuous, dismissive, and also wrong.
| People who write application-like front ends in React
| (etc.) want back ends that can interoperate with those
| front ends.
|
| They accomplish things like built-time code generation,
| static server-side rendering, and other kinds of code
| transformation that are difficult and flaky without a
| back end that can understand JS.
|
| I have looked for non-tinkertoy solutions in Java and Go.
| There aren't any, and senior people in those communities
| are hostile to the very idea. (Maybe remembering Java
| Nashorn?) Maybe the only people friendly to the idea of
| interoperable back ends are Rust people (where you have
| libraries like Yew/Sycamore/Dioxus/Leptos that actively
| imitate JS frameworks).
|
| But yes, your claim is that the only reason to write JS
| back ends is ignorance and enfeeblement is ignorant and
| repugnant.
| zozbot234 wrote:
| > want back ends that can interoperate with those front
| ends.
|
| You can ingest and emit JSON in any language. You can
| even compile backend-friendly code to run in JS on the
| frontend, via emscripten (and increasingly, Wasm), which
| will output very lean and JIT-friendly code. The usual
| "isomorphic" case for backend.js is no less
| 'presumptuous' or 'dismissive' than the comment you're
| pointing to and criticizing here.
| legerdemain wrote:
| > You can ingest and emit JSON in any language.
|
| How is this relevant? Serving a JS application to a
| client is not like serving a JSON API. >
| You can even compile backend-friendly code to run in JS
| on the frontend, via emscripten (and increasingly, Wasm),
| which will output very lean and JIT-friendly code.
|
| Not in my experience. Compared to front-to-back JS,
| shipping your applications as WASM ends up with downloads
| and memory footprints that are several times larger than
| the same application in ordinary JS, and this matters a
| lot for slower networks and mobile clients.
|
| Edit: not to mention that Go has a very limited WASM
| story, so your "realistic" choices for shipping back end
| code to the front end are C++ and Rust.
| nawgz wrote:
| > The usual "isomorphic" case for backend.js is no less
| 'presumptuous' or 'dismissive' than the comment you're
| pointing to and criticizing here
|
| > You can even compile backend-friendly code to run in JS
| on the frontend, via emscripten (and increasingly, Wasm)
|
| Lol, you can't be serious
| mardifoufs wrote:
| >>increasingly, wasm
|
| If you are referring to something similar to Blazor
| (client side), yeah no imo it's pretty awful for anything
| other than internal enterprise apps. I couldn't imagine
| running a public facing product on that.
| brimstedt wrote:
| To clarify my point, I think nodejs is great for the
| backend part of the view layer and to proxy requests to
| another backend service.
|
| But for business logic, database interactions,
| calculations, etc, I really think the language construct
| is to clumsy and does not scale nicely.
| ipaddr wrote:
| Your comments tells me you are in the group who doesn't
| know better. Data is passed in json which is a format
| other languages can read and send back. If that's your
| reason for using it you do have other choices.
| CuriouslyC wrote:
| While it doesn't have the batteries, typescript's gradual
| typing is much nicer than python's, so for some use cases
| it's a better language.
|
| All languages come with tradeoffs in terms of
| performance, development/maintenance cost and ease of
| hiring. Most businesses only care superficially about
| performance, which leaves developer productivity and ease
| of hiring. Node/typescript isn't terrible in terms of
| developer productivity, and it's got the best hiring
| story of any language. Python is good in both those ways
| too, but since you already need a javascript hiring
| pipeline for the client it's easier just to use node and
| hire full stack devs.
| worik wrote:
| > typescript's gradual typing is much nicer than
| python's,
|
| It is not Node V. Python, but Node V Java
|
| Python is a terrible choice as a backend, too.
|
| It has a place as a scripting language, but so often it
| is used to build complete systems. They suck.
| helsontaveras18 wrote:
| That's an interesting comment. I chose Node not because I
| love it, but it's the easiest to hire for as a startup.
|
| I hate configuring typescript and having to deal with
| bundlers, package.json, esbuild, etc.
|
| But Deno and Bun are just around the corner. What we need
| is to get rid of this a la carte mentality around tooling
| and just give everyone Typescript, batteries included,
| and make it fast.
|
| Then Node really isn't that bad anymore.
| nazka wrote:
| You should try NestJS with Prisma or Typeorm and Postgres.
| Plus all the classic other stuff. It's a great stack.
| pdntspa wrote:
| And the IDEs which practically write your code for you. I
| mean yeah Java is so verbose but most of that word vomit is
| me just tabbing through autocomplete
|
| I went back and prototyped a slightly similar app in Python
| w/ a gui toolkit and I felt like I was driving through
| exception city. I have made my career writing in dynamic
| languages so I forgot just how pleasant it was to write in
| a static one!
| nawgz wrote:
| > Python w/ a gui toolkit
|
| Sorry, this is always the wrong choice, which is why it
| felt so bad.
|
| Writing a UI in TypeScript with any of the major frontend
| frameworks will not require you to wade through run-time
| exceptions
|
| Java native GUI toolkits are also far more mature
|
| Python and TKinter and similar stuff is always just
| awful, I've never seen someone put together anything half
| decent with that stack
| bxparks wrote:
| Your post is a great example why I wish Go lang was named
| something different. Because you use the lower cased
| versions java, rust, js, ts, nodejs, deno, etc. But all
| your 'go' refer to the verb, not the Go language.
| 8note wrote:
| I find typescript makes the most common things I do in
| business app software as straightforward as possible. That
| is, making copies of objects with slightly different
| structure to pass them to some other system. Typescript is
| just fantastic for plumbing.
|
| To do the same in java means making a billion model files
| with a billion transformation functions on them
| jjnoakes wrote:
| I love Rust but I am still looking for the perfect blend of the
| two camps.
|
| One the one hand, Go/Node/Python/etc doesn't scratch my itch
| for the strong type system (sum types/tagged enums mostly) and
| on the other hand even though I like prototyping in Rust I
| really miss things like a REPL, more terse syntax, and a bit
| more expressiveness.
|
| I think OCaml is closer to my ideal but the ecosystem isn't
| quite there. Maybe all it needs is time.
| baby wrote:
| Yeah I would have recommended OCaml, the language seriously
| need more developers to contribute to the ecosystem. It could
| be much nicer.
| jdlshore wrote:
| Have you looked at Node + TypeScript? I'm just starting to
| dig into TS, but its type system is one of the better ones
| I've seen. And Node is nice and mature with good async
| capabilities.
| jjnoakes wrote:
| I'd prefer something with a more sound type system, and
| something that makes cleaning up resources easier and more
| ergonomic.
|
| This might help with cleanup:
| https://github.com/tc39/proposal-explicit-resource-
| managemen...
|
| But I'm not sure anything will help with the type system.
| For example, this drives me absolutely insane: https://www.
| typescriptlang.org/play#code/MYewdgziA2CmB00QHMA...
| cultofmetatron wrote:
| its older than rust. its had plenty of time. what ocaml needs
| is a renaissance and new blood. sadly it doesn't have the
| momentum of being new but I agree its a compelling language.
| I see it as a better, typed alternative to go.
| tekkk wrote:
| Pick a problem, not a tool first. Unless you're more
| interested in the tool than the problem, then it's fine. I
| don't love Rust, but I can get by. TS+NodeJS is okay. But I'm
| more interested in the problems that I'm solving so I just
| use whatever is the most suited.
| jjnoakes wrote:
| I do that today, but I believe there is still a lot of
| opportunity for languages to approach my ideal, and I think
| I share my ideal with others. And if a language like that
| did exist, or could be made, I'd love to use it - changing
| languages every project is workable, but you'd probably
| agree (I hope?) that NOT changing languages every project
| would be even better.
| hot_gril wrote:
| Yes. I cringe a little getting emails from startup
| recruiters saying "join a Rust startup." As if the success
| of their business hinges on which language they use.
|
| I've found that the basic NodeJS or Python works for most
| problems I've chosen. Not even with strong typing.
| throwawaygal7 wrote:
| Die hard rust fans often minimize the very real developer
| difficulty incurred by their language of choice. Even major
| library maintainers in rust have criticisms of various language
| features because of their difficulty to use. These are real and
| substantiative concerns that would affect any development team
| not made of expert rustaceans. Just look at basic dynamic
| programming implementations in a normal language versus rust for
| say popular leap code questions and you'll see the difference in
| basic developer productivity.
| RcouF1uZ4gsC wrote:
| Question for HN, all things being equal (you are not more
| familiar with one language/framework) what language would you
| choose to build a startup in?
| abledon wrote:
| typescript
| pjmlp wrote:
| Java or .NET platforms, hardly anything else comes close in
| languages, tooling and libraries.
| JTbane wrote:
| Agreed, those are the ecosystems that "just work".
| distcs wrote:
| Python or Go or a mix of both. I have seen new devs with no
| experience in either get get up to speed quickly in both. For a
| startup, velocity is critical.
| [deleted]
| secondcoming wrote:
| Java gives you so much out of the box it's hard to ignore it.
| david_allison wrote:
| Kotlin/C# backend. React (TS) frontend
| alfalfasprout wrote:
| The one appropriate for what you're trying to build. It may
| mean multiple languages.
|
| Not everything is a CRUD mobile app trying to be the next
| tinder for cats.
| steveklabnik wrote:
| I'm not sure all things are ever equal, but I would choose
| Rust.
| orthecreedence wrote:
| The language you're most proficient in that has a somewhat
| decent community.
| adastra22 wrote:
| Go. Swift if it was Apple ecosystem. Rust only for very
| specific tooling as required.
| metaltyphoon wrote:
| Java or .NET
| marcosdumay wrote:
| That's not a good question. There is no reason to pick one
| language over another if you don't even know what software you
| will write.
| it wrote:
| You can also get match in any variant of Erlang or ML, and those
| don't force you to jump through hoops for borrow checking.
| david_allison wrote:
| Also Kotlin: `when` or `with...when` for more complex matches
| jakswa wrote:
| I remember reading about PropelAuth somewhere and thinking that
| Rust might slow down development -- something I wanted to be
| proven wrong about since I've been learning rust off and on, and
| like some things about it. It seems it's ending up up a mixed
| bag, and the negatives in the bag are still light enough that
| you're carrying it forward. Thank you for this blog post!
| frodowtf wrote:
| The reason why people would like to pick Rust is because of its
| ergonomic features like sum types, streams and of course the
| toolchain.
|
| But here is a claim: Most business-level programmers are not
| ready for dealing with the borrowing and ownership concept. They
| don't want to care about reference vs. value types. They can't do
| memory management efficiently, because most of them have never
| used a language without GC.
|
| With Rust you would need to care more about memory which is not
| necessary for most use cases in startups.
| mrichman wrote:
| So in his opinion, choosing Rust is a premature optimization?
| aisrael wrote:
| Author here - yeah, that's how I feel about it, at least for
| startups specifically.
| mrichman wrote:
| What if your startup is in the embedded systems space, for
| example? I don't think you'd be doing your MVP in Python.
| distcs wrote:
| Why impose the "embedded systems" space requirement on the
| OP? The OP does not work in embedded systems space. So it
| is not relevant to this article. The OP is telling us what
| they would do, not what you should do and definitely not
| what embedded systems startups should do.
| steveklabnik wrote:
| (Not your parent but how I read it.)
|
| It's not imposing a space requirement. It's a reminder
| that these generalizations have limitations. The OP isn't
| in the embedded space, but they do say "a startup" not "a
| web startup." There are embedded startups.
| aisrael wrote:
| That's fair, I was definitely being a bit too general.
| There's another comment in this thread that summarizes it
| better which is asking "what would I use if Rust didn't
| exist?" and I think that's a more clear line. All of my
| embedded work was in C/asm so Rust is actually a great
| choice there.
| jeromenerf wrote:
| ... then however, how do you feel about tech debt with Rust?
| My feeling was that go, rust and such left a lighter burden
| on the future than say ruby.
|
| Do you think you will need a major rewrite soon?
| ReflectedImage wrote:
| As long as you know what you are doing Ruby won't leave you
| with more technical debt than Go or Rust.
|
| How many people know how to effectively program in
| languages like Ruby is another question altogether...
| aisrael wrote:
| To me, the language agnostic answer to reducing tech debt
| is having a good test suite so refactoring is easier. We're
| pretty good on that front.
|
| We have definitely done large refactors before, and I'm
| sure we'll have more in the future, but I don't think we
| need a major rewrite or anything like that.
| estebank wrote:
| I find it surprising that so many people are arguing about the
| benefits and drawbacks of `?`, when in my experience the handling
| of Result and Option haven't been an issue in practice on the
| consuming side (`?`, `.unwrap()`, `.map()`, `.ok()`, if let,
| match, let chains, let else, etc. help a lot), but where all the
| pain comes from is having to declare the appropriate error type
| itself. Libraries like `anyhow` takes some of the pain away, but
| declaring an appropriate struct or particularly an enum in the
| right places, and the boilerplate for all the type conversions
| (From/Into impls) are where, during development, I have
| frustration. What I do then is either use Result<T, ()> or a
| single `struct Error(String);`, and go back once I have all the
| scaffolding in place and pry the implicit error tree back into
| the type system. Anonymous enums like typescript (`A | B | C`)
| could presumably help here.
| lenkite wrote:
| All these workarounds for easier Result handling truly make me
| wonder whether Rust will eventually evolve exceptions as a
| feature - of-course without _explicitly_ terming them so.
| tomp wrote:
| Rust already has exceptions, they just call them _panic_ and
| offer exceedingly poor language support for them.
|
| Some people simply live in denial, believing untruths that
| confirm their worldview.
|
| This is the same situation as with Go and generics. The
| maintainers were in denial for a very long time, before
| finally admitting what was obvious to some of us long before
| [1]
|
| [1] https://news.ycombinator.com/item?id=8626978
| xcdzvyn wrote:
| The implementation, outcome, use-case, and characteristics
| of panics are all very different from exceptions. The only
| marked similarity between the two is that they both
| interrupt program execution (and in different ways). But I
| feel as if you already knew that.
| tomp wrote:
| Panics support stack traces, unwind the stack, releases
| the memory, and can either be recovered in some
| situations, or prints an error message. Sounds like
| Python exceptions.
| steveklabnik wrote:
| The community would revolt. Not going to happen.
|
| Proposals to make the existing syntax and semantics even
| _look_ more like exceptions were met with lots of hostility.
| a5huynh wrote:
| I've run into similar issues and found that the `thiserror`
| crate (https://crates.io/crates/thiserror) combined w/ anyhow
| makes a lot of that pain go away
| chrisgacsal wrote:
| I would add `snafu`(https://crates.io/crates/snafu) here as a
| good alternative to thiserror+anyhow.
| echelon wrote:
| `anyhow` + `?` make writing an application as smooth as
| butter. You won't miss exceptions.
|
| Don't use `anyhow` for libraries, though. You want to provide
| your consumers the ability to `match`.
| anacrolix wrote:
| here we go again!
| steveklabnik wrote:
| For those reading this that aren't super familiar, common
| Rust advice is "use thiserror for libraries and anyhow for
| applications," as they make slightly different tradeoffs and
| so are useful, especially together.
| Ylmaz wrote:
| I like this quote from 'The art of Unix Programming' published in
| 2003
|
| "While it still makes sense to write system programs and time-
| critical kernels of applications in C or C++, the world has
| changed a great deal since these languages came to prominence in
| the 1980s. In 2003, processors are a thousand times faster,
| memories are a thousand times larger, and disks are a factor of
| ten thousand larger, for roughly constant dollars.
|
| These plunging costs change the economics of programming in a
| fundamental way. Under most circumstances it no longer makes
| sense to try to be as sparing of machine resources as C permits.
| Instead, the economically optimal choice is to minimize debugging
| time and maximize the long-term maintainability of the code by
| human beings. Most sorts of implementation (including application
| prototyping) are therefore better served by the newer generation
| of interpreted and scripting languages. This transition exactly
| parallels the conditions that, last time around the wheel, led to
| the rise of C/C++ and the eclipse of assembler programming."
| efficax wrote:
| in 2003 you hoofed your servers to a colocation center and
| plugged them into the internet yourself. Deploying was
| something you did over `scp`. Buy a big server and you're good
| to go. That _can_ still be the case these days (see
| stackoverflow which at least until recently was not using cloud
| deployment). But for the most part people use cloud platforms
| that charge by fractions of a second of cpu time. It 's never
| been more cost effective to use a compiled language than it is
| today. And that would also apply to bare metal bring-your-own-
| server deployments. Want to host a monster site on just a pair
| of beefy servers? The less resource intensive your backend, the
| more requests you can serve per second.
| dilippkumar wrote:
| In a benchmark of how many fortune responses are returned by
| various web frameworks[0], nodejs returned 80k odd fortunes per
| second. The fastest c++ framework compared here returned 616k
| odd fortunes per second.
|
| Assuming that my application scales by the same amount (big
| assumption, yes), I could cut AWS costs by 7.7 times (!!!) by
| using the C++ implementation.
|
| I'm pretty sure that maintaining a C++ codebase is less than
| 7.7 times more expensive than Node, even if you throw in extra
| development time etc. This also ignores the decades worth of
| excellent tooling we've built up for C++ (static analyzers,
| fuzzers, etc).
|
| At a startup, when building things fast matters more than
| costs, sure. I buy the argument for Node or Python or any other
| interpreted backend. But once you start to scale, things change
| after some threshold. Unless you're facebook[1].
|
| [0]. https://www.techempower.com/benchmarks/#section=data-r21
|
| [1].
| https://developers.facebook.com/blog/post/2010/02/02/hiphop-...
| Ylmaz wrote:
| The speed of your web framework is, in reality, often
| irrelevant. Our slow nodejs app handles millions of customers
| with a few cheap and simple caching layers. Our salaries are
| a lot higher than the infrastructure costs.
| fweimer wrote:
| Except ... for spewing out fortune responses, most of your
| cost by far will be in bandwidth charges. Those won't change
| with the implementation language. If anything, the C++
| version will just be able to burn your dollars faster.
|
| (Yes, I know, it's just a silly example, but compute costs
| are only one aspect, and the bandwidth pricing in the on-
| brand public cloud actually tilts overall costs towards being
| bandwidth-dominated for many applications.)
| timerol wrote:
| > I'm pretty sure that maintaining a C++ codebase is less
| than 7.7 times more expensive than Node, even if you throw in
| extra development time etc.
|
| The problem here is assuming that a 7.7x less expensive AWS
| bill is the same value as a 7.7x more expensive development
| time. Imagine an app that is maintained by one programmer
| costing $10k a month and running in AWS for $1k a month. It
| is not worth dividing that AWS cost by 10x if it means a 10%
| development time hit. Actual numbers may vary, but
| development often costs much more than running in AWS. (For
| startups it's even more of a difference, because you pay AWS
| as you get more traffic, but you pay developers before you
| have an MVP.)
| apozem wrote:
| That's a great way of looking at it. Languages all have
| benefits and drawbacks, but you have to consider whether they
| help _you_ for _your_ problem.
|
| One time, I met a guy who wrote firmware for Seagate hard
| drives. Any new feature he added had a budget measured in
| microseconds. Obviously he wrote nothing but C++.
| draw_down wrote:
| The doc about pinning seems really good. But I don't understand
| what about it is necessary for something like middleware.
|
| Glad Rust is working for others, and I find it interesting to
| read about. but I don't know if I could or would ever use it
| myself.
| steveklabnik wrote:
| Oxide is a startup and we use Rust for everything except the
| front end of websites (where we use TypeScript.) In some cases
| that's due to hard requirements (embedded) but we use it for web
| backend cases as well.
|
| Iteration time hasn't been an issue, but compile times can be
| annoying. Though obviously compile time is related to iteration
| time.
|
| Of course, all of these things are anecdotal. Collecting
| anecdotes is how you develop evidence, of course...
| badrequest wrote:
| Steve, I just want to say I like you a lot. :)
| steveklabnik wrote:
| Thanks, that's very kind.
| ThatGeoGuy wrote:
| Tangram Vision [0] is also a startup and we also use Rust.
| We're using it to develop robotic / autonomous sensor
| calibration tools that would normally be written in a variety
| of C / C++ libraries.
|
| For context: most if not all of our team has developed
| calibration tooling similar to what we're doing now in the
| past, just at different startups and very specific to certain
| robotic or sensing configurations.
|
| If anything, once we got CI sorted and started using our own
| internal registry I would argue that we are significantly
| faster in terms of iteration time. This is partly because the
| team is small, but also because most of our tooling is
| consistent and easy to keep in lockstep. Pulling libraries is
| done uniformly across platforms and architectures, and our CI
| runs (through GitLab) stay up-to-date with the latest tooling
| without issue. Having a stronger type system to detect errors
| early and a compiler that actually tries to give human-readable
| messages (looking at you C++ linker errors) using that type
| system makes everything so much easier.
|
| Compile time seems like it would be an obvious bit that slows
| one down, but in practice sccache [1] does what it ought to and
| we barely notice it (at least, I don't and I haven't seen team
| members complaining about build times). Mostly I'd argue that
| the real thing holding us back is tooling extant to the rest of
| the wider Rust ecosystem. Debugging and perf tools are great in
| Unix land, but if you're making anything cross-platform you
| need to know more than just perf. That might just be my opinion
| though, I'll admit I'm still learning how best to apply BPF-
| based tooling even in Linux alone.
|
| I also realize I'm responding to steveklabnik, so I suspect
| most of what I'm saying is well-known and that this comment is
| really more directed at TFA.
|
| [0] https://tangramvision.com
|
| [1] https://github.com/mozilla/sccache
| steveklabnik wrote:
| Very cool!
|
| And yeah while I've had similar experiences, I'm glad to hear
| that it's so good for others. And, for example, sccache isn't
| something I have much experience with, so repeatedly hearing
| "it works well" is nice.
|
| (Also, secret of replying to people on the internet: you are
| often replying to the anonymous reader of the discussion as
| much, if not more, than to the person you're replying to.)
| efficax wrote:
| I'm also at a startup using rust. It's true that the feedback
| loop can sometimes feel bit slower. One thing that helps here
| is being test driven so that you're not waiting for compiles
| just so you can click through to confirm a small change in
| behavior. But in general I think my velocity is not much slower
| than it was at a previous company using a node backend. The
| hardest part of software isn't typing in the code and making
| sure it runs. It's thinking about what it should do and how it
| should do it in the first place. And really, Rust's type system
| is a force multiplier. We can prototype really fast, throw out
| things and rework them with confidence because with well
| thought out typing and tests to confirm logical behavior we
| have strong safety guarantees. It lets you experiment and
| investigate alternative implementations fearlessly.
| faitswulff wrote:
| Do you mind my asking what frameworks you're using in Rust on
| the backend, if any?
| steveklabnik wrote:
| We ended up building one https://crates.io/crates/dropshot
|
| Happy to talk about anything!
| shmerl wrote:
| That has a catch 22. If you aren't going to start with Rust from
| the beginning, switching to it later becomes too costly and too
| difficult, which defeats the argument of it being useful in
| general. Most often what's used in the beginning as "prototyping"
| is cemented into the system to the point that it's hard to change
| it.
|
| So yeah, better to deal with complexities in the beginning and
| save on switching later, than not to use it all.
| dhbradshaw wrote:
| We have a fairly complex app with a front end in Typescript and a
| back end in Rust backed by Postgres on AWS.
|
| My favorite part of the job is coding in Rust and we do a lot of
| cool things in that backend code. Unfortunately, most often the
| Rust code is the fastest and easiest part of a change, which
| means that I spend most of my time solving problems either on the
| front end with Typescript or on CI and infra type things rather
| than the Rust part.
|
| It's a bit sad: if something just works, you spend less time on
| it than on the hairier things.
| EVa5I7bHFq9mnYK wrote:
| Backend code is simpler because is has two limited well defined
| surfaces (API for the frontend on one side and database on the
| other side). Frontend is harder because it has to interface
| with those impolite hairy meat creatures ...
| dcow wrote:
| Frontend code has two as well: the input methods (mouse,
| keyboard, screen) and the API surface.
|
| > Backend code is simpler
|
| I hear this every once in awhile and think it's mostly a
| front end happy hour misrepresentation that makes everyone
| feel good so it gets repeated. The service layer of an
| application is very often far more complicated than, or to be
| fair, at least as complicated as, the user interface. Front
| end devs just typically aren't good at chopping up their
| problem into nice interfaces and therefore struggle to test
| it reliably or make large broad changes efficiently. This is
| where the complexity comes in. That's not a stab at FE devs,
| it's just not a skill that often gets rewarded in FE work so
| it's not very prevalent, which I find sad.
|
| The service layer has to deal with enforcing the correctness
| of business logic despite the infinite ways the meat monkeys
| can interact with it. It does this by defining clear
| boundaries on the outside and by ensuring the transactional
| correctness of logic on the inside. While front end folks
| have to figure out the correct UX to use to successfully
| communicate with with a user, service layer folks have to
| figure out all the implications of a single action the user
| wishes to take and make sure it happens correctly. Data
| validation, data modeling, transactions, errors, queuing,
| retries, scaling, monitoring, etc. are all things that would
| probably make the average FE dev explode if thrust upon them.
| newaccount2021 wrote:
| [dead]
| alfor wrote:
| Performance of language is almost never a big concern, but it's
| so interesting for a technical person.
___________________________________________________________________
(page generated 2023-02-17 23:01 UTC)