Cătă's Bits
Cătă's Bits
  • Видео 9
  • Просмотров 42 389
Rust: Haskell, but more imperative
Can Rust do functional programming? - We'll be covering common principles and features between Rust and Haskell.
Script on my blog: catalin-tech.com/haskell-rust/
Просмотров: 5 834

Видео

Rust: Associated types for Iterator implementations
Просмотров 4,9 тыс.Год назад
This video explains how to understand type bounds for standard library types around iterator traits. This will cover associated types, blanket trait implementations, and how these relate to the type-bound syntax, by using examples from Iterator, IntoIterator, and Flatten. You can find the transcript of the video as a blog post at this link: catalin-tech.com/std-lib-bounds/
Rust Does Interfaces BETTER!
Просмотров 30 тыс.Год назад
Comparing Rust's traits over with interfaces from languages like Java, and showing off the advantages that the traits offer. Linked article: catalin-tech.com/traits-vs-interfaces/
Hiding messages in PNG files with Rust - Part 5 (Wrapping up)
Просмотров 185Год назад
Implementation of the PNGme project suggestion. Link to original guide: picklenerd.github.io/pngme_book/introduction.html This project creates a binary together with library functions to open and edit PNGs (mostly metadata) - we won't be manipulating the pixel data in the images. This will allow users to add custom chunks with encoded messages while keeping the file structure still valid. As me...
Hiding messages in PNG files with Rust - Part 4 - parsing commands
Просмотров 120Год назад
Implementation of the PNGme project suggestion. Link to original guide: picklenerd.github.io/pngme_book/introduction.html This project creates a binary together with library functions to open and edit PNGs (mostly metadata) - we won't be manipulating the pixel data in the images. This will allow users to add custom chunks with encoded messages while keeping the file structure still valid. As me...
Hiding messages in PNG files with Rust - Part 3
Просмотров 152Год назад
Implementation of the PNGme project suggestion. Link to original guide: picklenerd.github.io/pngme_book/introduction.html This project creates a binary together with library functions to open and edit PNGs (mostly metadata) - we won't be manipulating the pixel data in the images. This will allow users to add custom chunks with encoded messages while keeping the file structure still valid. As me...
Hiding messages in PNG files with Rust - Part 2
Просмотров 220Год назад
Implementation of the PNGme project suggestion. Link to original guide: picklenerd.github.io/pngme_book/introduction.html This project creates a binary together with library functions to open and edit PNGs (mostly metadata) - we won't be manipulating the pixel data in the images. This will allow users to add custom chunks with encoded messages while keeping the file structure still valid. As me...
Hiding messages in PNG files with Rust - Part 1
Просмотров 794Год назад
Implementation of the PNGme project suggestion. Link to original guide: picklenerd.github.io/pngme_book/introduction.html This project creates a binary together with library functions to open and edit PNGs (mostly metadata) - we won't be manipulating the pixel data in the images. This will allow users to add custom chunks with encoded messages while keeping the file structure still valid. As me...
Rust iterator adapters for handling ownership
Просмотров 405Год назад
A short presentation on a few Rust iterator adapters used to handle ownership Link to associated blog post: catalin-tech.com/rust-iterator-adapters/

