HNHacker News
TopNewBestAskShowJobs

Measter

344 karma · joined February 8, 2020

submissionscomments
Measter··on Rust’s dependencies are starting to worry me
It can do. Additionally, because each part is now smaller it's now easier to ensure that each part, in isolation, does what it says on the tin. It also means that other projects can reuse the parts. An example of the last point would be the Regex crate.

Regex is split into subcrates, one of which is regex-syntax: the parser. But that crate is also a dependency of over 150 other crates, including lalrpop, proptest, treesitter, and polars. So other projects have benefited from Regex being split up.

Measter··on Rust’s dependencies are starting to worry me
What you're calling "tree shaking" is more commonly called "dead code elimination" in compilers, and is one of the basic optimisations that any production compiler would implement.
Measter··on C++26: more constexpr in the core language
You could have a two-stage process. Stage 1 would be the proposal, where you have the discussion on whether the feature is desirable or not, which can then be provisionally accepted. At this point it is not in the standard.

Then you have Stage 2, which would require an actual working implementation, so it can be properly tested and such. Acceptance in Stage 2 would result in the feature being in the standard.

Measter··on ChatGPT now performs well at GeoGuesser
I think one cause of this (and some other issues with LLM use) is that people see it exhibiting one human-level trait, its capability to use language at a human level, and assume that it then comes with other human-level capabilities such as our ability to reason.
Measter··on ChatGPT now performs well at GeoGuesser
I gave o4-mini-high a cropped version of a photo I found on Facebook[0][1], and it quickly determined that this was in the UK from the road markings. It also decided that it was from a coastal city because it could see water on the horizon, which is the correct conclusion from incorrect data. There is no water, I think that's trees on a hill. It focused heavily on the spherical structure, which makes sense because it's distinctive, though it had a hard time placing it. It also decided that the building on the left was probably a shopping centre.

It eventually decided that the photo was taken outside the Scottish Exhibition and Conference Centre in Glasgow. It actually generally considered Scottish locations more than others.

The picture was actually taken in Plymouth (so pretty much as far from Scotland as you can get in Britain), on Charles Street looking south-east[2]. The building on the right is Drake Circus, and the one on the left is the Arts University. It actually did consider Plymouth, but decided it didn't match.

[0] This image with the "university plymouth" on the left cropped out, just to make it harder: https://www.facebook.com/photo/?fbid=9719044988151697&set=gm...

[1] https://chatgpt.com/share/68024c91-61d0-800c-99b1-fcecf0bfe8...

[2] https://maps.app.goo.gl/3TXv2UxH5128xQjJ9

Measter··on Taming the UB Monsters in C++
> Compilers rather works in terms of UBs being constraints (on the program), which they can then leverage for optimisations. All the misbehaviour is emergent behaviour from the compiler assuming UBs don’t happen (because that’s what an UB is).

I think a good way to view this would be that optimization passes have invariants. The passes transform code from one shape to another while ensuring that the output from running the code remains the same. But in order for the transformation to be valid certain invariants must be upheld, and if they are not then the result of the pass will have different output (UB).

Measter··on How many artists' careers did the Beatles kill?
I have a weird second-hand memory by this. Back in the 90s, when I was still in school, we were having a bit of a relaxed period. My teacher had the radio on and was marking some stuff, while we kids were doing whatever.

At one point, while I was talking to him, Stairway to Heaven started playing, and he told me that every time he hears that song he remembers the taste and smell of a cheeseburger he had when he visited the US years before.

Now, every time I hear that song, I think of cheeseburgers.

Measter··on Zig's dot star syntax (value.*)
> Also, from learning human languages, it's a well-known lesson that phrasebook-type "this means this" translations (like some here are asking, from Zig to C/Rust) are useful for quick and dirty learning good enough for one trip, but long term learning needs this kind of a direct explanation.

This is also good when the user already knows the concept. Like, I'm a reasonably competent Rust user, and when I started playing around with Zig I already understood the majority of concepts at play and just needed to know how Zig spelled them. But I still needed that more in-depth explanation for concepts I was less familiar with (comptime being the main one).

Measter··on How types make hard problems easy
Yeah same, though with Rust. I once did a refactor of my compiler project where I completely rewrote how the AST was represented, then spent the next three or four hours fixing compiler errors.

