• 0 Posts
  • 93 Comments
Joined 2 years ago
cake
Cake day: September 2nd, 2023

help-circle
  • This can also be a side product for code blocks being expressions instead of statements.

    In rust for example they are, so it’s not rare to see functions like:

    fn add_one(x: i32) -> i32 {
        x+1
    }
    

    This lets you do amazing things like:

    let x = if y < 0.0 {
        0.0
    } else {
        y
    }
    

    which is the same as x = y < 0.0 ? 0.0 : y

    But is much better for more complex logic. So you can forget about chaining 3-4 ternary operations in a single line.


  • I’ve got all that. I just needed to convert a string of characters into a list of glyph IDs.

    For context, I’m doing a code editor.

    I don’t use harfbuzz for shaping or whatever, since I planned on rendering single lines of mono spaced text. I can do everything except string->glyphs conversion.

    Just trying to implement basic features such as ligatures is incredibly hard, since there’s almost no documentation. Therefore you can’t make assumptions that are necessary to take shortcuts and make optimizations. I don’t know if harfbuzz uses a source of documentation that I haven’t been able to find, or maybe they are just way smarter than me, or if fonts are made in a way that they work with harfbuzz instead of the other way around.

    As someone trying to have as little dependencies as possible, it is a struggle. But at the same time, harfbuzz saved me soo much time.

    EDIT: I don’t do my own glyph rasterization, but that’s because I haven’t gotten to it yet, so I do use a library. I don’t know if it’s going to be harder than string->glyphs, but I doubt so.


  • I cannot comprehend what the fuck harfbuzz does.

    I tried to implement my own because “I don’t need all the features, I’m gonna render self-to-right western text with very few font features”. But holly fuck, the font format documentation is barely non-existent. And when I tried my naive solution it was like 10000x (or more) slower than harfbuzz.





  • There are use cases. Like containers where the pointer to the object itself is the key (for example a set). But they are niche and should be implemented by the standard library anyway. One of the things I hate most about Java is .equals() on strings. 99.999% of times you compare strings, you want to compare the contents, yet there is a reserved operator to do the wrong comparison.




  • In C, goto is basically a necessity though. There is really no good way of error handling.

    Options:

    1. Using goto
    void func(void *var) {
        void * var2 = malloc();
        if var == Null {
            goto err;
        }
    
        do_something();
    
    err:
        free(var2);
    }
    
    1. Early returns:
    void func(void *var) {
        void * var2 = malloc();
        if var == Null {
            free(var2);
            return;
        }
    
        do_something();
    
        free(var2);
    }
    
    1. Skipping with conditionals:
    void func(void *var) {
        bool error = false;
        void * var2 = malloc();
        if var == Null {
            error = true;
        }
    
        if !error {
            do_domething()
        }
    
        free(var2);
    }
    
    1. Early return + cleanup function.
    void cleanup(void *var2) {
        free(var2);
    }
    
    void func(void *var) {
        void * var2 = malloc();
        if var == Null {
            cleanup(var2);
            return;
        }
    
        cleanup(var2);
    }
    

    Option 1 is really the only reasonable option for large enough codebases.

    Option 2 is bad because duplicate code means you might change the cleanup in one code path but not some other. Also duplicate code takes up too much valuable screen space.

    Option 3 has a runtime cost. It has double the amount of conditionals per error point. It also adds one level of indentation per error point.

    Option 4 is same as option 2 but you edit all error paths in one single place. However, this comes at the cost of having to write 2 functions instead of 1 for every function that can error. And you can still mess up and return while forgetting to call the cleanup function.

    You must also consider that erroring functions are contagious, just like async ones. I’d say most of the time a function is propagated upwards, with very few being handled just as it ocurrs. This means that whichever downside your option has, you’ll have to deal with it in the whole call stack.








  • I don’t know whatever that language is doing is called, but it’s not reference counting. It’s doing some kind of static code analysis, and then it falls back to reference counting.

    If you call that reference counting, what stops you from calling garbage collectors reference counting too? They certainly count references! Is the stack a reference count too? It keeps track of all the data in a stack frame, some of it might be references!


  • I don’t know what you read on my reply. But your reply makes no sense.

    Let me rephrase it if you prefer:

    Claiming that Rusty’s borrow checker is reference counting is hugely misleading. Since the borrow checker was made specifically to prevent the runtime cost of garbage collection and reference counting while still being safe.

    To anyone unaware, it may read as “rust uses reference counting to avoid reference counting, but they just call it borrow checking”. Which is objectively false, since rust’s solution doesn’t require counting references at runtime.

    I don’t know what mutable string or any of the other rant has to do with reference counting. Looks like you’re just looking to catch a “rust evangelist” in some kind of trap. Without even reading what I said.