HNHacker News
TopNewBestAskShowJobs

compi

26 karma · joined August 23, 2019

submissionscomments
compi··on Helvetica Now Variable
Web fonts are so weird, to display this site I had to download the advertised font as a .WOFF file to my computer. I now have a fully featured copy of what they are selling.

I know they are actually selling the license to use it but still it seems weird that any site that licenses and uses this will also be mass distributing it to peoples machines.

compi··on UI and Design Inspiration for Developers
I miss ffffound.
compi··on Working with Strings in Rust
I did miss that until I read your post, looking up behavior that your program relies in a language standard seems easy to me to because I _have_ to as a C programmer, a lot, for the reasons you and the post mentioned. I totally agree with you, and nearly all of the C footguns in the article.

That being said I'm still doubling down on my post:

"who knows" if argv is const? Me, because I program for a standard of C that guarantees that that it's not const and that it's pointers and the strings it pointers to are both modifiable.

And "who knows" if toupper returns an error because "It's a C API! Anything is possible!"

Also me, because I program for a standard of C where toupper returns what you gave it, or it gives you a single character back that _might_be_different_ based on the host computer's language.

Not defending toupper and towupper, but it is explicitly unreliable in the C standard I program to.

If I naively wrote a case-insensitive file manager in Rust, wchar_t C, or C with ICU, could operations on the following files be reliable on a German computer and on a English computer? If they are reliable, then is it correct to the point where either person wouldn't overwrite a file on accident? If the Rust one overwrites files, is it a smaller fuckywuky since Rust programers value "safety, correctness, and performance"?

    ẞ.txt
    β.txt
    阝.txt
    ß.txt
    ẞ.txt
    SS.txt
    ss.txt
compi··on Working with Strings in Rust
The first half was a surprisingly ok intro to unicode and utf encodings in C. Super clearly illustrated a handful of pitfalls of trying to roll your own utf8 handling code in C.

But it irks me when rust blogs misrepresent C to show that Rust is better:

    How nice. We even use const in all
    the right places! I think! Except
    maybe argv! Who knows? The compiler
    sure doesn't seem to care much. I
    guess casting non-const to const is
    pretty harmless. Fair enough, GCC,
    fair enough.

    Lucky toupper has no way to return
    an error and just returns 0 for 0,
    right? Or maybe 0 is what it returns
    on error? Who knows! It's a C API!
    Anything is possible.
Both of these have defined answers written into the C standard itself.

Also you can have const memory in C that will crash if you cast it to non-const and write to it. You can call out to the OS to mark a chunk of memory it as read only. The reason it's not as built into C as it is for Rust is that C was in part designed for and currently runs on hardware where there isn't read-only-memory outside of a physical ROM chip.

    So the problem here is that… we
    allocate enough room for “DOG\0”,
    but we end up converting “doggo
    override\0” to uppercase, so we end
    up writing past the area that malloc
    allocated for us.  I believe the
    technical term is a fucky wucky
    buffer overflow.
Something about this sentence screams Rust programmer but I can't put my finger on why.
compi··on Snake game made in Go
Snake games are my go-to when I learn new languages, it's always under 1000 lines of code and can usually be done without libraries. In not a lot of time you can learn how the language:

    -   does timers
    -   does sleeping and/or threads
    -   handles user input
    -   gets some kind of output to screen
    -   provides basic data structures
    -   writes and loads files for high scores
There are a lot of things that I like about the original Snake that most people don't put into their hobby projects:

    -   There is a delay right before you hit the wall.
        If you are playing at the fastest speed and barrel towards the wall,
        it slows down to the slowest speed when you are on the final square
        before game over.
        I always loved this because the it made the most deadly obstacle the
        snake body which is the one that you yourself created.

    -   When it polled input it stored one of each press.
        If you pressed up then left, and the next tick the snake would turn
        up, and the next tick the snake would turn left.

    -   There are only four parts of the screen max that are updated each
        tick, the new snake head is drawn, the previous snake head is drawn as
        a body, the previous snake butt is cleared, and maybe a new egg is
        drawn.
        Very common to see a snake game draw the entire screen, or redraw the
        entire snake on each tick.  Super frustrating to have a game get start
        to stutter more and more as your snake gets longer.

    -   You could play using two buttons instead of four.
        The game could be played by using buttons 2=up 8=down 4=left 6=right.
        But it could also be played using buttons 1=up-or-left and
        9=down-or-right because you can only change from your current
        direction to two other directions since you can't have a button to go
        the opposite direction, and you don't need a button to go the same
        direction.
        It was never super intuitive though, a "right turn" or "left turn"
        button would make more sense.
The only critique I have for this is your snake almost doubles speed when you move up or down which is pretty jarring.
compi··on Some Obscure C Features
I was reading the source code for a NES assembler written in pre-C99 C, and there was an odd C feature used in it that I haven't really seen anywhere else.

It was before C had built-in booleans and the author had defined their own, but true was:

    void * true_ptr  = &true_ptr;
true_ptr is a pointer to itself. So however many times you deference it:

    printf("%p\n", true_ptr);
    printf("%p\n", &true_ptr);
    printf("%p\n", *((void**)true_ptr));
    printf("%p\n", *((void**)*((void**)true_ptr)));
You get the same pointer:

    0x5555fefe715b
    0x5555fefe715b
    0x5555fefe715b
    0x5555fefe715b
I still think that it's neat that, even with ASLR, you have an address at compile time that you know won't collide with address space of malloc results, or the address space of your stack.

Also you can declare the pointer as const and the value it points to as const and, if your kernel faults on writing to readonly memory pages, you get a buggier version of a NULL pointer that only segfaults on write.

Also it takes a second to figure out why the position of the const matters even though the pointer's value is the value of the pointer, and why only one of these segfaults on write:

    const void * const_pointer = &const_pointer;
    void * const const_value   = &const_value;