Worked perfectly first time, because the type system allowed compiler to tell me everything that was broken.

Measter··on The humble for loop in Rust
> It does have syntax for them, but that is just syntactic sugar for an class with a single method under the hood. So streams end up doing lot of object allocation and garbage for the fake closures.

In Rust a closure is really just a struct that implements up to three closure traits, each of which provide a single function. So from that side of things, what Java is doing for them isn't inherently different from Rust.

Measter··on Making memcpy(NULL, NULL, 0) well-defined
The value of an abstract machine is that it allows you to specify how a given program behaves without needing to point to a specific piece of hardware. Compilers then have this as a target when compiling a program for a specific piece of hardware so that they know when the compiler's output is correct.

The issue here is that the abstract machine is under or badly specified.

Measter··on Move semantics in Rust, C++, and Hylo
They mean whether the value is properly initialized, as in all the bytes that make up that value have set values that are valid for that type. For example, in Rust the only valid values a boolean can have are 0 and 1, anything else is invalid. Notably, in the abstract machine, bytes actually have 257 values: 0-255 and uninitialized. Uninitialized means that an initialized value was never written to it. Reading a value that is not properly initialized is undefined behaviour, and optimization passes can result in unpredictable changes in behaviour of the code.

The type they mentioned is MaybeUninit (https://doc.rust-lang.org/std/mem/union.MaybeUninit.html), which is used to represent values that are not fully initialized. It's worth reading the documentation for that type.

Measter··on RAII and the Rust/Linux Drama
You were conflating details of C++'s object model and implementation of move semantics with RAII. Rust also makes heavy use of RAII, and the details of its object model and move semantics are not the same as C++'s.

The only thing that RAII requires is the concept of ownership, and a cleanup function that the compiler knows about. The one implicit thing here is the automatic insertion of calls to the cleanup function.

Measter··on RAII and the Rust/Linux Drama
> When does your constructor & destructor fire when a dynamic array grows?

What constructor? And why would a Drop implementation be invoked to move something? You've moved it, there's nothing left to drop.

> Did you use the copy-and-swap idiom properly?

I don't believe I'm familiar with this idiom? From some quick googling this seems to be related to panic safety and ensuring that you don't leave things in an invalid state if a panic happens. It doesn't seem to be RAII-specific, and would also apply to a defer mechanism.

> Did you define all the "rule of five" methods?

Rule of five? You mean that your Clone implementation must properly handle resources in accordance with your Drop implementation, right? I'm not sure where the other three come in?

Measter··on The two factions of C++
> The default cargo crate (template?) encourages people to use permissive licensing for their code. So that is an example where you are already making implicit political decisions on behalf of the ecosystem and developers. That is alarming and should not be for the language maintainers to decide at all.

You and I must be using two very different versions of Cargo, because on mine the default template doesn't specify a license.

Measter··on Zig's (.{}){} Syntax
Most languages handle this by having interfaces/traits/etc.

Zig doesn't have those, so you're forced to use these ad-hoc struct instances.

Measter··on C++ proposal: There are exactly 8 bits in a byte
Rust has two possible behaviours: panic or wrap. By default debug builds with panic, release builds with wrap. Both behaviours are 100% defined, so the compiler can't do any shenanigans.

There are also helper functions and types for unchecked/checked/wrapping/saturating arithmetic.

Measter··on Smart pointers for the kernel
You might be thinking of CVE-RS[0] which is exploiting bugs in the compiler.

[0] https://github.com/Speykious/cve-rs

Measter··on Smart pointers for the kernel
There was a paper a few years ago[0] was related to proving soundness. That could be what they meant.

[0] https://plv.mpi-sws.org/rustbelt/popl18/paper.pdf

Measter··on The strict aliasing situation is pretty bad (2016)
Rust's aliasing restrictions only apply to references. If you only stick to pointers and never at any point create a reference, you can alias to your heart's content.

For example, the equivalent[0] of the article's Offset Overlap example is perfectly valid according to Rust's abstract machine. What makes it hard is avoiding the creation of references. If I create a reference, then there's a good chance that the lifetimes don't get correctly linked up, and I accidentally have shared mutation/use after free/other UB.

[0] https://play.rust-lang.org/?version=stable&mode=debug&editio...

Measter··on Rewriting Rust
Having a quick look at efsw, it depends on both libc and the windows API, both are huge dependencies. The Rust bindings for libc come to about 122 thousand lines, while the winapi crate is about 180 thousand lines.

[Edit] And for completeness, Microsoft's Windows crate is 630 thousand lines, though that goes way beyond simple bindings, and actually provides wrappers to make its use more idiomatic.

Measter··on Rewriting Rust
Though we should also accept that some things are just hard. Though that's not to say that we should give up on trying to make them as easy to learn and use as possible.
Measter··on Creating an empty iterator of a certain type in Rust (2018)
I'll ignore the option of returning a Vec or Option, as the article already went over why these options were rejected, and concentrate on the later options.

Firstly the `std::iter::empty()` attempt: The issue they had here came down to the signature of the function. What they wanted to do was return an `impl Iterator<Item=&N>`. This means that the function isn't naming the specific type it returns[1], only stating that it's an Iterator that gives some `&N`s. However, the return type of this function is still one, specific type. You cannot return two different types that are both iterators. That's why this one failed.

Boxing: Instead, we can return a `Box<dyn Iterator<Item=&N>>`. This is roughly equivalent to a function in C# returning an `IEnumerabale<N>`, in that the actual type is hidden, and the work is done doing dynamic dispatch. This allows you to return different kinds of iterators, because the specific type is hidden away inside the Box. The downside here is that you're doing a heap allocation.

OptionIterator: This one is actually basically just the first Option case from earlier but wrapped up in a nicer-to-use interface for the user because it implements Iterator in a way that transparently handles the Option.

[1] Additionally, it's not even possible to name the type of the iterator here due to the filter closure being unnamable.

Measter··on Swift is a more convenient Rust
Bear in mind that the optimization on `Option<Infallible>` isn't specific to that type; it applies to anything that results in one possible value. For example, `Foo` in this example is also zero-sized:

    pub enum Foo {
        Foo,
        Bar(A),
        Baz(B),
        Qux(C),
    }

    pub enum A {}
    pub enum B {}
    pub enum C {}
The optimization applied to Vec also applies to any zero-sized type.
Measter··on Swift is a more convenient Rust
What's happening is that `Infallible` has no values, and cannot be instantiated. This results in `Option<Infallible>` only having one possible variant (None) which has no payload, and therefore being a zero-sized type.

Separately `Vec<T>`, if `T` is a zero-sized type, never allocates and has a capacity of usize::MAX. Then, when you push into the Vec, because the value you push is zero-sized, there's no allocation and no data to write anywhere. Therefore the only effect is to increment the length counter.

Measter··on Swift is a more convenient Rust
How are build times for AOT these days? Last time I tried it (~2019) it was slower than Rust at building the same project.
Measter··on Swift is a more convenient Rust
I've found it's kinda helpful to think of Rust/modern C++ style management as semi-automatic memory management. You control when things are allocated and freed, but you don't bother with the minutia of it unless you're writing a low-level container type.

This is contrast to something like C/Zig, where things are fully manual, or something like Python or Javascript where things are fully handled for you.

Measter··on Zig's Memcpy, CopyForwards and CopyBackwards
I think Steve might have forgotten (so many helper functions...), but Rust's slices have a `copy_within`[1] function for exactly this scenario:

    fn main() {
        let mut buf: [u8; 16] = *b"D04GOKUD09OVER90";
        
        buf.copy_within(7..16, 0);
        
        println!("{:?}", buf);
    }
It does only support types that are trivially copyable, but it's implemented exactly you'd expect: bounds checking then memcopy handling overlap.

[1] https://doc.rust-lang.org/std/primitive.slice.html#method.co...

Measter··on FreeBSD considers Rust in the base system
My understanding is that no one's asking them to take on that burden. What seems to be being asked is for them to explain the current semantics of the API, because it's unclear what they actually are.

From the sounds of it, some of them consider this request unreasonable.

Measter··on Ask HN: Why are AI generated images so shiny/glossy?
That's definitely been one of my hurdles. Though ammusingly one thing that's helped is to give an example to ChatGPT and ask it to describe the art style.
← PreviousPage 3 of 8Next →