Skip Navigation

InitialsDiceBearhttps://github.com/dicebear/dicebearhttps://creativecommons.org/publicdomain/zero/1.0/„Initials” (https://github.com/dicebear/dicebear) by „DiceBear”, licensed under „CC0 1.0” (https://creativecommons.org/publicdomain/zero/1.0/)C
Posts
0
Comments
522
Joined
3 yr. ago

  • functions

    Jump
  • 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.

  • An unhanded error will always result on a panic (or a halt I guess). You cannot continue the execution of the program without handling an error (remember, just ignoring it is a form of handling). You either handle the error and continue execution, or you don't and stop execution.

    A panic is very far from a segfault. In apparent result, it is the same. However, a panic is a controlled stopping of the program's execution. A segfault is a forced execution stop by the OS.

    But the OS can only know that it has to segfault if a program accesses memory outside its control.

    If the program accesses memory that it's under it's control, but is outside bounds, then the program will not stop the execution, and this is way worse.

    EDIT: As you said, it's also an important difference that a panic will just stop the thread, not the entire process.

  • Replace uncaught exception for unhanded error.

  • "unwrap should not exist" is true as long as you don't want to ever use the language. If you actually want to use it, you need it. At least while developing.

    Some values cannot have a default value. And some cases it's preferable to panic even if it has a default value.

    unwrap is not the problem. Cloudflare's usage is.

  • It's really hard to do without Rc (or similar) or unsafe.

  • 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've read a lot of people saying "oh what a horror, they used unwrap in production, they should NEVER do that". But I don't think that's true at all.

    1. The rust type system is not 100% flawless. For example you have a mathematically proven never-errors algorithm, but inside some steps have provisional Nones. At the end you just unwrap, since there's no point in changing the return type to an option to handle a non-existent error. You can't represent "this is None but I promise that it won't by the end" in rust's type system.
    2. Sometimes it's not worth handling the error. For example a simple CLI tool, just throw expects everywhere that shows why it failed, since most CLI tools just close anyway on failure, might as well panic.

    That being said, this was clearly a case where ? should have been used, since the function has a clear error case. And it also is a critical application that can't afford panicking as an error handling method.

    EDIT: Just to clarify, the way you would do this is by having a type Features that can error on creation/parsing which has a limit of 200 entries. And afterwards you can just use that type knowing that it will always have <= 200 entries. And you gracefully handle that one error case on creation/parsing.

    EDIT2: Another point for why I disagree with "production should never have unwrap":

    1. Unwrap is basically the same as assert(my_variable.is_some). I don't know a single person that would say "you should never have asserts in production code", the only reason I disable some assertions for release builds is for performance. Asserts are statements that should never do anything, by that logic they pose no harm by being there, so no need to remove them, their only effect should be wasting a few CPU cycles. Since asserts are only put when the programmer assures that a certain precondition will always be met. And if it is not, it's because the code changes and automatic tests should catch that.
  • 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.

  • Based on the responses (i haven't watch the video), hu just revered according to Unicode codepoints (chars). Therefore this should do the same.

    Of course chars() hides the complexity, that's what makes it easy.

  • In fact it is easy in rust. Might not be the most performance (or maybe it is), but you should be able to do just "my_str".chars().rev().collect::

    <String>

    ()

  • The problem with static mut is that it allows you to create multiple mutable references. And also mix mutable and immutable references. Additionally, it is accessible by any thread. So, as long as you don't do any of that, it should be safe. Maybe I'm missing something.

    If this is the entire program, it's not unsafe. But if it is just a fraction of the program, it may be unsafe. For example if 2 threads call the function at the same time. Since you would have 2 mutable references to BUF. Well, not actually unsafe since you don't use the mutable reference, only create it.

    As to the other question, static variables are not in the stack. They have their own region of memory. If they were in the stack, they couldn't be accessed across threads, since each thread has its own stack.

    EDIT: for completeness sake. For your last question. Yes, using a static buffer is probably more performant, since it doesn't need to be set to 0 each time it's called. However, that's not what statics are for. If what you want is just to avoid that setting to 0, there are ways to get initialized arrays. For example MybeUninit. Which would be way better.

  • Formal and informal is not the same in plural.

    "Ustedes" is formal, "vosotros" is informal. Although Mexicans (and many other south Americans) don't use the informal version, it doesn't mean that it doesn't exist.

    Some countries also say "vos" for singular. I don't know if that replaces "tú" or "usted" though.

  • This is the dram. Since the entire codebase is shit, you basically have to rewrite it basically in its entirety.

    Which means you can do it with an actual good design.

    And if you mess up on something, you have a working version you can consult.

  • It's not minor, but commuting. If every job that could be done from home was always done from home, those people would save 100% of their commuting time. They would also leave room so the ones that have to commute can go faster (in case of road) or enjoy more space (in case of rail).

  • It's not one thing or the other.

    For example I often end up using event loops. Where an event is a tagged union. Some events take up 1 byte, some 400. It's almost effortless to put the big variants in the heap, and just keep a pointer in the union. So why not do it from the start.

    Sure, optimizing every loop to make it vectorizable is probably not worth it, since that loop you wrote on the 10th commit might not even exist when the software is released. But there are many low hanging fruit.

    Also, some optimizations require a very specific software architecture. Turning all your arrays of structs into structs of arrays may be a pain if you didn't plan for making that switch.

  • If what you want is low level, I recommend wgpu. And you can go even lower level of you go for wgpu-core instead.

    However, when you go this low level, making a game is not the objective, since it would be incredibly tedious compared to using an actual game engine. I had a lot of fun doing small things with wgpu though. Learned a lot too.

  • In my opinion, this question makes no sense so it belongs nowhere.

    But for it to be on topic, it would need to go in a general technology or OS community.

  • Data storage devices are the last items you wanna buy second hand though. A drive failing could mean much more than just having to buy a new one.

  • I hope this is satire. But I can't be certain if it is.