HNHacker News
TopNewBestAskShowJobs

eddyb

465 karma · joined February 28, 2014

submissionscomments
eddyb··on First Impressions of Rust
You can use #[cfg(doc)] and #[cfg_attr(doc, ...)], but it looks like that still requires #![feature(doc_cfg)], so I guess it wouldn't be compatible with stable rustc anyway, until it's stabilized itself.
eddyb··on Rust 1.45
Long-term, with const generics, and VG (or a macro that creates a (a, (b, (c, ()))) nesting like the hlist crate), we could maybe replace format_args! and friends.

However, there is one more thing a function can't do: borrowing arguments. Formatting never moves arguments because the format_args! macro generates references to them, which it then creates std::fmt::Argument out of.

eddyb··on I Want Off Mr. Golang's Wild Ride
I wonder if people upthread meant the warning, or e.g. getting the `Foo` in `Result<Foo, BarError>`.

(EDIT: nevermind, just looked again and pcwalton was referring to the warning and specifically `Result<(), E>`; oh well)

Because the latter is impossible in Rust and probably more relevant to the usual cited issue with Go's pair approach (i.e. using the null/zeroed `Foo` without checking if there was an error).

I do agree though that the warning isn't to stop you from not handling the error at all, it's more of a hint that maybe you forgot something.

Printing a `Result` may be the legitimate way to handle it in that case, it's largely left to the user to decide what propagates and what doesn't.

eddyb··on The Rust Compilation Model Calamity
Monomorphization tends to happen "on the fly", and even if it wasn't, it would still be cheaper than duplicating all of the work of parsing and type-checking (which is needed if the user manually monomorphized).
eddyb··on Rust 1.34.0
> I also don't know what you mean by local git dep.

Presumably, the `git` URL for dependencies, in `Cargo.toml`, can point to a local git repository. That should let you refer to a branch / commit of that repository, other than the one currently checked out (which is what using a `path` dependency would give you).

eddyb··on Writing an OS in Rust: Advanced Paging
Then you can use the techniques in the thread I linked.

But without guarding mutability behind some way to indicate interrupts are disabled, or an outright lock, and without guaranteeing no data races (Sync), it's not actually safe.

And the compiler can't make `static mut` safe to use as any of those requirements could be broken and then it's not safe at all anymore.

eddyb··on Writing an OS in Rust: Advanced Paging
If it's per-core you should look into making `#[thread_local]` statics work, which remove some of the restrictions.

`static mut` is not always safe even in a single-threaded environment, because of reentrance - see also https://github.com/rust-lang/rust/issues/53639.

eddyb··on Rust has a static “garbage collector”
Not using pointers at all for graphs.

I suspect a lot of the data where you want to use pointers for efficiency, is already in stricter shapes than graphs.

eddyb··on Falling in love with Rust
Not sure how many editors' syntax highlighting do this by default, but at least for me, it really helped to make `?` bold red.
eddyb··on Falling in love with Rust
Note that Rust has "forward goto" in the form of "labelled break" (which can even carry a value), so I suspect some cases might not even need converting to a loop-match "state machine".
eddyb··on The Xi Text Engine CRDT
This is an old link, but I could find https://github.com/google/xi-editor/blob/master/docs/docs/cr... on master.
eddyb··on Announcing Rust 1.28
Yes, but limited to being applied at compile-time, with constant arguments.

Fully general dependent type would allow passing in runtime values, which is significantly harder to type-check and execute

eddyb··on Announcing Rust 1.28
Since nobody mentioned it by name, the TLS replacement they're suggesting for lazy_static is `thread_local!` and it's part of libstd.
eddyb··on Async and Await in Rust: a full proposal
I don't understand why people don't just support TLS in non-userspace code. It's so convenient for a bunch of things, and sadly Rust, for now, has nothing in between "fully explicit argument passing" and "scoped global state".
eddyb··on Async and Await in Rust: a full proposal
I would also mention https://github.com/edef1c/libfringe which pretty much solves context-switches (by replacing them with compiler-generated minimal stack spills/restores).

But as you might be able to tell from their APIs, you still have to allocate stacks somehow.

eddyb··on Async and Await in Rust: a full proposal
> guaranteed optimisation to a single stack frame and no allocation where possible

You are literally describing stackless coroutines. And the generator state transform is that optimization.

If you want to get this without using generators explicitly, it's still stackless coroutines just not how Rust supports stackless coroutines. There was some discussion about making it more implicit but no progress was made in the implicit direction.

eddyb··on How to speed up the Rust compiler some more in 2018
We've experimented with MIR-only rlibs - https://github.com/rust-lang/rust/issues/38913#issuecomment-... has some recent data on it - which seem to me like the best approach for solving this, but it needs more work.

Eventually, we might compile everything at once, making the whole "crate" separation a tad bit obsolete (or even silly), other than for code organization (it has other complications, like trait coherence).

eddyb··on Depressing and faintly terrifying days for the C standard [pdf]
Wasn't the ordering thing in C for stack push order in calling conventions? At least that's one theory I've heard.
eddyb··on Depressing and faintly terrifying days for the C standard [pdf]
You won't be able to entirely validate yourself most memory-related invariants in a language which can allow breaking memory safety, that's why I mentioned the hypothetical language which can encode proofs for invariants.

