Hacker News new | ask | show | jobs
by mswphd 23 days ago
LLMs do significantly better when they get reliable feedback on their actions (try to create any non-trivial project in some language without letting the LLM use a compiler. Similarly, talking with a "chat LLM" will produce worse code than an "agentic LLM").

Anyway, making such a (breaking) change in rust immediately tells you all of the callsites that break. You have to chase it through, but that's mechanical/low context work. More formally, you can parallelize across files with sub-agents to not pollute your main agents context window. So it really should be a "zero context window" cost.

Whether or not strict typing is strictly better is really a correctness/velocity tradeoff, the same as it always has been. For most projects something in the middle is right.

As for owned vs borrowed and things propagating quite a bit, sometimes it happens. It's often avoidable with a couple of tricks

1. always default to borrowed unless you have a good reason to otherwise

2. make your function signatures more permissive so they can support either way. This can be done by modifying f<T>(x: T) (or f<T>(x: &T)) to f<U: AsRef<T>>(x: U). The later can be equivalently written as f(x: impl AsRef<T>).

When you say "change a field from owned to borrowed", I'd generally suggest not doing that. It's generally easier to start with some owned type MyType. You can then have function signatures take &MyType as input. This borrows all the fields, and is often good enough for most functions.

If you have a more esoteric function (that needs a combination of borrowed and owned inputs), it's typically easier to define a struct for that function. The steps are

1. Define a FunctionInputsRef<'a>

2. write `impl<'a> From<&'a MyStruct> for FunctionInputsRef<'a>`, then

3. update your function to take as input FunctionInputsRef<'a> rather than `&MyStruct`, and

4. update callers with `input -> input.into()`.

It has the benefit of less churn, as you're maintaining the old def (which might be useful elsewhere), and only updating the callers in a fairly trivial way. `FunctionInputsRef<'a>` can also be defined local to the function, so it is modularized better. If you later have other functions with other requirements, it's a relatively easy pattern to duplicate as well.