swarm-game / swarm

Resource gathering + programming game
Other
834 stars 52 forks source link

Consider alternative name for `return` #700

Open byorgey opened 1 year ago

byorgey commented 1 year ago

People coming from an imperative programming background might be confused by return. For example, they might be confused by the fact that move; return (); move does not ignore the second move; they might be confused by the need for return in code like if foo {grab; return ()} {}; etc. Some options for improving the situation include:

We should also give some thought to how we explain it in the tutorials and other documentation.

byorgey commented 1 year ago

Some relevant IRC discussion which did not come to any concrete conclusions:

(09:25) <    xsebek> byorgey why not? I'm not sure non-functional folk will appreciate the miracle of "lifting pure values into the command monad" 😆
(09:31) <    xsebek> If we wanted to make this systematic, we could have nodiscard : cmd a -> cmd a, which works like id, except it warns when the command result is not bound
13:34) <    xsebek> (on a second thought let's not try nodiscard, that would be complicated)
(13:36) <   byorgey> agreed =)
(13:37) <    xsebek> but I think just doing something for return would be OK, it's the one thing that is very different from non-functional languages
(13:38) <   byorgey> I'm just opposed to adding special cases for things on principle, it can make things nice when it works but inevitably it doesn't quite work out and then it's just more confusing.
(13:38) <    xsebek> Agreed, but in this case how would this special case generalize?
(13:38) <   byorgey> I do think we should at least rename 'return', though
(13:39) <   byorgey> Honestly I've forgotten exactly what special case we were contemplating and why
(13:39) <    xsebek> :D
(13:40) <    xsebek> We were talking about why return (); grab does not do what imperative programmers might expect
(13:42) <    xsebek> I actually like return in swarm - it's nice that it looks a little like imperative program, but showcases functional/strongly typed ideas
(13:44) <    xsebek> calling it lift/pure would IMO make it hard to read to anyone except people from haskell
(13:45) <   byorgey> I like that it showcases functional/ strongly typed ideas.  But I'm not sure it's nice that it looks familiar to imperative programmers, because in fact it is completely different.  So it's just misleading.
(13:45) <   byorgey> I agree, I don't think we should call it lift or pure
(13:47) <    xsebek> Well, if we warn them "Statements after return cause the return to be ignored", then I think that its ok
(13:48) <   byorgey> Hmm... I'm not convinced that's a helpful way to explain it though
(13:48) <    xsebek> I would say it is not completely different - its just doing only the pure half, while in imperative world it *also* breaks control flow
(13:49) <    xsebek> Showcasing the pure half is IMO worth a little confusion
(13:50) <   byorgey> But in imperative world it is tied to the output of a function/procedure, and in monad world it's nothing of the sort
(13:50) <    xsebek> Procedure is just a monad 😎
(13:52) <   byorgey> how would you explain `if foo {grab; return ()} {}; move`?  why doesn't the move "cause the return to be ignored"?
(13:53) <    xsebek> because inside the {} there is cmd (), which is the procedure where return gives the value
(13:54) <    xsebek> If that is the only weird and common example, I think we should improve that - it annoys me to write that and I can not easily import some Prelude with grab_
(13:55) <   byorgey> I mean, sure, we should improve that, but I think it's a separate issue.
(13:56) <    xsebek> Another thing to consider is how soon will players run into this?
(13:56) <   byorgey> I think what I'm trying to say is that although imperative return and monastic return may bear a slight similarity, emphasizing the similarity is going to confuse imperative programmers more than it helps them.
(13:57) <   byorgey> But I cannot prove that, it is only an intuition based on my experience teaching haskell.
(13:57) <   byorgey> and that's "monadic" return, of course =)
kostmo commented 1 year ago

In exploring the space of alternative names for return:

Personally, I'm inclined toward an extant English verb or adjective. In particular, I think the word wrap is a

that is semantically well-aligned.

xsebek commented 1 year ago

I would keep it simple:


The problem with wrap is that from the player's perspective, there is nothing wrapping values in cmd.

Commonly wrap is used for a function that:

Wraps the single paragraph in text (a string) so every line is at most width characters long.

Python textwrap.wrap


If we wanted to change this keyword based on teaching experience from Haskell, I think it would be reasonable to do the same thing as Haskell eventually did and name it pure.

The only problem with return is that it means something else in imperative languages.

I do not care about that, because I want to show Swarm to people who either did not learn to program yet or they already know some functional language. Neither of these groups will be surprised by return behaviour, so changing the name does not bring any benefit to me. It will only be a slight annoyance since I got accustomed to return.

If we want to cater to imperative programmers, we can do s/return/pure/g right now. Let's not waste time bikeshedding names for that here, since Haskellers already spent a lot of thought on that.

Once we have the return keyword free, we can consider implementing an imperative style return command that returns to the outer scope that is delimited somehow (program/routine/imperativeCodeThatCanReturn?).


As for ergonomics, I think the really confusing thing in Swarm is the need for return () in almost every if. Even if we go with pure or something else, this is something we should improve.

byorgey commented 1 year ago

I do not care about that, because I want to show Swarm to people who either did not learn to program yet or they already know some functional language.

Personally, I actually do want to show Swarm to people who already know how to program but have never seen a functional language. For example, I am planning to use it somehow in my Programming Languages class this spring. Many of the students will know Java and Python; a few might know Haskell or Rust but most will not.

In general, I think return is simply a bad name for a function of type a -> cmd a; I think it was a bad name in Haskell too. I think the only good reason for using it is that some people are already familiar with it from Haskell, but most of those will be familiar with pure as well.

I think the really confusing thing in Swarm is the need for return () in almost every if. Even if we go with pure or something else, this is something we should improve.

I think a big part of why this is confusing is that initially, you are mostly using imperative features of the language, but Swarm does not have if statements, only if expressions. So perhaps one way to make this less confusing would be to provide a special if statement, like ifDo : bool -> {cmd a} -> {cmd b} -> cmd unit (ifDo is not a good name but I couldn't come up with anything better). But then again this is easy to implement given the usual if : bool -> {a} -> {a} -> a.