[ $davids.sh ] — david shekunts blog

🦀Farted on Rust v0.1 🦀

# [ $davids.sh ] · message #201

🦀Farted on Rust v0.1 🦀

7 times measure, one time return

#whyrustwhy

  • @ [ $davids.sh ] · # 802

    !DISCLAIMER! Syntax is a matter of taste and you can get used to any of it. With these posts, I don't want to complain, but I want someone to explain "why the hell?" to me.

    **Why the hell implicit return?

    **You don't have to declare return, then the last line of the function's logical branch will be returned.

    Okay, let's assume this is done in Haskell, but there it's justified by the fact that in pure functional programming, most functions are practically compositions of other functions or one-liners, so for the sake of syntactic beauty, you can omit return.

    But Rust is not a purely functional language, it's much more procedural than Haskell, so there will be a bunch of if ... else ..., while, etc., and figuring out what is actually returned is a fucking pain.

    **Why the hell does implicit return break on ;?

    **And this one really blew my mind... If you put a ; at the end of the last line, it won't be considered a hidden return....

    So, you fucking give the ability to return the last line without the word return, but if you put ;, then you can't??? And to fix this, you either have to add return or remove ;???

    What kind of bullshit is this, what possible use case could there be for this? Why is this feature in the language?

    Why not just make return mandatory and not create 1000 ways to return? No one will break in half if they have to write return.

    At most, you could do like in JS with an arrow function without parentheses to return the first line immediately.

    I HOPE this is just me starting out and not seeing the benefit of this, but at first glance, it's purely a Rust invention for reasons I don't understand yet.

    And God forbid you say there's a linter for this where you can disable it, because that's purely the Node.js path, which will lead to a very bad future.

  • @ Artur G · # 807

    Awesome feature! Explicit returns are evil! 😁

  • @ [ $davids.sh ] · # 808

    No, no, no, seriously, it's not the same as in functional programming (because there it's justified and necessary), but in Rust you'll have a lot of procedural code (if... else..., loop, variable assignments, and so on) and to find where the return is, you need to find the line that is (1) the last in the logical chain, (2) and also, damn it, without a semicolon.

    Finding such a thing visually in procedural code is very tough.

  • @ [ $davids.sh ] · # 812

    HAHAHAHAHA this is code (purely for visualization example) that will compile, tell me where and what will be returned?

  • @ Artur G · # 813

    Shouldn't you declare a variable and store the final value in it, and then return it at the end?

    Isn't it bad to have many exit points?

  • @ [ $davids.sh ] · # 814

    Moreover, I've already described above how it works, and understanding it will be a problem. If you don't know what I wrote above and know ANY other programming language, you'll never figure out what this garbage is.

  • @ [ $davids.sh ] · # 816

    This can only work well with monads and paths (I don't remember what it's called, but I mean functional branching that will call a function only if you get Left / Ok and skip everything until the branch where Right / Err is handled).

    When you explicitly write if ... else ... people will use many exit points, otherwise the code will turn into a giant boilerplate.

  • @ [ $davids.sh ] · # 821

    I've just found an example in pattern matching that answers the "why" quite well, but wouldn't it have been simpler to have a syntax option (e.g., a colon after the predicate) that allows returning a single line without using return?

  • @ Artur G · # 823

    It seems like Rust has an analog to monads.

    In any case, I think multiple exit points are also not a great idea.

    And Rail-way is just right.

  • @ [ $davids.sh ] · # 825

    Yes, they have something like monads implemented using enums (Ok / Err for example).

    Railway is definitely a cool thing, but only when you're working on a team that also thinks so.

  • @ Artur G · # 826

    So here it is, a monad. 😁

  • @ [ $davids.sh ] · # 827

    Yes, that's how it is, but look at what it's wrapped in: if ... else ...

    Undoubtedly, a person could have used match as well, but this is another example where procedural programming is starting to be added to functional programming.

    It would be even worse if there wasn't an else ... at the end, then it would be completely unreadable.

    And when exiting this function, there might be another if ... else ... scope, and we're again trying to comprehend: "Where is the exit here?"

  • @ Artur G · # 830

    You are wrong.

    This is precisely the trend of "monads in ordinary code," without special syntax.

    Everyone is striving for this now.

  • @ [ $davids.sh ] · # 831

    Okay, then let's phrase the question like this: what other languages that are NOT purely functional implement such an implicit return?

  • @ [ $davids.sh ] · # 832

    So I'm not just "not against it," I'm actually FOR it. It bothers me that a billion non-obvious ways to return something from a function are appearing, when the code is saturated with procedural style.

  • @ Artur G · # 833

    So it's a language for the masses, like PHP. 😂

  • @ [ $davids.sh ] · # 834

    But there is a language that has removed absolutely everything from itself and has become one of the most popular absolutely all over the world and remains so (and anyone reading this comment knows which language I'm talking about)

  • @ Artur G · # 835

    Yeah, a language for shuffling bytes. 🙈

    But people need abstractions, not bytes.

  • @ Dmitrii Rust Demenev · # 836

    implicit return is beneficial, as the function definition then becomes syntactically similar to a block returning a value

    rust // Here is an immutable value let obj = { // In this small piece of code, the name b exists let mut b = ObjBuilder::new(); // ... b.build() };

  • @ [ $davids.sh ] · # 837

    But I constantly argue against abstractions, and the byte-passing language ultimately proved to the world that they are not needed (generics were able to be knocked out, this is useful, they will also add union types and pattern matching, and I won't get off it until memory management is needed).

  • @ [ $davids.sh ] · # 838

    Oh, thanks for the example!

    Here's the same thing in TS:

    let obj: SomeType;
    {
      // The name b exists in this small piece of code
      let mut b = ObjBuilder::new();
      // ...
      obj = b.build()
    }
    
    Thanks to {}, you can create a separate scope so that variables don't "leak" out of it.
    
    Yes, you'll have to declare the type in advance and make the variable empty, BUT the compiler can calmly check whether the variable will be filled or not, so you don't run into nil-pointer issues later.
    
  • @ [ $davids.sh ] · # 839

    This is what I mean: how much more convenient is the Rust option compared to a more obvious (due to explicit assignment) example in TS, which will also be safe at compile time?

  • @ Le Gouch · # 854

    This is another way to do it

  • @ Le Gouch · # 855

    No language will protect you from shitty code

  • @ [ $davids.sh ] · # 856

    I don't argue, my code is intentionally "ugly" and it can be refactored more beautifully, but that's the point: you'll have to work with a tired / junior / bad developer who will be able to write such code

    • this refactoring, in my opinion, is more about ternary operators than implicit return

    That is, the first photo is pseudocode, and the second is its Go equivalent, which has more boilerplate, but also more clarity IMHO

  • @ [ $davids.sh ] · # 858

    This looks nicer

  • @ [ $davids.sh ] · # 859

    100%, but it can reduce the likelihood of spaghetti code, and for that, clear boundaries are needed.

    For example (sorry for using it so often, but I truly believe it's done excellently there), Go, which removed all the magic, left the strictest minimum, and thereby in 90% of cases, you don't have the option to "solve the same thing in different ways"; there's specifically one way.

  • @ [ $davids.sh ] · # 860

    Sorry, of course, it should be written like this in Go, and it became even more readable

  • @ Nikita · # 861

    I'd say it looks awesome

  • @ [ $davids.sh ] · # 862

    Yes, but how difficult is it compared to what actually needs to be done?

    When you work with really large codebases, you'll understand how tired you'll get of realizing every time, "what did this idiot want to write?" – and the funniest thing is that often you'll end up being that idiot yourself, I speak from experience))

  • @ [ $davids.sh ] · # 863

    And here, there's nothing to realize, everything is on the surface, read the lines and do what you have to do.

  • @ Le Gouch · # 864

    zig removed all the magic, I recommend trying it, and there's only one path there - the one indicated by comrade Andrew

  • @ [ $davids.sh ] · # 866

    And in the first post I'm saying that I love Zig, but it's raw))