Rust Does Interfaces BETTER!

Поделиться
HTML-код
  • Опубликовано: 28 янв 2025

Комментарии • 123

  • @solarshado
    @solarshado Год назад +48

    Every now and then, the youtube algorithm turns up a gem. Solid video, dude!

    • @CataBits
      @CataBits  Год назад +1

      Thank you so much! Let me know if you'd like to see a certain topic!

    • @Barnardrab
      @Barnardrab 6 месяцев назад +1

      Agreed. I subscribed after the 2nd video. I'm a Java junkie, but have felt limited by its features.
      I'll have to get used to how ugly Rust's syntax is. But the actual features of Rust is what matters and this looks promising.
      Java got me into object oriented programming, so I'll appreciate having the aforementioned object oriented features.

  • @programming8339
    @programming8339 Год назад +8

    Great video and explanations! So much knowledge baked into a 10 min video! I also code primarily in Java, so this kind of videos are exceptionally interesting to me!

    • @CataBits
      @CataBits  Год назад +1

      Thank you for the very kind words! Really glad you found it informative :)

  • @91rene91
    @91rene91 Год назад +2

    For being one of your first videos this is pretty good. You seem to be talented. Wish you all the best for your channel!

    • @CataBits
      @CataBits  Год назад

      Thank you for the kind words and encouragement!

  • @patrickwoolard4340
    @patrickwoolard4340 Год назад

    Hey I liked the video, but at around 4 minutes in (4:00) when you define the impl for the Iterator trait, I think there might be a typo (there's a ; where a { should be). shouldn't it be:
    fn next(&mut self) -> Option{ // instead of a ;
    Some(Thing {...})
    }
    Not a huge deal of course, but since I am trying to learn Rust I was scratching my head for a bit wondering if Rust just has some weird syntax when defining interface implementations 😅

    • @CataBits
      @CataBits  Год назад +1

      Darn, very sorry about that - thanks for pointing it out, I'll add it to the errata comment. Ill also have to update the blog post for this. Sometimes I make quick edits to my notes without checking if the code still compiles.
      I'll be a lot more careful for upcoming videos. The next one is going to go into more detail about associated types and blanket implementations, with more complex examples.
      Thanks for watching - hope you have fun learning Rust!

  • @CottidaeSEA
    @CottidaeSEA Год назад +5

    Something that would've made this video better for me would be slightly less pausing during speech. On one hand it's very clear and proper, but I would've been able to pay attention more easily if the speech flowed better through shorter pauses.
    It's fine to take longer pauses, but it felt a bit too frequent. Long pauses are more effective when used sparsely.
    Good video though, a nice showcase.

    • @CataBits
      @CataBits  Год назад +4

      Thanks for the feedback! Yes, I want to have more inflexion in my delivery and reduce wait times for upcoming videos.

    • @CottidaeSEA
      @CottidaeSEA Год назад +2

      @@CataBits Keep up the good work, looking forward to the next video!

  • @pepperplume
    @pepperplume Год назад +1

    2:31 would it be possible in java to create a sub class for an external class, and have that sub class implement the target interface? i think thats a work-around to have an object in an external library implement an interface, kind of like a decorator. this, however, is gross af and it looks much muuuch nicer to do in rust

    • @CataBits
      @CataBits  Год назад +2

      Yes, you can - people usually refer to this as the adapter pattern. Java, with being so ubiquitous, but this in itself indicates that the design is not optimal in all regards.

    • @pepperplume
      @pepperplume Год назад

      @@CataBits yes, i agree, my solution is still gross, and just because its possible in a language doesnt mean its clean, or easy to understand, especially since theres an entire design pattern around this problem. thats a good take away, maybe language specific design pattern syntax implementation is better?

  • @CataBits
    @CataBits  Год назад +6

    If you want to the contents of the video in text form, here's the corresponding article:
    catalin-tech.com/traits-vs-interfaces/
    Errata:
    This is mostly a showcase of the basic syntax features that I think Rust does better around interfaces. At the start, the video is framed as a straight-up comparison, which it isn't for the most part - aspects of how Java tackles the limitations of its basic syntax around this are not covered.
    As mentioned by @tauraamui, the Intro slide mentions that in Rust, data is decoupled from behavior while this is not the case in Java - this is incorrect, as most idiomatic Rust has a lot of methods associated to structs. The methods are not defined in the struct itself, but they are still paired / coupled with the struct.
    At around 4:00 the code should be:
    fn next(&mut self) -> Option{ // instead of ";"
    Some(Thing {...})
    }
    (the semicolon needs to be replaced with an opening curly brace)

  • @charliesumorok6765
    @charliesumorok6765 Год назад

    8:28 Does Java's or Rust's approach require more instructions on the JVM?

    • @CataBits
      @CataBits  Год назад +1

      Rust can't run in the JVM. (You can run Rust compiled to WebAssembly in certain implementations of the Java runtime - but this is uncommon). Rust is compiled to CPU instructions. The JVM would run more CPU instructions when executing than Rust would use even for dynamic dispatch.

    • @charliesumorok6765
      @charliesumorok6765 Год назад

      @@CataBits It can using LLJVM.

    • @CataBits
      @CataBits  Год назад

      @@charliesumorok6765 Thanks for sharing! are there any seriously maintained projects doing this? The libraries I found for this haven't been maintained in over 8 years.
      Seems like you have to compile Rust to LLVM intermediate representation and then link to the Java classes before Java compilation.
      Seems like something fun to try out, but doesn't look like anything that would be used in prod. I think using JNI to call into the binary, or a JVM that supports WASM might be a more likely approach.

    • @charliesumorok6765
      @charliesumorok6765 Год назад

      @@CataBits JNI and WASM are more likely if they are avaliable.
      JNI requires the processor to be able to load code from multiple sources.
      WASM, if not implemented using JNI, requires the JVM to know how to run WASM, or for the program to have a WASM emulator in the code, which would be inefficient.

    • @CataBits
      @CataBits  Год назад

      @@charliesumorok6765 Good points! From looking at the GraalVM project, it seems like WASM is more popular in this regard.
      Indeed, this approach is less performant, but it seems to be around the speed of Java code (also being JIT-compiled), so it should be acceptable to solutions running on the JVM (unless the module was created specifically to treat a bottleneck in performance)

  • @bernardcrnkovic3769
    @bernardcrnkovic3769 Год назад +2

    most of the points here can be disputed:
    - java does not force you to program in OOP way, sure you can, it was intended to, but coding in FP style is not as "ugly" as some may think
    - java also allows "derive(Eq)" annotations on objects using comptime libs, same number of lines of code
    - for the life of me, i cannot think of benefit of "impl Trait for SomeStruct {}" over "class MySubClass extends SomeStruct implements Trait"
    - function signature can also immediately tell you what is mutated and what is not in java:
    doStuff(Map m);
    vs
    doStuff(ImmutableMap m);
    also, if you REALLY want to know whether method modifies state of its own object (which you don't actually need to know if you didn't implement the class), why not annotate with some docstring? every modern editor will show you hints
    agreeable points:
    - method dispatching is fair point. obviously, rust is faster language, no debate about it but from the perspective of a developer doesn't affect ergonomics of coding

    • @CataBits
      @CataBits  Год назад +1

      Thanks for watching!
      I don't think your points about derive and mutability are fair.
      For derive - I think you're confusing the term of "compile-time" for libraries - this just means that the the code in libraries is checked for compatibility with the one in the codebase. The Java compiler cannot generate code at compile time. You can use different programs to do this, but this is discouraged. You can get automatic implementations in Java, but this is done using reflection at run time. I also have not seen this being done in my professional experience. The libraries I found for this seem quite obscure, plus the implementations are merely placeholders, while Rust can infer a lot more coherent logic for the implementation (because it applies for std library types). Can you recommend such a library that you saw in use?
      Regarding mutability - it's not the same, you would have to use a special wrapper, or a collections library (as in your example). When you don't use the special collection / wrapper it's not clear why (is this just an omission, or should the element be mutable?). In Rust, it's built into the basic syntax, and the compiler also warns me when I make something mutable that doesn't need to be. In Java, I have to remember to use a special primitive, and if I don't use it, it's not easily visible why.
      About your point on using a docstring to mark mutability - I always want mutability to be clear. I work with enterprise and legacy software and when I go through a 10-method call stack I don't want to start investigating and guessing where the value can be modified. Also, the annotations, wrappers, and special primitives are all stuff I have to remember to do - when in Rust I just get this for free. Moreover, the docstring is not understood by the compiler, so it will not enforce it in other places to warn me of logic errors - I would have to remember to change it if the logic changes.
      For the uses of the Impl block, it allows you to reduce boilerplate, and better organize code. For example, at work, we have hundreds of classes generated by an external tool, which cannot be modified. If I want to implement an interface for them, I have to write hundreds of wrapper classes. In Rust, I can just write the Impl blocks in one place in the module where the implementation is necessary, without having to add a couple of hundred classes to my project. I can also make this more condensed by writing a macro that generates the Impl{} blocks.
      You can totally get what you want without it in Java, but it's just more of a chore and comes with more boilerplate.

    • @CataBits
      @CataBits  Год назад +1

      For dispatch, the fact that Java defaults to dynamic dispatch, makes it better ergonomically ( you don't have to think about dispatch at all in terms of syntax ). In Rust, you have to think about using trait objects, though this comes with a level of visibility.
      Visibility on this part is not much of a problem in Java, since few cases use static dispatch, and it's easy to determine what they are if you need to.
      The part that is more ergonomic in Rust is the mutability info in the signature - this applies to normal methods and functions (not just the ones in traits).

    • @bernardcrnkovic3769
      @bernardcrnkovic3769 Год назад

      @@CataBits
      1. absolutely, example of such library is Immutables and AutoValue but i prefer Immutables, it is the only one I've seen it done fully correctly. It is APT so it is "build time" rather than "compile time". We can argue terminology but it processes source files and generates appropriate sourcefiles. The final outcome is the same.
      It is certainly not discouraged. Why would codegen be discouraged if you don't modify generated sources? What you may have seen is the discouragement of Lombok, which I agree with because it internally uses wrong approach. Immutables does it right.
      2. Rust have a slight edge in ergonomics here because:
      - passing Collections.unmodifiableMap(m) to function that might try to mutate it would be runtime error instead of compile time.
      - immutable is default in rust which, if you use immutable libraries is also not a big issue for java, but having immutable as default is certainly better, i agree
      But "having to remember to use special wrapper/primitive", I could argue the same for "having to remember to not place mut...". Feels kinda strawman. Also, "going through 10 layer call stack trace" is trivial if you pass immutable wrapper. you will immediately have logged error WHERE exactly IF it was attempted to be modified.
      The only benefit, again, is compile time. But you should still write unit tests so you'd catch that in Java too.
      3. I'd really like to see use case of writing hundreds of impl blocks instead of one (max few) "extension" to base impl. If you have related behavior scattered around in other files you have low cohesion which is universally agreed upon to be a bad design.
      4. lack of metaprogramming is exact reason for Javas maintainability and popularity. I don't have to learn a new pseudo-language DSL in every new codebase I see. This might be personal preference though, so I won't argue about whether or not you should use metaprogramming, but I've never seen DSL that is any better than fluent builder pattern.
      also, writing, maintaining and extending DSL's is a pain but you do you.

    • @bernardcrnkovic3769
      @bernardcrnkovic3769 Год назад

      also, forgot to mention, extending stuff is terrible, just add proxy adapter for modifying desired behavior and then you can stack wrappers around implementations. i, too, hate OOP from the bottom of my heart :)

    • @CataBits
      @CataBits  Год назад +1

      @@bernardcrnkovic3769 Good points. In greenfield projects it's easier to put good practices in place, and you have good ways of doing this in Java. Sadly, that's not the code that I have to work with. The vast majority of it doesn't use immutable primitives, and state gets passed around willy-nilly. I'd say it's easier to not put "mut" everywhere in Rust than it is to import or write special primitives. Also, what about primitives or simpler objects - does everything get a wrapper? In Rust, you can't really put mut everywhere, as it will force you into borrowing patterns (exchanging ownership will be annoying), which will restrict the usage of the mutable modifier for multiple references.
      For point 4, to do what I proposed, you don't need a DSL - you can use the standard declarative macro syntax. The macro call would just look like a basic function call for the most part.
      The critical point here is that Rust can enforce mutability on the level of variable bindings (even in function params), while the library you proposed just allows the creation of immutable objects. This will not get you the same level of safety as Rust.
      I think that immutable bindings by default changes the way one thinks about code - I don't think this is as trivial as you're making it out to be. If you tell people to make doctor's appointments, they won't, but if you make one by default for them and ask them to cancel if they don't want to attend - they'll end up having an appointment when otherwise they wouldn't have. In Rust the no-effort default is safe, while in Java, you need to expend effort to get to a sane, controllable place (getting a library, and remembering to use it). Let's not forget that this does nothing about the bindings, so you can still mess up a variable value by giving it a new invalid immutable value.

  • @Dywanoid
    @Dywanoid Год назад +3

    Nice video man! Sometimes we have to hear it from the other person to really understand some things. You made me realize why I like trait system so much in Rust!
    As some people mentioned - if you'll work on your speaking you'll do great on RUclips!

    • @CataBits
      @CataBits  Год назад +1

      Thank you for the kind words and the suggestion! Yes, I plan to focus on that.
      And yes, sometimes hearing something from another can trigger something clicking into place.
      Take care!

  • @ikhlasulkamal5245
    @ikhlasulkamal5245 Год назад +1

    Nice video, you have a clear explanation and a clear voice. it is perfect for non native english like me

    • @CataBits
      @CataBits  Год назад

      Glad it was useful! Thanks for letting me know - helps me make decisions for later videos.

  • @ibrahimkoz1983
    @ibrahimkoz1983 Год назад

    C# and Kotlin have extension functions that allow you to superimpose a functionality over libraries you don't own. Likewise, type Item can be easily implemented via generics.

    • @CataBits
      @CataBits  Год назад +3

      For your point about generics - Yes, but it's not the same thing in terms of API design.
      An associated type has a grouping effect - the implementor can choose what it is, but it can only be one. If I would have it as a generic param for the trait, the user can write N different implementations for the trait - and there are cases where that is not desired. The associated type allows me to restrict what the implementor does.
      Yes, you can always use a generic type instead, but that, in some cases, might let implementors use the API in ways that don't make sense.
      I didn't really make this clear in the video, sadly.

    • @ibrahimkoz1983
      @ibrahimkoz1983 Год назад

      @@CataBits You can restrict genetic type of course. Interface, for e.g.

    • @CataBits
      @CataBits  Год назад +2

      @@ibrahimkoz1983 Again, it's not the same thing - I can write tens of different implementations if I want with subclasses of Vehicle. With an associated type, it allows exactly ONE possible implementation. Like for the Iterator trait - there is only one valid return type for the generic class of the trait. If I put the return type as a generic param, I could then write N possible implementations for each generic class.
      If I have Iterator - there is only one valid type that the iterator should return for T - If I turn it into Iterator, with R being the return type, the user can write multiple Iterator implementations for an input type T, which we don't want as an API designer.

    • @alexleung842
      @alexleung842 Год назад

      @@CataBits feels like there's enough nuance here to warrant its own video. I'd watch it!

    • @CataBits
      @CataBits  Год назад

      @@alexleung842 Thanks for the input - the upcoming video covers associated types, and their impact on trait bounds. It's not just about associated types - but they'll get good coverage.

  • @zyklos229
    @zyklos229 Год назад

    Not sure, what's the thing. Doing Kotlin instead Java - which is 100% interoperable has also extensions and multiple stuff in 1 file.
    From "clean code" point of view, not sure if traits instead interfaces make code easier to understand at all. At least you'd have to rethink the gang-of-four patterns, otherwise it just introduces randomness ("hey look at my crazy code tricks to scramble the meaning")

    • @CataBits
      @CataBits  Год назад +2

      I'm not going into a Kotlin vs Java debate.
      About the idea of clean code - I think you're taking it dogmatically. You can write all the patterns in the gang of four book in Rust - just that you can replace some of these with language feature in some cases. And this is not unique to Rust. Some Java features such as lambdas make some patterns in the book unnecessary.
      The book was written to document how people got around limitations of OO languages at the time it was written. The book is not a prescription on how to write "clean code". The patterns are solutions to specific problems and not principles of organizing code.
      Thinking that language features are bad because they make the explicit use of design patterns obsolete is putting the cart in front of the horse. The patterns are a toolbox, not a set of universal principles for code.

  • @brunoais
    @brunoais Год назад

    Thank you. Great explanation!
    However, @ 5:30, that is wrong. Java has static methods which is the exact equivalent of that. Instead of being specified in the argument, whether or not it can use the self/this, can be seen in by looking at the "static" keyword in the signature.

    • @CataBits
      @CataBits  Год назад +1

      Thank you! Yes, you're right on that. Rust still offers the extra info on mutability though.

    • @brunoais
      @brunoais Год назад

      @@CataBits True but in java you can always specify it cannot be mutated using the final keyword (rarely used)

    • @brunoais
      @brunoais Год назад

      And then you will come to me that rust's mut isn't just for the variable itself.... And Rust wins there 😀

    • @CataBits
      @CataBits  Год назад +1

      @@brunoais You can put "final" in method signatures, but it will just stop you from changing the reference with another. You could still mutate stuff through the reference you have. (I don't think I've seen it in signatures ever :D) It's also not clear in the calling code.

    • @brunoais
      @brunoais Год назад

      @@CataBits true

  • @friendliness1337
    @friendliness1337 Год назад

    This was a really cool video! Helped some things 'click' in my mind finally which for some reason they never fully did. Thanks and keep up the good work! ^^

    • @CataBits
      @CataBits  Год назад +1

      Glad it was useful! Thanks for the encouragement!

  • @tauraamui
    @tauraamui Год назад +1

    Methods on a struct is coupling logic with data, what do you mean it's uncoupled in Rust?

    • @lukaszoblak
      @lukaszoblak Год назад

      You technically cant create a function not belonging to any class in Java

    • @tauraamui
      @tauraamui Год назад

      @@lukaszoblak But you can have static methods on a non data type class to which you can pass other instances to. Rust and Go both support methods, which is coupling logic with data by definition. The only language which actually can claim to actively enforce decoupling is Odin or functional languages.

    • @CataBits
      @CataBits  Год назад

      I never said that in the video - though Rust lets you write decoupled code in this manner if you wish, but doesn't enforce it ( you can use methods, but you don't have to).
      I said that the data-types , traits (interfaces) and implementations are not tied together location-wise in the syntax. In Java, the method implementations are in the class itself, while in Rust, they are in the Impl {} block, which can be anywhere. The difference might seem trivial at first, but in Rust I can provide an implementation for an external type directly, while in Java, I would have to use something like the adapter pattern for this, adding a lot of boilerplate.

    • @tauraamui
      @tauraamui Год назад

      @@CataBits In your bullet point list you just said that they're not coupled as they are in Java but at that point you didn't make it clear what you meant by uncoupled. The impact of having logic tangibly linked to your functionality is greater than having that link expressed over multiple files. It is a shame that Java has enforced OOP in the way that it does, but most people's usage of Rust of defining methods on their "traits"/interface types is not somehow different. You can't say that being able to do header style define in one file and implementation in another file somehow makes the coupling of the logic and data looser, or less significant from a "tangible" point of view. Idiomatic Rust and Java tie logic and data together in the same way, just because you don't have to couple them doesn't mean that they are not when you do that.

    • @tauraamui
      @tauraamui Год назад

      @@CataBits In Go and I assume in Java external types can be provided by just providing any type which stratifies the required interface to be passed, sounds similar to Rust, but less magical.

  • @mskiptr
    @mskiptr Год назад

    Hi, what's the font at 0:01?

    • @CataBits
      @CataBits  Год назад

      Hi, it's JetBrains Mono throughout the whole video. Might look bigger different in the intro due to increased font weight.

    • @mskiptr
      @mskiptr Год назад

      @@CataBits Thanks!

  • @dixztube
    @dixztube Год назад

    I always got interfaces and methods mixed up

  • @YYYValentine
    @YYYValentine Год назад +1

    Sometimes I hear people complaining about Rust's lack of inheritance, and I am not understand why. If I want to give common fields , I just create an other struct (which woud be a base class in oop), and refer it in a field of the other structs, thus having common data in multiple struct. Something similar like composition, I think. Am I missing something? (I am a noobie)

    • @CataBits
      @CataBits  Год назад +2

      I don't think you are. "Composition over Inheritance" is a fairly well-known principle at this point. Extension might help in some edge cases - but enabling the feature in a language just seems to encourage a lot of misuse.

    • @heruhday
      @heruhday Год назад +1

      Rust has trait inheritance..

    • @CataBits
      @CataBits  Год назад +2

      @@heruhday It's different from OOP inheritance - Supertraits are a way of describing that a trait has another as a requirement (dependency). If B is a supertrait of A, it just means that implementing B requires A to be implemented. B does not gain the functionality of A automatically as in OOP inheritance.

    • @heruhday
      @heruhday Год назад

      @@CataBits so what is oop definition? Its still bias..
      According The book Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (Addison-Wesley Professional, 1994), colloquially referred to as The Gang of Four book, is a catalog of object-oriented design patterns. It defines OOP this way:
      Object-oriented programs are made up of objects. An object packages both data and the procedures that operate on that data. The procedures are typically called methods or operations.
      Using this definition, Rust is object-oriented: structs and enums have data, and impl blocks provide methods on structs and enums. Even though structs and enums with methods aren’t called objects, they provide the same functionality, according to the Gang of Four’s definition of objects.

    • @heruhday
      @heruhday Год назад +1

      @@CataBits
      Another aspect commonly associated with OOP is the idea of encapsulation, which means that the implementation details of an object aren’t accessible to code using that object. Therefore, the only way to interact with an object is through its public API; code using the object shouldn’t be able to reach into the object’s internals and change data or behavior directly. This enables the programmer to change and refactor an object’s internals without needing to change the code that uses the object.

  • @anuragdhadse1426
    @anuragdhadse1426 Год назад

    Is there a tool that you use for creating these slides?🤔 Will be really helpful for college grads.

    • @CataBits
      @CataBits  Год назад +1

      I used motioncanvas.io/
      There's also:
      -Manim if you like using Python
      -Remotion if you want to use React
      -Animotion if you know JS animation libraries and just want to plug those in (this project is new and fairly bare-bones).

  • @JaLikon65
    @JaLikon65 Год назад

    This was a great video! It really helped me crystallize some things in my head. Thank you for making it, subscribed :)

    • @CataBits
      @CataBits  Год назад

      Awesome! Thanks for subscribing! I'm working on improving the format and the delivery.

  • @gusvanwes6192
    @gusvanwes6192 Год назад +4

    Good video but could be a bit faster paced. Just cutting a bit of the dead air.

    • @CataBits
      @CataBits  Год назад +3

      Thanks for the feedback. Yes, I'll do it for the upcoming videos. The delivery is a bit slow, and there are a number of unnecessary wait times. I think I was afraid of rushing through the video and I over-corrected.

  • @kamertonaudiophileplayer847
    @kamertonaudiophileplayer847 Год назад

    Indeed, it's a good illustration of a power of traits in Rust.

  • @torarinvik4920
    @torarinvik4920 Год назад

    Swift Protocols are somewhat the same. But they are dynamic by default but can be used statically. So opposite of Rust. Parameters in Swift are immutable by default, a function must be marked with mut to mutate arguments. Swift is sort of like a more productive, nicer and easier to use version of Rust. Since Swift has automatic memory management it doesn't need all the safety features that Rust needs. It gives around 70% of the performance of Rust, but if maximum performance is needed then Rust is a sure winner. Biggest problem with Swift is it's poor portability. Programming on Mac is amazing, but on any other system is incredibly painful. It could be a good contender to compete with Go if it wasn't for the portability issue.

    • @CataBits
      @CataBits  Год назад +2

      Hi! I very much like Swift - it shares a lot of DNA with Rust (probably because of Graydon Hoare's contributions, maybe). To me it's not general-purpose enough (the tooling more than the language design itself) to use it regularly.
      I would push back on the idea that Rust is not productive - it isn't while you're learning, but after the longer learning period, I'm mostly as productive in it as I am in other languages (the recent Google survey on Rust mirrored this sentiment). I do spend more time on the design, but this leads to less time spent on fixing issues later.
      I get what you're saying - Swift is a lot easier to pick up, and it comes with great features. You can be productive a lot sooner.
      I find that the ownership model in Rust not only covers memory management but also helps eliminate a lot of common logic bugs (around unexpected mutation, concurrency, invalid state), and I find myself wanting the feature in all languages that I use.
      Thanks for your thoughts on this!

    • @torarinvik4920
      @torarinvik4920 Год назад

      @@CataBits I see your point, however Rust introduces more friction, very similar to Haskell. This means that your program is less likely to have runtime errors. But there is a trade off. Functional programs for instance tends to take longer time to write because of the hoops you need to jump through. Rust does this also, but too a lesser degree. So as far as productivity goes there is a sweet spot between correctness and the ease of which you can write the programs. F# to me hits that sweet spot almost perfectly, but Swift is also IMO a close contender. Also because of garbage collection you automatically free up cognitive resources to think about programs rather than resource lifetime. I would also like to say that even though a language with friction takes more energy to use, with time you will become as productive if not more if you spend all your time doing it. But that goes for just about anything in life. IMO guitar is harder to play than drums, but if you spend all your time playing guitar then of course drums is going to be more difficult. So then question would be if you spend 50/50 of your time on the two what would be easiest. That being said this is subjective, and everyone has their own experience. Things like dependent types for instance might increase correctness and lead to less debugging in the future, but I have no evidence to back this claim up. Excellent video btw.

    • @CataBits
      @CataBits  Год назад +1

      @@torarinvik4920 I agree - I find the friction introduced by the ownership system to be worth it, so I kind of want a similar system everywhere. The sweet spot is indeed debatable, though I think most languages with mass-market appeal don't have enough mechanisms to enforce correctness. I also like F# (though I just looked at its features and syntax, but not coded in it). I really like OCaml and F#, but the ecosystems and communities around them don't seem developed enough for me to consider dedicating a serious amount of time to them.
      Thank you for the kind words. Now, I'm self-conscious about the video. Doesn't seem polished enough for the amount of views it got. I also forgot to explain the point of associated types and also forgot to talk about blanket implementations for traits.
      I'll try to do better for the next one. Thanks again!

    • @torarinvik4920
      @torarinvik4920 Год назад

      @@CataBits The video was great, no need to be self-conscious about it. As far as OCaml goes it has a very small community, I don't know about the F# community as I have just been doing it on my own, but I think it's quite small too. The ecosystem on F# however is very good because it runs on .NET if one browses the package manager there is tons of libs and they actually work in contrast to Haskell's notorious build/package manager Cabal. But focusing attention on Rust is a good choice, it also gives you a lot of the features of the functional programming languages.

  • @sohansingh2022
    @sohansingh2022 11 дней назад

    Absolute gold!

  • @Adityarm.08
    @Adityarm.08 Год назад

    Good stuff. Thank you.

  • @realtimberstalker
    @realtimberstalker Год назад

    I don’t think I understand the ending. It looks like you are comparing a value in Java which is already boxed in a variable of type interface to Rust simply calling the function on the object. I’m sure both act the same when you do the same thing, but correct me if I’m wrong.

    • @CataBits
      @CataBits  Год назад +1

      The point was how the internals behave (binary exacutable for Rust, and JVM for Java). Yes, calling a method on an interface does the same thing in both languages. The question was how they perform this.
      Again, both languages use a mix of static and dynamic dispatch with different defaults. The idea is that in static dispatch, you know before starting the program what method implementation will be called (it's written expressly inside the binary format), while in dynamic dispatch this gets determined while running, a bit before the actual execution.
      Let me know if this helped clear things up.

    • @realtimberstalker
      @realtimberstalker Год назад

      @@CataBits
      From the way you explained it,
      Derived.GetFoo() and IInterface.GetFoo() would both be dynamic dispatch in java except for certain random exceptions. I would assume both languages use static dispatch when calling the function from the derived class and dynamic dispatch when calling from the interface/trait.

    • @CataBits
      @CataBits  Год назад +1

      @@realtimberstalker It doesn't matter if you use Derived.GetFoo() or Interface.GetFoo() because in Java, ALL calls are dynamic, except for private methods and final methods (static methods too, but this is irrelevant to our discussion) In Rust everything uses static dispatch, unless you use trait objects (the Box syntax) How you call the method does not effect how the runtime determines the actual implementation.

    • @realtimberstalker
      @realtimberstalker Год назад

      @@CataBits Oh ok. Thank you.

    • @CataBits
      @CataBits  Год назад

      @@realtimberstalker You're welcome - I think part of the confusion comes because I didn't explain aspects of traits. In Java, you can use an interface like a type, so you can call the method on an interface reference, while in Rust, you can't use a trait as a type. Rust only supports this when using the trait object pointer. So, unless you're using the "dyn" syntax, you can only call methods on concrete types.

  • @noomondai
    @noomondai Год назад

    Thank you!

  • @olucasromero
    @olucasromero Год назад

    Nice video but I still prefers how interfaces do work instead of traits. Everything should be into own type instead otherwhere implementation, with makes it hard to understand in a large code bases. Everything else, like default implementation and optimization interfaces does provide, as language specific way to do that

    • @CataBits
      @CataBits  Год назад

      Thanks! I still prefer Rust's system - with blanket implementations (sadly I forgot to cover it in this video - though it is in my latest one) you can have methods available for structs even before the structs are defined, so any type that respects certain conditions will have the methods available without having to do anything extra.

  • @ImaginaryNumb3r
    @ImaginaryNumb3r Год назад +2

    Oh nice, this is not biased at all. But just a few things:
    1. You can do anonymous implementations if you want to. But most elegantly, Java allows you to use single-method interfaces as function pointer targets.
    2. Interfaces can have default methods, which achieve the same thing as associated types in traits.
    3. Fails to mention dynamic runtime optimization and instead provides a strawman statement of "in some cases, inlining happens".

    • @CataBits
      @CataBits  Год назад +2

      Thanks for commenting - Really good points.
      I can't say I'm not biased on this. I have been working with Java professionally for almost a decade now, but for my personal work, I have a strong preference for Rust, due to increased flexibility and safety. My replies to your points:
      1 - I know, and these are great features, but these are a result of the fact that Java forces you to organize everything into classes. These are great ways to allow for flexibility within Java's system, but my point was that Rust is more flexible from the get-go, and thus I don't have to tie my types to my interfaces. In Java, everything that is not a lambda or an anonymous implementation will be limited by this.
      2 - I don't think you're seeing all the implications of associated types. This is my fault because I kind of breezed through the example in the video without highlighting the differences. The associated type is different than a generic type for the trait - It allows me as the trait designer to force a single type for all the possible implementations of a generic trait. Normally, the user would be able to use different types for each implementation. Rust gives me the tools to enforce this as a library designer when it's the case.
      3 - Yes, I did not go into detail about Java's optimizations, mostly because I thought it was too much for the video. With the same rationale, I avoided discussing Rust optimization strategies. My main point on this was that Rust uses static dispatch by default unless you ask for dynamic, while Java uses dynamic dispatch, except for some cases (private, final, static). I didn't cover the cases where the optimization is made as the channel is Rust-focused. Also, this would be a compile-time optimization. Any dynamic runtime optimization as you mentioned still proves my point (that Java mainly handles this at runtime).
      Also, for this, I didn't propose that one approach is better than the other - I just showed that they're different because I thought it was interesting to showcase. Indeed, I do show my preference for Rust in the first half and the conclusions, so I get why the dispatch section could give off this impression.

  • @mahmoudabdelsattar8860
    @mahmoudabdelsattar8860 Год назад

    its wonderful, but an advice there is "smock" sounds between statements try to remove it

    • @CataBits
      @CataBits  Год назад

      Thanks - I'll pay more attention to this when editing. Should have done it for this video as well, but I didn't expect it to get so many views.

  • @AK-vx4dy
    @AK-vx4dy Год назад

    Yes valuable gem from algorithm!!!

  • @basilalharbi3293
    @basilalharbi3293 Год назад +2

    put the video on 1.25x

    • @CataBits
      @CataBits  Год назад +2

      Thanks, I'll update the presentation style for future videos - it is quite slow indeed.

  • @Vianou-vm2zv
    @Vianou-vm2zv Год назад +3

    20 seconds in and it's weird. When Rust is compared with another language, folks often use C++.

    • @CataBits
      @CataBits  Год назад +2

      It might be illegal in some states :D The concept of interfaces (via abstract classes with virtual methods) in C++ looks too weird for a comparison on this topic - it might have been confusing.
      Also, I program Java professionally and haven't touched C++ in almost two decades, so there you go.

  • @_rkkm_
    @_rkkm_ Год назад +2

    java ia multiparadigm too lol.

    • @CataBits
      @CataBits  Год назад

      You could say so, but the way in which Java is multi-paradigm would apply to the vast majority of languages - in which case, I don't find the designation that useful.
      I'd say Java is not multi-paradigm on the level of its DNA. It forces you to organize everything into classes and objects.
      You get limited features from other paradigms, such as lambdas from FP, but those are just syntactic sugar over object calls.
      In a way, both languages are multi-paradigm, but I just wanted to point out that Rust allows for more flexibility in the ways code can be organized.

  • @cemgecgel4284
    @cemgecgel4284 Год назад

    Unfortunately, many things you talked about have Java equivalents and you did not talk about them.

    • @CataBits
      @CataBits  Год назад

      Java has workarounds for the design limitations, but save from the dispatch section, none of the features I showcased in Rust are present in Java.

    • @cemgecgel4284
      @cemgecgel4284 Год назад +1

      @@CataBits Hello, I just do not wan't to be in an echo space about how Rust (TM) is so good. For example, the new type pattern int Rust (TM) is equivalent to the adapter pattern in Java. But, one of them gets labeled as "workaround".

    • @CataBits
      @CataBits  Год назад +1

      @@cemgecgel4284 I find Rust very good - it's not all good - and I'm not saying this. The point of the showcase was to show stuff in Rust that you don't get in other languages.
      What I presented (implementing an interface in my code for an external type) does not require the newtype idiom, while the same use case requires a structural pattern in Java (the adapter).
      Indeed, if want to implement an external trait for an external type I would have to use the newtype pattern (which I would consider as a workaround in this case). Still, Rust is more flexible here, as the previous case does not require a structural pattern to get what I want.
      Sure, I can implement whatever I want in Java - it's a powerhouse language, and people have figured out all sorts of patterns for it, but that doesn't mean that there aren't cleaner more ergonomic ways of doing things in other languages (and that's what the showcase is about).

    • @cemgecgel4284
      @cemgecgel4284 Год назад

      @@CataBits Thanks for clearing out your stance. Newer languages are definitely neater than the older ones. I agree. I just expected a comparison with Java, but did not see the Java equivalents shown.

    • @CataBits
      @CataBits  Год назад +1

      @@cemgecgel4284 I agree, the packaging is somewhat misleading - It's mostly a showcase of what I think Rust does better (the dispatch section would be mostly a straight-up comparison).
      Still, some of the things in the list don't have a relevant / convenient Java equivalent (associated types, visibility of mutability, derives).
      I'll avoid framing videos like this in the future if I don't do a thorough comparison.
      It's my fault, I started with one idea, and the video took a whole different direction - I should have updated the start to match this.

  • @TheNinjaDwarfBiker
    @TheNinjaDwarfBiker Год назад

    your 299th subscriber

  • @bretzel30000
    @bretzel30000 Год назад

    i am sorry i need to "actually ..." you on the claim in the beginning that java forces you to use OOP.
    Its not correct that java forces OOP, you can do completely OOP free coding with java by simply only ever declaring all methods to be static and never use inheritance.

    • @CataBits
      @CataBits  Год назад +1

      Haha, Get out! :) - Indeed you can, but it would be too unwieldy to use with these restrictions. You can also use a lot of lambdas ( though behind the scenes they're still method calls on objects).

  • @dmitrykim3096
    @dmitrykim3096 Год назад

    Are you a real person? You sound like Steven Hawking

    • @CataBits
      @CataBits  Год назад +3

      Haha - I'm actually a frog waiting for a kiss from a princess - until then, I'm using AI to generate text and voice for me. :D Joke aside, I realize my voice sounds robotic in this video. I was too worried about pronouncing each word correctly and it came out very flat. I want to improve this in future videos.

  • @TheD3adlysin
    @TheD3adlysin Год назад

    Please take a course on speaking.

    • @CataBits
      @CataBits  Год назад +1

      Point taken - I actually attended Toastmasters for a while, and my mentor evaluated me as someone who naturally speaks well, having the TM fundamentals covered from the get-go.
      The problem is that I'm awful at recording from a script. I naturally speak very fast, and tried to consciously slow it down for clarity, but it ended out being robotic. I should have re-recorded it, but I rushed to release the video as I've been delaying it for a while. If I knew the video would take off like it did, I would have focused more on the delivery.
      I'm conscious this is a major sore point for the video, and I'll focus on getting this handled.

    • @TheD3adlysin
      @TheD3adlysin Год назад

      @TrustyBits-ni8ub oh! You'd be surprised how many people are like that. Do yourself a favor. Don't script. Use an Outline and we know you already understand your topics o you're already 50% there.
      It wasn't robotic, it called forth all the character of a tenured college professor droning off information they'd repeated for the last 20 years.

    • @CataBits
      @CataBits  Год назад +1

      @@TheD3adlysin Hmm, the script is useful for creating the animations and synching them to audio, but yeah - I need to use a different strategy when I record. Thanks for the suggestions!

  • @aliimranalfred
    @aliimranalfred Год назад

    we can do this in java like this
    public class SomeStructWithLength extends SomeStruct implements Length{
    public int get_length(){
    return this.toString().length();
    }
    }
    but I agree in rust we do things differently.