Skip to content

Comment on The Wake Programming Language

Comments

I'm not sure I like the closure syntax, with the explicit return. Most modern languages (Swift, Rust, Python (lambdas), Lisp if I can call it modern) support implicit returns and it looks much better. Maybe it's just the juxtaposition with the JS code, but I was confused for a second by the word "return" inside the closure, thinking that it returned from the original function with just the first result.

(I really like Rust's take on this with the semicolons—just leave off the semicolon to return—it makes the semicolon actually useful.)

Thanks! Great comment, I'd planned on adding implicit returns, and may copy rust on that one!

Arbitrary two cents: Rust's approach to this bothers me a lot. A missing semicolon having such a weighty meaning strikes me as one of the worst warts to survive Rust's rapid evolution. It forces you to scan very carefully to determine outputs.

The rule only applies at the ends of blocks/functions. The semicolon can only be omitted on trailing expressions. And, when it's omitted, the block/function takes on the value of that trailing expression. E.g. this is not valid Rust:

  fn foo(x: bool) -> i32 {
      if x { 
          1 // no semicolon on the 1
      }

      let a = 2 + 3;
      return a * 4;
  }
It's not implicitly returning the 1 from `foo`. An early return would need to be written `if x { return 1 }`. On the other hand, the `return a * 4;` could just be written `a * 4` since it's at the end of the function.

This rule means the scanning required is just looking at the end of the function.

In any case, having a static type system means I have never personally encountered a bug caused by this sort of implicit return in Rust.

I can imagine so; But as a counterpoint, isn't it worse with forced implicit returns, where you never have a choice but to return something, and you have to scan the code carefully to see if it was required?

Maybe I'll add a 'noreturn' keyword; single expresions are automatically returned, and you can use a 'noreturn' statement to explicitly return void despite running a non-void expression.

Sadly I don't really have a perfect answer to that. I'm inclined to think making all returns explicit is the right choice, and is only really a problem in a language where long returns are common (specifically in my mind is ruby, where being able to return from the enclosing function is crucial to the common uses of blocks). Arguments against in languages that don't feature this sort of thing seem to be against the length/weight of the word return.

Something I've played with in languages I've worked on is named returns [1], which I like for that case.

[1] https://github.com/stormbrew/channel9/blob/master/sample/c9s... -- see the get function definition, '-> return' names the return 'channel' and 'return <- val' calls it (which returns). Now I might consider having an implicit '<- val' with no lhs that calls the current function's return, I think.

I do think a special case for single statements makes sense, though.

Yeah, I wonder why Rust needs to have statements at all--why can't it just have "everything is an expression" semantics?

Why aren't declaration statements in Rust just expressions that evaluate to the value being bound to the name being declared?

Would this mess up Rust's type checker somehow?

Most functions in Rust return, so you can count on the last expression to be returned the vast majority of the time.

Which begs the question, why even have the trick of the missing semicolon in that case? Why rely on one missing 5 pixel character to say that "this function defies your expectations"?

If it's not the norm, I'd rather have an explicit "nil" or something at the end.

The trick is that now the keyword return marks an early return. And as early returns are often exceptional, I find the added visibility nice. On the other hand, every function in Rust, except those that contain an infinite loop, returns something so the keyword at the end of the function body is redundant in my opinion.

Also, because function signatures are never infered in Rust, mistakenly adding or forgetting the last semicolon will always result in a type error.

Well, if you add a semi-colon where it's not supposed to be you'll get a compile error. If you omit a semi-colon, you'll also get a compile error. They're just there to separate statements (Rust is not whitespace-sensitive).

The most common pattern in my Rust code is:

`statement; statement; expression` where the expression is what I actually want to return from this function

it seems more noisy to say `statement; statement; return expression;`

It'd be `()` and make it so that every side effecting function would be at minimum two lines long, and be a visible wart. It's pretty easy to tell that if the function returns something, the last line evaluates to that expression even if there's no `return` since if it didn't, it wouldn't compile (or there'd be a dead code warning).

I hate implicit returns and don't even want them to be possible. A return is a major event. It's clearly a matter of taste.

To me there is nothing major about a function returning. Every function does that. Implicit early returns on the other hand could be deceiving, but I don't know any languages that would support those.

Agreed that it's a matter of taste. After working with Ruby and Clojure I don't even want statements or void functions to be a thing. I prefer the "everything is an expression" paradigm.

AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.