Recent submissions

Comment · 4 months ago
Steelmanning this decision:

I would guess for the use-case of "I have a C project and I want to run it in Fil-C" the ability for this to be a warning + run-time panic is very helpful for quickly getting started. Reminds me of GHC's -fdefer-type-errors.

I agree that I wouldn't want to deploy a program where those panics are reachable*, but it's still handy for local development and/or maybe the developer knows they aren't reachable.

I haven't checked, but I'd guess there's a warning and a -Werror -style flag to opt-in to having a hard error for unsafe assembly?

* Obviously a panic is better than not. But guaranteed safeness is better than either of those.

Comment · 9 months ago
I'm sure Bill understands what I'm about to say, but as a person on team "require explicit initializations" I think the mitigations I would be looking at are:

1. Only require that the programmer prove the variable is initialized before it's read. Riffing on Bill's example:

    Object *x; // Fine
    if (is_foo) {
      x = &foo;
    } else {
      x = &bar;
    }
    x->a // Fine, was initialized by the time it was used.
Of course this is still a trade-off, your compiler has to work harder to prove that all paths that flow to each use are definitely-initialized. When you have initialization functions you now need to have type specifiers like 'in', 'out', and 'in/out' so that 'out' can take a pointer to uninitialized data, or something like MaybeUninit. This handles this example from Bill:

    Foo f;
    Bar b;
    grab_data(&f, &b); // Fine if 'grab_data(out Foo *, out Bar *)'.
2. Something like Rust's MaybeUninit to explicitly opt-in to wanting to deal with possibly-uninitialized data. Obviously also a trade-off, especially if you want to force all the maybe uninitialized stuff to be in an 'unsafe' block.
Comment · 1 year ago
Making all registers caller-saved around context switches is a neat insight, it's intuitive how that could potentially lead to needing fewer instructions to execute when switching contexts.

I haven't yet digested exactly how the stacks are made to work. I think fig 8 should be obvious, but I'm getting stuck on picturing how the system guarantees that frame 1 can't grow into frame 2.

EDIT: Ah, I think I understand. It seems that they're taking advantage of a large virtual address space to give each stack loads of space, rather than them being contiguous like I assumed from fig 8.

> As modern 64-bit address-space is big enough for the allocation of many large continuous stacks [...]

Comment · 1 year ago
> `foo :: Semigroup a, Traversable t => t a -> a` I already know that whatever is passed to this function can be traversed and have it's sum computed. It's impossible to pass something which doesn't satisfy both of those constraints as this is a specification given at the type level which is checked at compile-time.

To add to your point, I don't think foo can even be implemented (more accurately: is not total) because neither `Semigroup a` or `Traversable t` guarantee a way to get an `a`.

I think you'd need either `Monoid a` which has `mempty`, or `(Foldable1 t, Traversable t)` which guarantees that there's at least one `a` available.

Comment · 1 year ago
Would you expect IS_CONST to evaluate to the constant? With a name like that I would expect it to evaluate to true/false.

C here is asserting that the value inside is a constant and then evaluating to that constant.

Comment · 1 year ago
> One very frustration aspect is that there is basically no real documentation

I looked at DRM/KMS briefly earlier in the year and this is what made me abandon it in the end. Can you recommend any sources of information?

The atomic API and "test only commit" both sound really useful.

Comment · 1 year ago
> doesn't run against the grain of the entire language

Not an expert, but my gut says maybe it runs against zero values? As in, "what's the zero value for a non-nullable reference?" Maybe the answer is something like "you can only use this type for parameters", but that seems very limiting.

Comment · 6 years ago
I think the person you're responding to is agreeing with you that you should optimize for languages other than English rather than for people naming a label "Bin" and then switching to the UK locale.
Comment · 6 years ago
Comment · 6 years ago
Please write a blog post!
Comment · 6 years ago
I'd probably find the name Natural Seitan misleading (i.e. mistakenly buy it thinking it was vegan), but calling it "Animal Seitan" would be perfectly acceptable/clear to me .
Comment · 6 years ago
Forbid "\t* *\t"?
Comment · 6 years ago
I wouldn't do it, but this works perfectly fine. The rule is "use tabs to indent blocks of code, use spaces to align within those blocks".

  <TAB><TAB>function name(arg1, arg2,
  <TAB><TAB>              arg3)
Comment · 6 years ago
What about implementing something like map for lists? You know literally nothing about the values and the function except for their types.

    map :: (a -> b) -> [a] -> [b]
    map f [] = []
    map f (a:as) = f a : map f as
Personally I don't see any reason to use longer names than f, a, and as because you can't add any additional information.

You might say "well I don't write code like that", and I don't have any answer for you. But I find I write a fair amount of generic code.

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton