Funny that you joke about being an educational channel. I been noticing lately I get a lot of useful nuggets from watching more casual videos on about programming. I never know what I am going to find but when you do find it. Its like you knew that's what you needed to find and can immediately put it to practice.
Once you get past syntax, formulae, and patterns, the rest is all experience, philosophy, and nuanced opinion/discovery. The classroom is great for the former, but open forums and casual discussions are where you get into the meat and potatoes of the latter.
I love how OCaml gets inspiration from Rust after Rust got inspiration from OCaml :). I can now see how OCaml has some unique advantages over F#. Thanks for your continued focus on OCaml, guys!
Haskell has (experimental) support for linear types, though they are not the same as the affine types of Rust. Hopefully one day linear types in haskell will be extended to affine types. Once you have linear types, affine types shouldn't be too much extra work (as far as I understand) Not to mention that a lot of these things can also be done in haskell with indexed monads, like making sure a file descriptor is closed before you finish or leave a computation. You can also do internal mutability with the ST monad, etc.
I'm curious about the recent complains about Rust. I haven't experienced Arc hell or lifetime explosion for my usual web apps. I would love to see Prime giving some real world examples for Go vs Rust vs Ocaml.
I haven't seen Arc hell, but I have seen lifetime explosions in web apps when later down the line a field in a struct changes to be something that requires a lifetime. In a recent case it was a field that was initially a concrete struct with an associated function becoming a dyn trait object, or vector of them, like a Vec or something similar. Then everywhere that takes or injects this struct such as middleware extractors now needs this lifetime adding, including whatever was initially building this struct, then anything that uses that and so on. When it's on things like state for web apps you can get away with static but this is not always the case depending on what it is, such as something that's being built up in middleware and injected into the request context for further down. It's a quick and simple refactor, I find it to be a seconds vs minutes gripe, but it can result in a lot of lifetime adding to signatures, impl blocks etc for the sake of what was initially interpreted as a simple change. That kind of "simple" change in other languages, essentially changing a field type from a "struct" to an "interface", is actually significant under the hood, Rust just makes you realise how significant as the lifetime can't/won't be automatically inferred anymore. The only real actual "issue" I can see with it is the amount of git merge conflicts it can cause in teams as you can end up changing a lot of seemingly unrelated code to your original business logic requirement requiring the change, or "breaking" code wanting to come in from other PRs. That's what desk-nunchucks are for though.
@@kriscarr2442 Why not put that dyn into `Box` or a `Rc`/`Arc` if it needs to be shared? It would end up on heap anyway due to `Vec`. Alternatively something like `any_vec` crate would be a nice fit to retain a single vtable deref. I use a rule of thumb for references and it's: "Should my `StructA` care about this lifetime existing?". So for something like `Reader`, it cares about the source; something like `House` shouldn't have a lifetime because one of the inhabitants might have a shared car - car goes in `Rc`.
So it's like a local opt-in to Rust's safety features. Interesting. Though, as far as I can tell, you still get some function coloring. If you make a function parameter unique, then you might have to track down all calls to the function and ensure the uniqueness of the argument, potentially making more parameters unique or exclusive. If they manage to infer these modes, though, it's gonna be huge.
Now things are coming full circle, rust's memory management is based on research on region-based memory management that was done as a ML dialect, back in 1995.
Wow you know I’m only a little interested in rust but I’ve always wanted to try a taste of the functional koolaid. I think I will join you for Advent of Code this year in OCaml
So what's more complicated: explicit borrowing and explicit lifetimes, or a hundred modifiers? It's a tradeoff I guess but now I appreciate Rust more. Also: F# is awesome and they should incorporate some of the new OCaml stuff.
While i understand your issues with: - coloring - futures being lazy - ownership & lifetimes I personally do like the explicitness everywhere in Rust. Futures running before i tell them to are a headache for me. I like working with lifetimes and ownership. And i don't mind having colored async functions when they e.g. use async internally since it gives me a heads-up for what is happening "down below". Though the situation with multiple runtimes and tokio being a de-facto standard hurts me - i prefer zigs way of providing the async runtime. Love your content! I'm regularly learning a lot from you. Your opinion on topics is a valuable factor in quite a few decisions i have to make in my job & personal projects. Thank you Prime!
The concept of lifetimes is good in principle, but the explosions of lifetime required errors you get when you add one anywhere is truly brutal. It's the main area Rust needs improvement. What if the compiler could just keep trying different lifetime requirements until the code worked, maybe putting up a warning if one of your variables needed a static lifetime as a result so you're not eating too much memory. Lifetimes are just handled as a total pain in the ass. Like if I create a struct containing a reference, it forces me to put a lifetime just to tell it that the struct's lifetime has to be shorter than the reference's lifetime, so it can't hold a dead reference. This is 100% a thing the compiler should be able to figure out on its own.
@@taragnorSure, but what if your struct has two or more references? Do they have the same lifetime or different ones? Also he is saying that Rust's "fearless concurrency is just Arc> which is not true. Rust's fearless concurrency are Send and Sync traits (possibly other mechanism's too, not a Rust expert) by which Rust can check at a compile time that you wont have data races.
@@maniacZesci you are correct with Arc not being the only option. There are for example multiple channel implementations within the tokio::sync module and within the crossbeam crate which i have used. The choice between those depends on if the project is async or not. As opposed to golang we get specialized channel implementations for different use cases (e.g. mpsc, mpmc, oneshot).
@@maniacZesci The rust complier can already tell if you have lifetime problems, that's part of what makes it so good at spotting errors. All I'm saying is that it could just fill in a lifetime that makes your code work. Essentially just try a few different lifetimes to see if the code compiles, and if it only works with a static lifetime then give a compiler warning. I understand if you're writing some code for a library, you'd probably still have to do them yourself, because you don't have all the code, but if you're writing a complete executable, the Rust compiler has all the code and a complete picture of the program. If there exists a set of lifetimes that work for that program, it should just be able to auto fill them in in a way that eliminates the compilation error (assuming your program isn't doing anything totally unsound that'd make that it impossible to set a lifetime).
I love OCaml-users who think OCaml has more industry adoption than Haskell, its cute really. Especially since it only requires a 15 second google to find out that the financial industry has an order of magnitude more adoption of Haskell. Which is hilarious in and of itself, because that means that 10 companies use Haskell. Rust, which hasn't even been around half as long as either, has more adoption. That's a sad state of affairs. 😅
11:06 isn't that the point of implicit Copy in Rust though?! Where if it's trivial to copy it'll just do that? To me the whole point is that in Rust you might need to be verbose all the time, but if too much stuff is opt-in someone is bound to mess it up and you're left with the same problems again.
Firstly OCaml for AOC2023 FTW! This is a healthy language competition, just like antimonopoly in business, both are learning from each other and evolve to higher level. Which, the OCaml wasn't that low level to begin with. Are they both eventually going to evolve into Haskell? 😂
I like the statement of "Does this mean i don't have to go and put lifetimes everywhere?" I'm pretty sure that's wrong: If you run into a situation where you would need a lifetime (a function returning a reference) you just can't do it. At least that's how i understand it. More like C++ references maybe.
1:00 I don't really get what people are talking about. I literally never use clone and I don't see how it would help in many situations. A &mut is all you need 90% the time anyway.
I feel the same way. If you use clone a lot you should rethink the architecture of your program. You can get away with &mut fn parameters passing stuff around just fine. The same with the whole "Arc" and "
Reasonml I was a mess. Now I think it's just called re-script which is fine I suppose but it leans very heavily into the JavaScript syntax which is not easier.
It's not just OCaml, even the new wannabe Python superset called Mojo is implementing Rust-like ownership. I don't know who in the Python community would actually want that.
I know it's such a meme by now that it will never happen... but watching videos where you talk about clever stuff in OCaml makes me think you would really enjoy Haskell...
you guys talk about 'running' programs being some niche thing to haskell programmers... I have it on good authority that there is a subsect of hasklnauts that don't care about compilation at all beyond type checking. If it typechecks, some angel gets a bonus and stock options. Linting would probably get them 99% of the way to completion.
How does this mode work with relation to the type inference? You mention it is completely separate, so I'd assume that overloads are not a thing? One could imagine two definitions of map - A fast one that takes advantage of exclusiveness ( when given ) , and a default one. As I understand, the compiler would not be able to correctly dispatch to the best one?
If the compiler is able to do pattern matching when no argument is given, I’m sure it can compile into a similar kind of backtracking automata or decision tree as that case when handling the case when the type mode is specified or not. I could be wrong though. Interesting question and I hope somebody has a better answer!
Honestly I think that is because he does web stuff mostly. I/O bound issues mean you're kinda forced into using Tokio and the path of least resistance is always cloning or Arc'ing everything which become frustrating very quickly. Rust is very good if you plan beforehand. If you just want to get in and code away making stuff up as you go along it's rough for any medium complexity issue.
OCaml is older, but these `local` and `unique` modes are new extensions of it that afaik are not (and may never be) in the language. Rust on the other hand had ownership from the start.
Regarding the opt-in mutability thing in Rust: you can't call it a variable if it isn't variable -- if everything is immutable, then nothing varies, so it ultimately isn't actually a variable. Perhaps "symbol" would be a better term, but then you'll get the attention of the Lispers.
Ocaml is kinda faster. Read somewhere it hovers around top 10. Its older than rust, but got many of features of newer languages. Imagine a language from 90s with package manager like rust. But don't know much beyond it though.
@@NC-nc3gsOCaml is definitely, not remotely, even closely, faster than Rust or any of the C/C++ like languages when considering base line usage. There is plenty of simple/stupid benchmarking examples you can Google for and OCaml falls massively, several orders of magnitude in certain cases behind. Now, I know benchmarks like those should always be taken with a grain of salt, but it goes to show that no, OCaml can not be claimed to be faster than Rust.
@@simonfarre4907no one said it's as fast as rust but it is one of the fastest languages out there and I'd argue for the amount of abstraction ocaml has it is the fastest.
Funny that you joke about being an educational channel. I been noticing lately I get a lot of useful nuggets from watching more casual videos on about programming. I never know what I am going to find but when you do find it. Its like you knew that's what you needed to find and can immediately put it to practice.
:)
@billybest5276 Actually! Constantly I'm learning tiny nuggets that unlock understanding. Often things i didn't realise I didn't quite understand.
This
The best part is when they're discussing concepts and now i gotta lookup that concept and stuffs. This does not happen in actual educational videos!
Once you get past syntax, formulae, and patterns, the rest is all experience, philosophy, and nuanced opinion/discovery.
The classroom is great for the former, but open forums and casual discussions are where you get into the meat and potatoes of the latter.
I love how OCaml gets inspiration from Rust after Rust got inspiration from OCaml :). I can now see how OCaml has some unique advantages over F#.
Thanks for your continued focus on OCaml, guys!
Haskell has (experimental) support for linear types, though they are not the same as the affine types of Rust.
Hopefully one day linear types in haskell will be extended to affine types. Once you have linear types, affine types shouldn't be too much extra work (as far as I understand)
Not to mention that a lot of these things can also be done in haskell with indexed monads, like making sure a file descriptor is closed before you finish or leave a computation.
You can also do internal mutability with the ST monad, etc.
Ye, Linear types are just Affine types + a lower bound for usage
Ever tried working with the STD monad?
*pets the Prime’s OCaml* 🐫
“Wow, thats a good camel right there. It takes a function like no problem! Thats a good camel right there!” 😻
I'd love a video comparing writing a program in rust with and without cloning.
I mean you can just try doing it. It comes up in essentially every program.
I'm curious about the recent complains about Rust. I haven't experienced Arc hell or lifetime explosion for my usual web apps. I would love to see Prime giving some real world examples for Go vs Rust vs Ocaml.
I haven't seen Arc hell, but I have seen lifetime explosions in web apps when later down the line a field in a struct changes to be something that requires a lifetime.
In a recent case it was a field that was initially a concrete struct with an associated function becoming a dyn trait object, or vector of them, like a Vec or something similar. Then everywhere that takes or injects this struct such as middleware extractors now needs this lifetime adding, including whatever was initially building this struct, then anything that uses that and so on. When it's on things like state for web apps you can get away with static but this is not always the case depending on what it is, such as something that's being built up in middleware and injected into the request context for further down.
It's a quick and simple refactor, I find it to be a seconds vs minutes gripe, but it can result in a lot of lifetime adding to signatures, impl blocks etc for the sake of what was initially interpreted as a simple change. That kind of "simple" change in other languages, essentially changing a field type from a "struct" to an "interface", is actually significant under the hood, Rust just makes you realise how significant as the lifetime can't/won't be automatically inferred anymore.
The only real actual "issue" I can see with it is the amount of git merge conflicts it can cause in teams as you can end up changing a lot of seemingly unrelated code to your original business logic requirement requiring the change, or "breaking" code wanting to come in from other PRs. That's what desk-nunchucks are for though.
@@kriscarr2442 Why not put that dyn into `Box` or a `Rc`/`Arc` if it needs to be shared? It would end up on heap anyway due to `Vec`. Alternatively something like `any_vec` crate would be a nice fit to retain a single vtable deref.
I use a rule of thumb for references and it's: "Should my `StructA` care about this lifetime existing?". So for something like `Reader`, it cares about the source; something like `House` shouldn't have a lifetime because one of the inhabitants might have a shared car - car goes in `Rc`.
So it's like a local opt-in to Rust's safety features. Interesting. Though, as far as I can tell, you still get some function coloring. If you make a function parameter unique, then you might have to track down all calls to the function and ensure the uniqueness of the argument, potentially making more parameters unique or exclusive. If they manage to infer these modes, though, it's gonna be huge.
html is faster
based
It can't render what it can't parse, so the error handling for it is blazingly fast!
ocaml btw
Now things are coming full circle, rust's memory management is based on research on region-based memory management that was done as a ML dialect, back in 1995.
If Prime and TJ would kiss in the mouth their facial hair wouldn't touch. It's like they complete each other, and a van dyke (beard.)
HUHH
@@teej_dv that came outta nowhere
Wow you know I’m only a little interested in rust but I’ve always wanted to try a taste of the functional koolaid. I think I will join you for Advent of Code this year in OCaml
Same here
Did you try out OCaml?
So what's more complicated: explicit borrowing and explicit lifetimes, or a hundred modifiers? It's a tradeoff I guess but now I appreciate Rust more. Also: F# is awesome and they should incorporate some of the new OCaml stuff.
GC + Mem. Arena is all I need.
I'm noob though so I really like go.
@@muhwyndham yeah, Arenas are a great idea. I'm not a fan of how imperative Go is but it's a very cool language.
"It runs and maybe like someone makes money off of it" 🔥
While i understand your issues with:
- coloring
- futures being lazy
- ownership & lifetimes
I personally do like the explicitness everywhere in Rust.
Futures running before i tell them to are a headache for me. I like working with lifetimes and ownership. And i don't mind having colored async functions when they e.g. use async internally since it gives me a heads-up for what is happening "down below". Though the situation with multiple runtimes and tokio being a de-facto standard hurts me - i prefer zigs way of providing the async runtime.
Love your content! I'm regularly learning a lot from you. Your opinion on topics is a valuable factor in quite a few decisions i have to make in my job & personal projects.
Thank you Prime!
The concept of lifetimes is good in principle, but the explosions of lifetime required errors you get when you add one anywhere is truly brutal. It's the main area Rust needs improvement. What if the compiler could just keep trying different lifetime requirements until the code worked, maybe putting up a warning if one of your variables needed a static lifetime as a result so you're not eating too much memory.
Lifetimes are just handled as a total pain in the ass. Like if I create a struct containing a reference, it forces me to put a lifetime just to tell it that the struct's lifetime has to be shorter than the reference's lifetime, so it can't hold a dead reference. This is 100% a thing the compiler should be able to figure out on its own.
@@taragnorSure, but what if your struct has two or more references? Do they have the same lifetime or different ones? Also he is saying that Rust's "fearless concurrency is just Arc> which is not true. Rust's fearless concurrency are Send and Sync traits (possibly other mechanism's too, not a Rust expert) by which Rust can check at a compile time that you wont have data races.
@@maniacZesci you are correct with Arc not being the only option. There are for example multiple channel implementations within the tokio::sync module and within the crossbeam crate which i have used. The choice between those depends on if the project is async or not. As opposed to golang we get specialized channel implementations for different use cases (e.g. mpsc, mpmc, oneshot).
@@maniacZesci The rust complier can already tell if you have lifetime problems, that's part of what makes it so good at spotting errors. All I'm saying is that it could just fill in a lifetime that makes your code work. Essentially just try a few different lifetimes to see if the code compiles, and if it only works with a static lifetime then give a compiler warning. I understand if you're writing some code for a library, you'd probably still have to do them yourself, because you don't have all the code, but if you're writing a complete executable, the Rust compiler has all the code and a complete picture of the program. If there exists a set of lifetimes that work for that program, it should just be able to auto fill them in in a way that eliminates the compilation error (assuming your program isn't doing anything totally unsound that'd make that it impossible to set a lifetime).
@@remissio42 also atomic types with Ordering enum for lock-free concurrency but those are not simple to use.
I love OCaml-users who think OCaml has more industry adoption than Haskell, its cute really. Especially since it only requires a 15 second google to find out that the financial industry has an order of magnitude more adoption of Haskell. Which is hilarious in and of itself, because that means that 10 companies use Haskell. Rust, which hasn't even been around half as long as either, has more adoption. That's a sad state of affairs. 😅
wasn't rust originally written in ocaml?
Yes it was
@@protosevn the compiler was, yes
11:06 isn't that the point of implicit Copy in Rust though?! Where if it's trivial to copy it'll just do that? To me the whole point is that in Rust you might need to be verbose all the time, but if too much stuff is opt-in someone is bound to mess it up and you're left with the same problems again.
Funny they say TJ might actually build something that’s gets to production using OCaml yet Rust’s compiler was first written in OCaml.
Firstly OCaml for AOC2023 FTW!
This is a healthy language competition, just like antimonopoly in business, both are learning from each other and evolve to higher level. Which, the OCaml wasn't that low level to begin with.
Are they both eventually going to evolve into Haskell? 😂
When I see this type of stuff, I wonder why F# is never mentioned?
Because Prime hates Microsoft
F# is the perfect balance between functional and object oriented... I think if it wasn't maintained by Microsoft it would have been more popular.
More like F Shart. Gottem
Exceptions in FP, what a tragedy.
Because he hates Microsoft so much but still relies on windows for streaming, typescript for work, and GitHub for SCM.
There is no logical sense here.
I like the statement of "Does this mean i don't have to go and put lifetimes everywhere?"
I'm pretty sure that's wrong: If you run into a situation where you would need a lifetime (a function returning a reference) you just can't do it.
At least that's how i understand it. More like C++ references maybe.
This looks a lot like reference capabilities in Pony.
That’s developed by Ginuwine, right?
I probably will never use OCaml again, but its cool that a newer gen is refactoring OCaml.
It's going to end up being Haskell.
1:00 I don't really get what people are talking about. I literally never use clone and I don't see how it would help in many situations. A &mut is all you need 90% the time anyway.
I feel the same way. If you use clone a lot you should rethink the architecture of your program. You can get away with &mut fn parameters passing stuff around just fine. The same with the whole "Arc" and "
Have you ever played with ReasonML? It seems more approachable, does it share the same features? It's built on top of ocaml, right?
Reasonml I was a mess. Now I think it's just called re-script which is fine I suppose but it leans very heavily into the JavaScript syntax which is not easier.
It's not just OCaml, even the new wannabe Python superset called Mojo is implementing Rust-like ownership. I don't know who in the Python community would actually want that.
Those who value safety
I know it's such a meme by now that it will never happen... but watching videos where you talk about clever stuff in OCaml makes me think you would really enjoy Haskell...
He would if he didn't have his head up his a** lmao
One day maybe...
You should look at Haskell's linear types 👀
These Haskell jokes are funny because we all know Haskell practically lives out of financial industry right? From Standard Chartered to the Cardano.
you guys talk about 'running' programs being some niche thing to haskell programmers... I have it on good authority that there is a subsect of hasklnauts that don't care about compilation at all beyond type checking. If it typechecks, some angel gets a bonus and stock options. Linting would probably get them 99% of the way to completion.
BIG IF TRUE
“Colored structs”? There is no such thing as lifetimes ARE part of the type!
I'm curious how this feature will work with partial application. Then again, if locality was an old one, that might have been handled
How does this mode work with relation to the type inference? You mention it is completely separate, so I'd assume that overloads are not a thing?
One could imagine two definitions of map - A fast one that takes advantage of exclusiveness ( when given ) , and a default one. As I understand, the compiler would not be able to correctly dispatch to the best one?
If the compiler is able to do pattern matching when no argument is given, I’m sure it can compile into a similar kind of backtracking automata or decision tree as that case when handling the case when the type mode is specified or not. I could be wrong though. Interesting question and I hope somebody has a better answer!
jane st interns make me feel so worthless and insignificant
Everybody gangster until &'c
CHROOT
WTF is oxidizing means in this context? Chemically combining with oxygen = oxidizing.
It's rusting, as in it's borrowing ideas from rust.
Lets say hi to RON here as well. Hiiiiiiiiiiiiii
Prime went from turning me onto rust to turning me off pretty quick lol.
Apparently Prime used to not like Rust
Honestly I think that is because he does web stuff mostly. I/O bound issues mean you're kinda forced into using Tokio and the path of least resistance is always cloning or Arc'ing everything which become frustrating very quickly. Rust is very good if you plan beforehand. If you just want to get in and code away making stuff up as you go along it's rough for any medium complexity issue.
How about making up your own mind, instead of being influenced by some youtuber like that?
OCaml is much older than Rust, it's funny, how people consider it borrowing.
if the concepts dont exist in Ocaml, then is borrowing
OCaml is older, but these `local` and `unique` modes are new extensions of it that afaik are not (and may never be) in the language. Rust on the other hand had ownership from the start.
Can I do grpc and graphql in ocaml?
Its not faster so its unique point should be simplicity..
OCaml ❤
ST monad?
I so want to dunk on prime for being borderline illiterate when reading out loud, except I do the same damn thing :(
10/10 would agree
he’s dyslexic
Hi Ron
Regarding the opt-in mutability thing in Rust: you can't call it a variable if it isn't variable -- if everything is immutable, then nothing varies, so it ultimately isn't actually a variable. Perhaps "symbol" would be a better term, but then you'll get the attention of the Lispers.
PHP is faster
why Ocaml always compare it to Rust ??? is that rust fork ?
Ocaml is kinda faster. Read somewhere it hovers around top 10. Its older than rust, but got many of features of newer languages. Imagine a language from 90s with package manager like rust. But don't know much beyond it though.
also first rust compiler was written in ocaml
@@NC-nc3gsOCaml is definitely, not remotely, even closely, faster than Rust or any of the C/C++ like languages when considering base line usage.
There is plenty of simple/stupid benchmarking examples you can Google for and OCaml falls massively, several orders of magnitude in certain cases behind.
Now, I know benchmarks like those should always be taken with a grain of salt, but it goes to show that no, OCaml can not be claimed to be faster than Rust.
@@simonfarre4907no one said it's as fast as rust but it is one of the fastest languages out there and I'd argue for the amount of abstraction ocaml has it is the fastest.
@@47bytes It is outperformed by c, c++, Rust, zig, d to name a few. I'm sure there are more.
Python is OP 🔥
Python is so trash it always have a global lock with it
No
@@stevefan8283gil is getting removed
Python is Obvious Pain (that makes you suffer in hell fire)