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

Battery-only EVs have a much simpler drive train, and longer-lasting batteries.

Hybrids are not simply EV+ICE, they have very different kind of batteries (low-voltage, high C-rate).

In a hybrid, you have a battery that is 1/10th of the size, so the battery works 10x harder – needs to discharge at higher rate to move the car by itself, and usually there's no room for proper cooling of the battery.

In a BEV you have 10x more modules working at 1/10th of that rate, and there's battery management system keeping it at optimal temperature.

Batteries live longer when they're kept in 20-80% state of charge, and don't like to be cycled deeply. Small hybrid batteries get charged and discharged fully quite regularly, while the same distance needs only 10% of BEVs battery.


In the UK (and probably most of Europe) there is already regulation requiring new residential parking and garages to have a grid connection installed, to be able to easily add chargers at residents' request (even if they're renting).


Exclusive access is nice, but not necessary.

BEVs used just for city driving need to be charged about once a week, so you just plug in when there's an opportunity. A basic 7kW charger is enough to charge full battery overnight.


GameBoy Advance had a CPU without cache, but with 32kbit of fast RAM on the chip. That was pretty close to a fully manual cache, and turned out to be a complete waste in practice.

It was impractical to share/reuse it like a real cache, because that would require writing some sort of memory allocator or a hash table — in software. Managing that was a hassle, and an overhead in itself. Only a few games (mostly 3D) took advantage of it, and simply by copying their hottest loop in there.


EVs on public roads must still obey the same speed limits and common sense behavior. Having more torque doesn't mean drivers have to slam brakes like on a race track.

In normal driving regenerative braking takes away most of the energy, leaving very little work for the friction brakes. Sometimes EVs even have the opposite problem — brakes rust due to very low use.


Who's going to pay for carbon capture? Definitely not the current polluters who benefit from fossil fuel prices that don't include the cost to clean that up. This is like a fossil fuel subsidy from a debt left to someone else to pay.


>Who's going to pay for carbon capture? Definitely not the current polluters who benefit from fossil fuel prices that don't include the cost to clean that up.

Carbon emitters through carbon pricing schemes. They already cover more than 20% of worldwide emissions, with China joining a few years ago.

[1] https://www.economist.com/cdn-cgi/image/width=1424,quality=8...


> towards feeling safe about dependencies

Sandboxed is better than unsandboxed, but don't mistake it for being secure. A sandboxed JSON parser can still lie to you about what's been parsed. It can exfiltrate data by copying secrets to other JSON fields that your application makes publicly visible, e.g. your config file may have DB access secret and also a name to use in From in emails. It can mess with your API calls, and make some /change-password call use attacker's password, etc.


You seem to have a very narrow understanding of the utility of language purity and effects systems.

Yes, the parser can lie to you. But the actual lying can only depend on the code you are parsing. No it can't just exfiltrate data by copying it into other messages.


I've said fields, not messages. It can exfiltrate data by copying it between fields of the single message it parses.

Imagine a server calling some API and getting `{"secret":"hunter2"}` response that isn't supposed to be displayed to the user, and an evil parser pretending the message was `{"error":{"user_visible_message":"hunter2"}}` instead, which the server chooses to display.


I'm trying to puzzle this one out a bit. Who are the good and bad actors in this threat model?

I wrote a server:

  myServer = do
    fetched : Bytes <- fetchFromExternalApi
    let parsed : SecretResponse = jsonParse fetched
    return parsed
    
This code is all mine except for the jsonParse which i imported from a nefarious library. If jsonParse returns a SecretResponse, then the code will compile. If jsonParse returns an ErrorResponse, it won't compile.


In more mature implementations a simple "doesn't parse" doesn't cut it. You may want to get specific error codes to know if you should retry the request, or blame the user for bad inputs, or raise an alarm because the API changed its schema unexpectedly. You'll also want to report something helpful to the end users, so they can understand the issue or at least have something useful to forward to your tech support, so you don't just get "the app is borken!! don't parse!!11".

JSON APIs often have a concept of an envelope that gives them a standard way to report errors and do pagination, so the message would have been parsed as some Envelope<SecretResponse>, or reparsed as an ErrorResponse if it didn't parse as the expected kind.

JSON is used in lots of places where lying about the content could cause trouble, and this is just one hypothetical example. I just want to bring attention to the class of attacks where a malicious dependency can lie through its normal API, and may have opportunity to turn its caller into a Confused Deputy instead of having to break out of the sandbox itself.


The change itself was very reasonable. They only missed the mark on how that change was introduced. They should have waited with it until the next Rust edition, or at least held back a few releases to give users of the one affected package time to update.

The change was useful, fixing an inconsistency in a commonly used type. The downside was that it broke code in 1 package out of 100,000, and only broke a bit of useless code that was accidentally left in and didn't do anything. One package just needed to delete 6 characters.

Once the new version of Rust was released, they couldn't revert it without risk of breaking new code that may have started relying on the new behavior, so it was reasonable to stick with the one known problem than potentially introduce a bunch of new ones.


But that is not how backwards compatibility works. You do not break user space. And user space is pretty much out of your control! As a provider of a dependency you do not get to play such games with your users. At least not, when those users care about reliability.


Meaning of this code has not changed since Rust 1.0. It wasn't a language change, nor even anything in the standard library. It's just a hack that the poster wanted to work, and realized it won't work (it never worked).

This is equivalent of a C user saying "I'm disappointed that replacing a function with a macro is a breaking change".

Rust had actual changes that broke people's code. For example, any ambiguity in type inference is deliberately an error, because Rust doesn't want to silently change meaning of users' code. At the same time, Rust doesn't promise it won't ever create a type inference ambiguity, because it would make any changes to traits in the standard library almost impossible. It's a problem that happens rarely in practice, can be reliably detected, and is easy to fix when it happens, so Rust chose to exclude it from the stability promise. They've usually handled it well, except recently miscalculated "only one package needed to change code, and they've already released a fix", but forgot to give users enough time to update the package first.


> attempting to design a new programming language without first studying carefully the history of programming

Rust's original designer credits these languages as the inspiration: http://venge.net/graydon/talks/intro-talk-2.pdf

Mesa (1977), BETA (1975), CLU (1974), Nil (1981), Hermes (1990), Erlang (1987), Sather (1990), Newsqueak (1988), Alef (1995), Limbo (1996), and Napier (1985, 1988).

The original Rust compiler was written in Ocaml.

> has to specify whether function parameters are passed by value or by reference

You specify whether arguments are borrowed or moved, and whether the access is shared or exclusive. This is not an implementation detail, it's an API contract that affects semantics of the program. It adds or removes restrictions on the caller's side, and controls memory management and thread safety.

People unfamiliar with Rust very often misunderstand Rust's borrowed/owned distinction as reference/value, but in Rust these two aspects are orthogonal: Rust also has owning reference types, and borrowing types passed by copying. This misunderstanding is the major reason why novices "fight the borrow checker", because they try to avoid copying, but end up avoiding owning.

There are different possible approaches to achieving similar results for argument passing, but Rust prefers to be explicit and give low-level control. For example, Mutable Value Semantics is often cited as an alternative design, but it can't express putting temporary loans in structs. The syntax needs a place to declare lifetimes (loan scopes), as otherwise implicit magic makes working with view types tricky or impossible: https://safecpp.org/draft-lifetimes.html


Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

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

Search: