for loop should *maybe* return `null`
This is R's behavior:
> x <- for(i in 1:10) i
> x
NULL
This the behavior in the re-implementation:
> x <- for (i in 1:10) i
[1] 10
> x
[1] 10
>
I guess nobody uses the return values of for loops anyway, but I think it is more intuitive for for loops to return null instead of the last evaluation in the last iteration.
Yeah, this was intentional, but up for debate if you see some undesirable effects. Although it's not really a stated philosophical pillar of the project, I guess the underlying philosophy here is "anything is more useful than nothing".
We're always returning something (sometimes NULL, but always something), so given the choice between something possibly useful and NULL, we should prefer anything if it brings even marginally more utility. We see this in other keywords like if () else , in base functions like you found with print, and I'd say it's generally a good idea in user-provided functions as well.
If we hit the point where it has detrimental performance ramifications, then I think we can revisit this philosophy. For now I think this approach adds some nice consistency to the language.
So the (minor) detrimental side effect that made me create this issue was the printing in the repl. With the current implementation, loops like
for (i in 1:10) {
print(i)
}
will print the last value twice when executed in the repl.
While this is not a problem in the example above, where it is relatively clear from the code what is going on, I think that it can be a little tricky when using for loops for debugging, where it is not clear which values are being printed. If one is not aware of this behaviour, one might think that the last value was actually printed twice explicitly ( in the last two iterations), causing some wrong beliefs about the values that were printed.
Still, I think the return something where possible philosophy seems like a good guideline! :)
That's a good use case to keep in mind. I think we should stick with the current approach for now, and we can figure out how problematic it is.
I think the ideal long-term solution is to have print return "invisibly" as mentioned in https://github.com/dgkf/R/issues/80#issuecomment-1975016332 - that is, not with a special internal visibility, but rather with a wrapping class that has a custom, no-output print method.
In this style we avoid all the complexity of managing visibility as an internal language construct while still letting functions like print return something useful and not display when returned.
A lot of features need to be in place before this can happen - we need generics, classes and dispatch, but it seems like the best long-term solution.
If a for-loop returns something than I think it would be natural to support break <value> to specify what to return when exiting early, just like in Rust.
If a for-loop returns something than I think it would be natural to support break
to specify what to return when exiting early, just like in Rust.
I like that! (And also didn't realize you could do that in rust!)