• 0 Posts
  • 179 Comments
Joined 2 years ago
cake
Cake day: June 17th, 2023

help-circle
  • nous@programming.devtoRust@programming.devstruct in Rust
    link
    fedilink
    English
    arrow-up
    6
    ·
    1 day ago

    Structs are the AND data type in rust (ie it contains all the fields defined). As opposed to Enums which are the OR type (which can only be one of the variants defined). You also have ananomous data types like tuples or arrays.

    The point about methods applies to any type in rust, structs are not unique or special there. Rust does not revolve around the struct type like other languages revolve around the class type.




  • Coloured text does not require a dep. It is just about printing the right colour codes like:

    const BLACK: &'static str = "\u{001b}[30m";
    const RED: &'static str = "\u{001b}[31m";
    const GREEN: &'static str = "\u{001b}[32m";
    const YELLOW: &'static str = "\u{001b}[33m";
    const BLUE: &'static str = "\u{001b}[34m";
    const MAGENTA: &'static str = "\u{001b}[35m";
    const CYAN: &'static str = "\u{001b}[36m";
    const WHITE: &'static str = "\u{001b}[37m";
    const CLEAR: &'static str = "\u{001b}[0m";
    
    fn main() {
        println!("{RED}red! {BLUE}blue!{CLEAR}");
    }
    

    The libraries just make it easier so you don’t need to remember or know what those codes mean.


  • Declare input in the loop. That limits scope which is basically always a good idea.

    There is good reason to not do this. Though in this case it won’t make much difference as performance is not an issue. But by having it outside the loop it allows the allocation of the string to be reused and in more complex programs is typically what you would want to do - allocate once outside the loop and reuse that inside.

    In this case waiting on user input is going to outweigh any performance benefit I would not call it out as bad practice either.


  • The biggest/only real problem is the .unwrap(). This will cause the program to exit with an error message if the user inputs an invalid value. Which is not a great user experience. Better to reject the input and ask them again (aka start the loop again). You can do this with a match on the returned value of parse with a message and a continue on Err (good time to learn about enums and pattern matching as well).

    A minor improvement can be done to this:

            input = input.to_string().replace("\n", ""); // removing the \n
            let user_input: u32 = input.parse::<u32>().unwrap();
    

    By replacing it with:

            let user_input: u32 = input.trim().parse::<u32>().unwrap();
    

    Which has a few advantages:

    • it removes all white space, including tabs and spaces from both the start and end.
    • it requires no allocations.
    • it is one fewer lines while still being clear what it is doing.
    • no mutability needed (though input still needs to be mutable here in other cases this can be a benefit).

    These are more nitpicks than anything substantial - would lead to nicer code in more complex situations but negligible at best in this code base (only really pointing out to give you some things to think about):

    Since you break in the win condition the attempts += 1; can be moved out of the other branches at the same level as the input.clear().

    Rand has a gen_range function which can be used like:

    rand::thread_rng().gen_range::<u32>(0..=100);
    

    Though typically you would save the thread_rng() output to a local and reuse that throughout your program instead of creating one each time - here you only need one number so that matters less. The Rng trait has a lot more convenience function on it as well so it is generally worth using over just the random() function. Though in this case it makes very little difference overall here - typically you would want to opt for one of those methods instead so is worth knowing about.

    I dislike the name x as it is very ambiguous. IMO short letters should be used only in smaller scopes or when they represent some sort of mathematical value. Here I would use secret_number or secret_value or something more descriptive. Though in this case there is not a much better domain name here, more often there is.




  • But is Rust merely a new face on Ada?

    They share some features. But what language does not share any features with any other language? Any new language these days will be heavily inspired by and take features from other languages while making changes to or pulling in features from other places to create a mix that is unique to that new language. Rust is far more than just its GCless memory safety features and I am not even sure if they are inspired by ada or were just arrived at a similar solution to ada - they are not exactly a one to one matching with how ada does anything. If anything I believe that rust is much more heavily inspired by ocaml than ada.



  • But it applies to features, not coding practices

    I disagree. It applies to everything. I would argue it applies to SOLID most of all. I do not find SOLID principals to be good ones to follow most of the time. Situational they can be useful but I have seen so many projects that strictly follow SOLID that becomes an unmaintainable mess.

    If you struggle to understand the SOLID principles or think they are too general, then I would suggest you follow my SOLID Training Wheels until you understand them better.

    I hate this excuse. If the answer to the problem is you are just not doing it right then it is a terrible answer. But lets look at some of this advice:

    Summary: 1 piece of code has 1 responsibility. The inverse: 1 responsibility of code has 1 piece of code

    Training Wheels:
    Follow the 10/100 Principle
    Do not write methods over 10 lines
    Do not write classes over 100 lines

    No. Just no. Making everything as small as possible is exactly what is wrong with the single responsibility principal. I agree that everything should have one responsibility, but that responsibility might be complex and require a lot of code. Hiding the code behind other functions does not make it easier to read, only means you need to jump around a lot in order to understand what it is doing which IMO makes things harder to read. Every time I jump location it gets harder to remember where you came from or what the wider context is. Keeping related code together is more important then creating small function.

    Just take a look at the stdlib of almost any mainstream language. Like the ArrayList in Java, or Vec in rust. These classes are thousands of lines long with many methods being 10-20 lines of code with some even longer then that. Is this code bad or hard to read? Not for what it is doing. And code like this is not atypical in stdlibs, you can jump to almost any class/struct in a language of your choice and see similarly structured code. And in all cases the classes represent one thing and its methods do one thing on that object regardless of how many lines of code they contain.

    If you have to change a class that already breaks the 10/100 Principle:
    take your code out of that class and put it in a new class first so the original class is smaller
    Check-in this refactor without your new code
    make your changes in the new class
    Check-in your new code

    IMO this breaks the single responsibility rule. If new code is mostly related to a single class then it should be added to that class as that is what the class is responsible for. Adding a new class for every bit of logic just splits up the responsibility and makes it far harder to find what is responsible for something.

    I could go on about the rest of that training guide - which this whole post seems to be an advert for.

    YAGNI, will ruin your code base if you apply it to how you code.

    It applies just as much to how you code as to what you are coding. If you added every programming paradigm and principal to your code base it would be a unreadable mess. Not to mention impossible to do as loads of these conflict with each other.

    Pick the right tools for the right job. Don’t blindly apply anything to every situation. There are times when the SOLID principals can help but there are also times where they make code worst. Instead always ask yourself if there is a simpler way you could be doing something and if when applying a principal if it actually made the code easier to read (ask someone else as well as it can be hard to tell yourself). Don’t be afraid to break a principal if it is not helping.





  • Transactions should be short lived, they block data on the database side from acessing those tables or rows. Best to not jole onto a transaction that long and instead gather your data first or rethink your access patterns to your data base.

    But arc does give you a try_unwrap which returns the inner type if there is only one strong copy left. And mutex gives you an into_inner to move out of it. But really transactions should not be held for a long period of time.



  • Of these 25 reasons, most apply to a lot of languages and are far from Java exclusive or even java strong points. Pick any mainstream language and you will hit most of the benefits it lists here. With quite a few being almost meaningless. Like this:

    Java/JVM/JIT can achieve runtime optimization on frequently run code, especially on something that’s running as a service so that you avoid the overheads from JVM startup times.

    Compiled languages generally don’t need a JIT or to be optimized at runtime as they are compiled and optimized at compile time. And most language that don’t have a runtime like Javas already run faster than Java without its heavy startup time. Language with JITs are generally interpreted languages which have these same benefits as java lists here. Though do often suffer from other performance issues. But really at the end of the day all that really matters is how fast the language is and how good its startup times are. Java is not ahead of the pack in either of these regards and does not do significantly better then other languages in its same class (and often still drastically sucks for startup time).

    Or

    Much of a company’s framework can be stable Java, with Scala or Clojure-backed business logic.

    Many languages you can embed other languages inside. Nothing really special about scala or clojure here except that they work well with java. And I don’t really see this as a major benefit as most places I see dont separate their core code and business logic into different languages.

    And the remaining issues that are more java specific are:

    Java was one of the first mainstream GC strongly typed OOP languages. So it got its niche.

    Java has been one of the main programming languages taught in colleges and universities in the last few decades.

    Java’s Legacy Migration: Many banks in particular migrated legacy systems to Java in the early 2000’s when it was getting a lot of popularity and the industry was collectively in the midst of a huge OOP fever dream.

    Which all paint a picture - it was popular long ago and taught in universities and lots of business pushed it when back in the day. And now it is hard to move off it.

    And lastly:

    Oracle

    What? How is this a point? If anything this should be a massive negative.

    Not exactly 25 reasons to pick java in financial enterprise.


  • Did you read the article at all?

    “Putting all new code aside, fortunately, neither this document nor the U.S. government is calling for an immediate migration from C/C++ to Rust — as but one example,” he said. “CISA’s Secure by Design document recognizes that software maintainers simply cannot migrate their code bases en masse like that.”

    Companies have until January 1, 2026, to create memory safety roadmaps.

    All they are asking for by that date is a roadmap for dealing with memory safety issues, not rewrite everything.



  • You could do a lot of things. Rust had a gc and it was removed so they have already explored this area and are very unlikely to do so again unless there is a big need for it that libraries cannot solve. Which I have not seen anyone that actually uses the language a lot see the need for.

    Not like how async was talked about - that required a lot if discussion and tests in libraries before it was added to the language. GC does not have anywhere near as many people pushing for it, the only noise I see is people on the outside thinking it would be nice with no details on how it might work in the language.