What you want is effectively automated proof-search (a hard problem) for an entirely-safe systems language (which doesn't even exist yet, AFAIK. at least not what I described).

eddyb··on Depressing and faintly terrifying days for the C standard [pdf]
It's interesting to see which things Rust has defined where C refused to, such as fixing a strict evaluation order (mostly post-order on the AST), requiring signed integers to be 2's complement or masking shift amounts (`x << n` being `x << (n % bitwidth)`).

Where does C actually gain anything nowadays? Signed integer UB is mostly useful for optimizing misuses of `int` for unsigned values (https://news.ycombinator.com/item?id=17191295), and is evaluation order even relevant anymore? (I don't think clang can pass that information down to LLVM, at all)

The only example I gave which has known drawbacks is the shift one, where modern platforms differ in the behavior, and LLVM will only optimize out the masking of the shift amount on the platforms that have that same behavior in their shift instructions (I think x86, but not ARM).

However, even if you make all of these changes to C, there's still a lot of UB left, in the form of memory accesses, which is much harder to get rid of (see the other comments, some of which mention Rust as well).

eddyb··on Depressing and faintly terrifying days for the C standard [pdf]
The UB is the result of operations which assume invariants, when they are not met. Invariants are useless if you can't assume them. Having no UB in C would require having no way to break those assumptions but C is memory/type-unsafe so that's outright impossible.

Recently I've been trying to imagine what Rust's safe abstractions that use `unsafe` code internally would look like on top of some advanced mix of dependent type theory and proofs about state-manipulating imperative programs.

At that point, the optimizer would have proofs of the invariants it can rely on and it could even potentially emit proofs that every single transformation it performed preserves the (safe) semantics of the code being optimized.

But we're not there yet. Today, we need at least a small subset of the libraries of a systems language to prevent UB "by hand". And in C (or C++, although not necessarily for the same reasons), that's even harder, as there is no notion of a "safe abstraction" (one which you cannot misuse to produce UB).

eddyb··on Depressing and faintly terrifying days for the C standard [pdf]
Some of that is sadly C having bad defaults - like people ending up using signed 32-bit integers (i.e. `int`) to index arrays on 64-bit platforms, which keeps signed integer overflow UB relevant, for optimizing typical indexing C code.

Both C++ and Rust use pointer ranges for iteration, and Rust even forces indexing/counting to use pointer-sized unsigned integers. So Rust turned off the LLVM bit which says "signed overflow is UB" and did not really lose much from it (AFAIK, anyway).

eddyb··on Depressing and faintly terrifying days for the C standard [pdf]
See this sibling thread https://news.ycombinator.com/item?id=17189666 - typically anything touching memory needs invariants to be optimized, which in languages that can directly manipulate memory means there's also UB (code that can't be statically proven not to break those invariants).
eddyb··on Depressing and faintly terrifying days for the C standard [pdf]
Indeed. Only wanted to point out that their optimizations also rely on UB, so they're bad examples for specifically "optimizing without relying on UB".
eddyb··on Depressing and faintly terrifying days for the C standard [pdf]
You get register allocation back if you deny taking the address of variables declared with the `register` keyword - and we've gone full circle!
eddyb··on Depressing and faintly terrifying days for the C standard [pdf]
Note that `unsafe` code blocks (or having some unsafe primitives) fundamentally results in some kind of UB in the language as a whole, and you totally can create tons of problems from it, since the rest of the language has invariants it can't itself violate, but the unsafe code can (potentially much easier than C, if there are more invariants) - that is the "UB", and the invariants that can be violated are what the compiler optimizes based on.

Lest we forget, any language with a C FFI capability must have some notion of UB, because the FFI effectively includes the C code in its own semantics (unless fully sandboxed, which may be too expensive to be done).

eddyb··on Depressing and faintly terrifying days for the C standard [pdf]
The languages that you describe must look nothing like C (other than, ironically, syntax), and must have no untyped direct memory access pointer feature at all, which usually means they rely on a GC instead for memory safety.
eddyb··on Writing Complex Macros in Rust: Reverse Polish Notation
Right, you can write a function that returns its argument plus one, but it couldn't e.g. evaluate `e` more than once (which both C and Rust macros can).
eddyb··on How the JVM compares strings on x86 using pcmpestri
What do you think about Cray-style vectors, which are coming back in the form of ARM SVE and the RISC-V V extension?

At least the latter claims code compiled once is compatible with all possible hardware configurations, from the start (by way of giving the CPU a "remaining iterations count" and having it reply with how many it can do for the chosen vector lane shapes).

IMO, if it does end up working that well in practice, it does put all of the various incompatible versions of packed SIMD extensions in a pretty awkward spot - could we have skipped all of MMX, SSE, AVX, NEON, etc. versions with technology that has been around for almost half a century?

eddyb··on Homotopy Type Theory and Higher Inductive Types
Given an equivalence between (all the values of) two types, you can assume the types are equal, i.e. substitute one for the other in any value, no matter how complex (including functions on values/types etc.).

The value/function conversion is called a "transport" and it actually depends on which equality you've chosen (called "paths" in HoTT).

E.g. bool <-> bit can map false => 0, true => 1 or false => 1, true => 0.

So `(a: bool, b: bool) => a && b` can be "transported" to `(a: bit, b: bit) => a & b` or to `(a: bit, b: bit) => !(!a & !b)` (which is `a | b`).

Of course, bit tricks aren't that useful, but two types which are defined differently (e.g. from different libraries, or different versions of the same library), yet contain the same information, would be interchangeable given a "path" (in the case of the Univalence Axiom, a proof of equivalence).

The other important addition in HoTT is defining non-trivial "paths" (equalities) between values of a type when you define the type - this is used in the HoTT book to describe integer, rational and real numbers, in a way reminiscent of quotient sets.

← PreviousPage 2 of 6Next →