Комментарии

  • @razishah794
    @razishah794 Месяц назад

    THANKS FOR CREATING THAT video i was stuck in project for 1months even i take a break from rust cause i were not able to do that and im new in rust so i dontt have good experience with these chunks

    • @CataBits
      @CataBits 16 дней назад

      Sorry for the late reply - Glad it was helpful! Thanks for letting me know!

  • @rajajrt_
    @rajajrt_ 2 месяца назад

    Hey, thanks for the walk through!

    • @CataBits
      @CataBits 2 месяца назад

      Thanks for watching and engaging! Glad it was useful!

  • @deanroddey2881
    @deanroddey2881 2 месяца назад

    The whole unsafe side trip is highly misleading to anyone who doesn't know Rust, who might think you have to use unsafe just to do I/O.

  • @Chinmaykhadilkar
    @Chinmaykhadilkar 3 месяца назад

    your walkthrough for this projects has been a very vital guides for me. I thank you very much sir!!!!

    • @CataBits
      @CataBits 2 месяца назад

      Thanks for letting me know! Glad it was useful!

  • @docteurklein
    @docteurklein 4 месяца назад

    I raised my eyebrows at 5:40 when I heard that "unsafe" is the rust way to "know what parts of the code can cause side effects". I was expecting Result::and_then to popup when talking about IO and monads! Also Option::map/and_then ,which share far more similarities than "unsafe" IMHO. (I would have compare rust's unsafe to haskell's "unsafePerformIO").

    • @CataBits
      @CataBits 3 месяца назад

      Hi - I didn't say that, though I get how a viewer could make the connection. Thanks for pointing this out. I was just saying that it's a similar concept o creating a barrier around operations that are more dangerous. I wanted to mostly compare philosophical approaches to language design, rather than comparing Haskell's monad capability with the monad types we have available in Rust.

  • @TheLANBeforeTime-uo9ph
    @TheLANBeforeTime-uo9ph 10 месяцев назад

    agian really good part2 after part1. I have taken a look at the part2 hint and learned to use reader to get the data from [u8], and I learned to use iterator.by_ref() to do the same. Also the container = vec![] and container.extend() to fill in data. You have a calm way to write and express the code. It's a super good screencasting style for teaching code. Hope you will make more of Rust videos :)!

    • @CataBits
      @CataBits 10 месяцев назад

      Thanks! You're too kind :) I might try this format again. I did do some more Rust coding recently - maybe I can package it in an interesting way to record.

    • @TheLANBeforeTime-uo9ph
      @TheLANBeforeTime-uo9ph 9 месяцев назад

      @@CataBits creating videos take time and energy, but also helps you to solidify the knowledge, especially if you enjoy doing it :)! Looking forward

  • @TheLANBeforeTime-uo9ph
    @TheLANBeforeTime-uo9ph 10 месяцев назад

    Thanks for the video, just fits my level :). I was unfamiliar with "Display", thus also stuck with the error returning part. May I ask what editor do you use? Look like IntelliJ.

    • @CataBits
      @CataBits 10 месяцев назад

      Glad it's useful! Yes, it's IntelliJ. I have tried RustRover recently along with neovim using the Astro configuration.

    • @TheLANBeforeTime-uo9ph
      @TheLANBeforeTime-uo9ph 10 месяцев назад

      I was using neovim, so it's natural for me to continue. Never tried other IDEs for Rust other than VSCode, but I'm pretty happy with neovim and my own dotfiles@@CataBits

  • @Jan-gl7mn
    @Jan-gl7mn Год назад

    Rust just took some old ideas from Haskell and others and found a way to write code without GC, but the syntax of Rust is ugly and terrible, coming from Haskell, Rust code looks like C++ mix with some hipster language, hard to read. Haskells main issue is bad documentation, tooling(2 gb to install the compiler..) and no backward compatibility, but Haskell's syntax is amazing, although language extensions in Haskell are annoying.

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

      Would agree - I think it's hard to come up with a way of simplifying Rust syntax while keeping the advantages it currently offers. I'm personally ok with dealing with awkward syntax in some areas in order to have the benefits, but I get why people wouldn't want to deal with it. Haskell is indeed elegant and beautiful (though there are certain design choices that I very much dislike), but using it to build something that you actually want to use is not the best experience - though it's getting better. Compared to Rust's tooling, a lot of languages don't look that good, in any case.

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

      Well spotted. Just to make the story more interesting - Rust also took old ideas from Simula I, with automatic memory management via the ownership model ... which is effectively a form of automatic garbage collection. That was all back in the late 1960s, where CPUs were not as fast, and allocate / free overhead was quite a bit higher. So the general solution to that performance problem was to delay and batch up garbage collection, which then led to the "mark and sweep'" style of GCs that we are familiar with today. Ironically, mark and sweep GC is now considered harmful to performance :) End of the day ... manual memory management has always been the performance king, and its always going to be the performance king. It's just got a few obvious foot guns. I much prefer Zig's approach to addressing those obvious foot guns, rather than attempt to invent a whole new way of restricting programmers that just gets in the way. I don't find using Rust to be enjoyable in the slightest, and that has nothing to do with the syntax. I would rather peel potatoes for a living

    • @angeldude101
      @angeldude101 6 месяцев назад

      Honestly, making Rust's syntax more like Haskell is one of the very few things that would make me like the language even more than I already do.

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

    Magnificent video <3 TYSM!

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

      You're too kind! Glad you enjoyed it!

  • @Lucs-ku5cb
    @Lucs-ku5cb Год назад

    Please make a video about haskell templates and Rust macros

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

      Thanks for the input!

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

    Script and code: catalin-tech.com/haskell-rust/ Errata: At 11:40 - the macro doesn't have the correct syntax, and the derived trait has to be Debug - Display is not derivable. The following print macro also needs a format string.

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

    id say more like scala really...

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

    Loved, the video, concepts are explained fairly clearly, I would love to see more Haskell content.

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

      Noted - Glad it was useful, thank you so much!

  • @0-Kirby-0
    @0-Kirby-0 Год назад

    Content? Fantastic, learned something and had things cleared up in my head. Prosody? Needs work. Looking forward to more!

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

      Glad you found it useful! Thanks for the feedback - I'm working on improving the way I talk while recording.

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

    Perhaps Ocaml is more accurate :)

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

      You could say that OCaml is closer to Rust because it has some imperative features, while Haskell has none. (Though this makes it closer to any imperative language - which I find very uninteresting to discuss). Looking at the way the type system is designed, I find that Rust borrows more from Haskell than Ocaml (see traits / typeclasses vs modules in OCaml.

  • @Nesdac-k1l
    @Nesdac-k1l Год назад

    underrated channel. 🙏🙏🙏

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

      Thank you so much!

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

    This is a very good video! Can you telll us what you used for creating these animations for slides and the code highlighting synced with audio?

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

      Thank you! I used: motioncanvas.io/ The animations have to be made using code, but the synching is done by clicking and dragging in the render interface. The code animations use this component: motioncanvas.io/docs/code-block/

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

    Re-upload?

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

      Yes, there was a major mistake for the monad explanation in the first version, so I updated, rerendered and re-uploaded.

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

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

    Amazing video! :D Thank you, I was really entertained. I love type system of Rust, so I could watch these kind of videos all day!

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

      Thank you so much! I can also just geek out on Rust's type system. I do want to do more of this - though it can be difficult to find good examples that can be packaged neatly into a video.

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

    Hi, Trusty Bits! Thanks for sharing this. I think you might like to try, in `TryFrom<&[u8]>`, using slice indexing instead of messing with vectors and `iter().take(n).copied()`, etc. You can use `u32::from_be_bytes(<[u8;4]>::try_from(&value[..4])?)` to get the length, for example. You could also go back to chapter 2, and make `Chunk`'s' `TryFrom<&[u8]>` work when given `value` with multiple chunks. It would just ensure that the value has 12 bytes, then read the length, then ensure the value is at least long enough to hold that length of data. This way in `Png`'s `TryFrom` you can just loop calling `let chunk: Chunk = value.try_into()?; value = &value[chunk.length() + 12..];`. Anyways, I thought that might be an interesting option for you to play with.

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

    I'm happy to see this topic being covered. I used some concepts here myself making my own crate.

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

      Glad you found it useful! Thanks for letting me know.

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

    I just started learning and making videos about Rust, and this video is very helpful.

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

      Glad it was useful! Hope you have fun learning!

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

    Very well done video!!! Very nice. Keep these up. We need more intermediate videos on rust. Thank you.

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

      Thank you so much!! Will do!

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

    Great video, we need more of this xD

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

      Thank you so much! Working on it :)

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

    Very nice video and great explanation ! Thank you all that is missing is a small implementation of an iterator at the end but i'm just nitpicking :)

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

      Thanks, glad you enjoyed it. To be honest, towards the end of recording, I kind of got tired of saying the word "iterator" :D Hmm, I wanted to focus on the trait bounds specifically, though I did cover some tangential stuff around iterators. I think I did it in the previous video, though I didn't give a practical example with showcasing the iteration logic. I felt like there are many details to cover for a realistic implementation scenario (most of the stuff that's iterable already implements Iterator or IntoIterator) and didn't want to spread the topics too much. Thank you for watching and reaching out!

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

    Blog post with transcript: catalin-tech.com/std-lib-bounds/

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

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

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

      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)

  • @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 Год назад

      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 Год назад

      @@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

  • @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<Self::Item>{ // 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 Год назад

      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!

  • @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!

  • @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 Год назад

      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).

  • @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 Год назад

      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 Год назад

      @@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.

  • @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 Год назад

      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.

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

    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!

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

    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 Год назад

      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 Год назад

      Rust has trait inheritance..

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

      @@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 Год назад

      @@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.

  • @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 Год назад

      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<T: Vehicle>, for e.g.

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

      @@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<T> - there is only one valid type that the iterator should return for T - If I turn it into Iterator<T, R>, 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.

  • @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 Год назад

      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 Год назад

      @@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<dyn T> 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.

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

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

    Good stuff. Thank you.

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

    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<String, String> m); vs doStuff(ImmutableMap<String, String> 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 Год назад

      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 Год назад

      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 Год назад

      @@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.

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

    your 299th subscriber

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

      Thank you so much!

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

    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.

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

  • @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 Год назад

      @@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 Год назад

      @@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 Год назад

      @@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.