232

A while back I got rebuked by Simon Urbanek from the R core team (I believe) for recommending a user to explicitly calling return at the end of a function (his comment was deleted though):

foo = function() {
  return(value)
}

instead he recommended:

foo = function() {
  value
}

Probably in a situation like this it is required:

foo = function() {
 if(a) {
   return(a)
 } else {
   return(b)
 }
}

His comment shed some light on why not calling return unless strictly needed is a good thing, but this was deleted.

My question is: Why is not calling return faster or better, and thus preferable?

Community
  • 1
  • 1
Paul Hiemstra
  • 59,984
  • 12
  • 142
  • 149
  • 13
    `return` is unnecessary even in the last example. Removing `return` may make it faster a little, but in my view this is because R is said to be a funcional programing language. – kohske Jul 31 '12 at 13:07
  • 5
    @kohske Could you expand your comment into an answer, including more details about why it is faster, and how this is related to R being a functional programming language? – Paul Hiemstra Jul 31 '12 at 13:13
  • 2
    `return` induces non-local jump, and the explicit non-local jump is unusual for FP. Actually, for example, scheme does not have `return`. I think my comments are too short (and maybe incorrect) as an answer. – kohske Jul 31 '12 at 13:23
  • 2
    F# doesn't have `return`, `break`, `continue` either, which is tedious sometimes. – colinfang Aug 27 '13 at 12:17

9 Answers9

151

Question was: Why is not (explicitly) calling return faster or better, and thus preferable?

There is no statement in R documentation making such an assumption.
The main page ?'function' says:

function( arglist ) expr
return(value)

Is it faster without calling return?

Both function() and return() are primitive functions and the function() itself returns last evaluated value even without including return() function.

Calling return() as .Primitive('return') with that last value as an argument will do the same job but needs one call more. So that this (often) unnecessary .Primitive('return') call can draw additional resources. Simple measurement however shows that the resulting difference is very small and thus can not be the reason for not using explicit return. The following plot is created from data selected this way:

bench_nor2 <- function(x,repeats) { system.time(rep(
# without explicit return
(function(x) vector(length=x,mode="numeric"))(x)
,repeats)) }

bench_ret2 <- function(x,repeats) { system.time(rep(
# with explicit return
(function(x) return(vector(length=x,mode="numeric")))(x)
,repeats)) }

maxlen <- 1000
reps <- 10000
along <- seq(from=1,to=maxlen,by=5)
ret <- sapply(along,FUN=bench_ret2,repeats=reps)
nor <- sapply(along,FUN=bench_nor2,repeats=reps)
res <- data.frame(N=along,ELAPSED_RET=ret["elapsed",],ELAPSED_NOR=nor["elapsed",])

# res object is then visualized
# R version 2.15

Function elapsed time comparison

The picture above may slightly difffer on your platform. Based on measured data, the size of returned object is not causing any difference, the number of repeats (even if scaled up) makes just a very small difference, which in real word with real data and real algorithm could not be counted or make your script run faster.

Is it better without calling return?

Return is good tool for clearly designing "leaves" of code where the routine should end, jump out of the function and return value.

# here without calling .Primitive('return')
> (function() {10;20;30;40})()
[1] 40
# here with .Primitive('return')
> (function() {10;20;30;40;return(40)})()
[1] 40
# here return terminates flow
> (function() {10;20;return();30;40})()
NULL
> (function() {10;20;return(25);30;40})()
[1] 25
> 

It depends on strategy and programming style of the programmer what style he use, he can use no return() as it is not required.

R core programmers uses both approaches ie. with and without explicit return() as it is possible to find in sources of 'base' functions.

Many times only return() is used (no argument) returning NULL in cases to conditially stop the function.

It is not clear if it is better or not as standard user or analyst using R can not see the real difference.

My opinion is that the question should be: Is there any danger in using explicit return coming from R implementation?

Or, maybe better, user writing function code should always ask: What is the effect in not using explicit return (or placing object to be returned as last leaf of code branch) in the function code?

micstr
  • 5,080
  • 8
  • 48
  • 76
Petr Matousu
  • 3,120
  • 1
  • 20
  • 32
  • 6
    Thanks for a very good answer. I believe there is no danger in using `return`, and it comes down to the preference of the programmer whether or not to use it. – Paul Hiemstra Aug 13 '12 at 08:59
  • 53
    The speed of `return` is really the last thing you should be worrying about. – hadley Oct 02 '14 at 13:58
  • 2
    I think this is a bad answer. The reasons come down to a fundamental disagreement of the value of using unnecessary `return` function calls. The question you *should* ask isn’t the one you propose at the end. Instead, it’s: “why *should* I use a redundant `return`? Which benefit does it provide?” As it turns out, the answer is “not much”, or even “none whatsoever”. Your reply fails to appreciate this. – Konrad Rudolph Mar 29 '17 at 09:44
  • @KonradRudolph ... you repeated actually what Paul was originally asking (why explicit return is bad). And I would like to know right (the one right for anyone) answer as well :). Do you consider to provide your explanation for users of this site? – Petr Matousu Mar 30 '17 at 08:53
  • @PetrMatousu No, I didn’t repeat that question, I’m (effectively) saying that it’s the wrong question to ask because it inverts the burden of proof, so to speak. I’m saying that the right question to ask is the opposite question. And I also gave an answer to *that* question: using unnecessary `return` has no benefit. – Konrad Rudolph Mar 30 '17 at 08:55
  • @KonradRudolph Some would argue that being explicit in your code is a benefit. – Dason Apr 17 '17 at 13:18
  • 2
    @Dason I’ve elsewhere linked a Reddit post explaining why this argument is flawed in this context. Unfortunately the comment seems to get automatically removed every time. The short version is that `return` is like an explicit comment that says “increment x by 1”, next to a piece of code doing `x = x + 2`. In other words, its explicitness is (a) utterly irrelevant, and (b) it conveys the *wrong* information. Because `return`’s semantics in R are, purely, “abort this function”. It does *not* mean the same as `return` in other languages. – Konrad Rudolph Apr 17 '17 at 13:37
114

If everyone agrees that

  1. return is not necessary at the end of a function's body
  2. not using return is marginally faster (according to @Alan's test, 4.3 microseconds versus 5.1)

should we all stop using return at the end of a function? I certainly won't, and I'd like to explain why. I hope to hear if other people share my opinion. And I apologize if it is not a straight answer to the OP, but more like a long subjective comment.

My main problem with not using return is that, as Paul pointed out, there are other places in a function's body where you may need it. And if you are forced to use return somewhere in the middle of your function, why not make all return statements explicit? I hate being inconsistent. Also I think the code reads better; one can scan the function and easily see all exit points and values.

Paul used this example:

foo = function() {
 if(a) {
   return(a)
 } else {
   return(b)
 }
}

Unfortunately, one could point out that it can easily be rewritten as:

foo = function() {
 if(a) {
   output <- a
 } else {
   output <- b
 }
output
}

The latter version even conforms with some programming coding standards that advocate one return statement per function. I think a better example could have been:

bar <- function() {
   while (a) {
      do_stuff
      for (b) {
         do_stuff
         if (c) return(1)
         for (d) {
            do_stuff
            if (e) return(2)
         }
      }
   }
   return(3)
}

This would be much harder to rewrite using a single return statement: it would need multiple breaks and an intricate system of boolean variables for propagating them. All this to say that the single return rule does not play well with R. So if you are going to need to use return in some places of your function's body, why not be consistent and use it everywhere?

I don't think the speed argument is a valid one. A 0.8 microsecond difference is nothing when you start looking at functions that actually do something. The last thing I can see is that it is less typing but hey, I'm not lazy.

flodel
  • 87,577
  • 21
  • 185
  • 223
  • 8
    +1, there is a clear need for the `return` statement in some cases, as @flodel showed. Alternatively, there are situations where a return statement is best omitted, e.g. lots and lots of small function calls. In all other, say 95%, of the cases it does not really matter if one uses `return` or not, and it comes down to preference. I like using return as it is more explicit in what you mean, thus more readable. Maybe this discussion is akin to `<-` vs `=`? – Paul Hiemstra Aug 10 '12 at 08:45
  • 8
    This is treating R as an imperative programming language, which it is not: it’s a functional programming language. Functional programming simply works differently, and using `return` to return a value is nonsensical, on par with writing `if (x == TRUE)` instead of `if (x)`. – Konrad Rudolph Jun 20 '14 at 18:02
  • 5
    You also rewrite `foo` as `foo <- function(x) if (a) a else b` (with linebreaks as needed). No need for explicit return or intermediate value. – hadley Oct 02 '14 at 13:57
30

This is an interesting discussion. I think that @flodel's example is excellent. However, I think it illustrates my point (and @koshke mentions this in a comment) that return makes sense when you use an imperative instead of a functional coding style.

Not to belabour the point, but I would have rewritten foo like this:

foo = function() ifelse(a,a,b)

A functional style avoids state changes, like storing the value of output. In this style, return is out of place; foo looks more like a mathematical function.

I agree with @flodel: using an intricate system of boolean variables in bar would be less clear, and pointless when you have return. What makes bar so amenable to return statements is that it is written in an imperative style. Indeed, the boolean variables represent the "state" changes avoided in a functional style.

It is really difficult to rewrite bar in functional style, because it is just pseudocode, but the idea is something like this:

e_func <- function() do_stuff
d_func <- function() ifelse(any(sapply(seq(d),e_func)),2,3)
b_func <- function() {
  do_stuff
  ifelse(c,1,sapply(seq(b),d_func))
}

bar <- function () {
   do_stuff
   sapply(seq(a),b_func) # Not exactly correct, but illustrates the idea.
}

The while loop would be the most difficult to rewrite, because it is controlled by state changes to a.

The speed loss caused by a call to return is negligible, but the efficiency gained by avoiding return and rewriting in a functional style is often enormous. Telling new users to stop using return probably won't help, but guiding them to a functional style will payoff.


@Paul return is necessary in imperative style because you often want to exit the function at different points in a loop. A functional style doesn't use loops, and therefore doesn't need return. In a purely functional style, the final call is almost always the desired return value.

In Python, functions require a return statement. However, if you programmed your function in a functional style, you will likely have only one return statement: at the end of your function.

Using an example from another StackOverflow post, let us say we wanted a function that returned TRUE if all the values in a given x had an odd length. We could use two styles:

# Procedural / Imperative
allOdd = function(x) {
  for (i in x) if (length(i) %% 2 == 0) return (FALSE)
  return (TRUE)
}

# Functional
allOdd = function(x) 
  all(length(x) %% 2 == 1)

In a functional style, the value to be returned naturally falls at the ends of the function. Again, it looks more like a mathematical function.

@GSee The warnings outlined in ?ifelse are definitely interesting, but I don't think they are trying to dissuade use of the function. In fact, ifelse has the advantage of automatically vectorizing functions. For example, consider a slightly modified version of foo:

foo = function(a) { # Note that it now has an argument
 if(a) {
   return(a)
 } else {
   return(b)
 }
}

This function works fine when length(a) is 1. But if you rewrote foo with an ifelse

foo = function (a) ifelse(a,a,b)

Now foo works on any length of a. In fact, it would even work when a is a matrix. Returning a value the same shape as test is a feature that helps with vectorization, not a problem.

nograpes
  • 18,623
  • 1
  • 44
  • 67
  • It is not clear to me why `return` does not fit with a functional style of programming. Wether one is programming imperatively or functionally, at some stage a function or subroutine needs to return something. For example, functional programming in python still requires a `return` statement. Could you elaborate more on this point. – Paul Hiemstra Aug 11 '12 at 12:18
  • 3
    In this situation, using `ifelse(a,a,b)` is a pet peeve of mine. It seems like every line in `?ifelse` is screaming, "don't use me instead of `if (a) {a} else b`." e.g. "... returns a value with the same shape as `test`", "if `yes` or `no` are too short, their elements are recycled.", "the mode of the result may depend on the value of `test`", "the class attribute of the result is taken from `test` and may be inappropriate for the values selected from `yes` and `no`" – GSee Aug 11 '12 at 12:31
  • At second look, `foo` doesn't make much sense; it will always return TRUE or `b`. Using `ifelse` it will return 1 or several TRUEs, and/or 1 or several `b`s. Initially, I thought the intent of the function was to say "if some statement is TRUE, return something, otherwise, return something else." I don't think that should be vectorized, because then it would become "return the elements of some object that are TRUE, and for all the elements that aren't TRUE, return `b`. – GSee Aug 11 '12 at 18:06
  • I was just bitten by `ifelse` and its returning arguments of the same length as test... `ifelse(length(v) == 0, 0, v)` always returns a vector of length one, silently. I had wrongly assumed that `test` would be recycled if it was just 1, which is a typical behaviour of vectorised functions, including `ifelse` for its other arguments...! – Fons MA Jan 16 '21 at 03:17
22

It seems that without return() it's faster...

library(rbenchmark)
x <- 1
foo <- function(value) {
  return(value)
}
fuu <- function(value) {
  value
}
benchmark(foo(x),fuu(x),replications=1e7)
    test replications elapsed relative user.self sys.self user.child sys.child
1 foo(x)     10000000   51.36 1.185322     51.11     0.11          0         0
2 fuu(x)     10000000   43.33 1.000000     42.97     0.05          0         0

____EDIT __________________

I proceed to others benchmark (benchmark(fuu(x),foo(x),replications=1e7)) and the result is reversed... I'll try on a server.

Alan
  • 3,153
  • 2
  • 15
  • 11
  • Could you comment on the reason why this difference occurs? – Paul Hiemstra Aug 01 '12 at 05:06
  • 4
    @PaulHiemstra Petr's Answer covers one of the main reasons for this; two calls when using `return()`, one if you don't. It is totally redundant at the end of a function as `function()` returns it's last value. You'l only notice this in many repeats of a function where not much is done internally so that the cost of `return()` becomes large part of total compute time of function. – Gavin Simpson Aug 07 '12 at 09:25
16

My question is: Why is not calling return faster

It’s faster because return is a (primitive) function in R, which means that using it in code incurs the cost of a function call. Compare this to most other programming languages, where return is a keyword, but not a function call: it doesn’t translate to any runtime code execution.

That said, calling a primitive function in this way is pretty fast in R, and calling return incurs a minuscule overhead. This isn’t the argument for omitting return.

or better, and thus preferable?

Because there’s no reason to use it.

Because it’s redundant, and it doesn’t add useful redundancy.

To be clear: redundancy can sometimes be useful. But most redundancy isn’t of this kind. Instead, it’s of the kind that adds visual clutter without adding information: it’s the programming equivalent of a filler word or chartjunk).

Consider the following example of an explanatory comment, which is universally recognised as bad redundancy because the comment merely paraphrases what the code already expresses:

# Add one to the result
result = x + 1

Using return in R falls in the same category, because R is a functional programming language, and in R every function call has a value. This is a fundamental property of R. And once you see R code from the perspective that every expression (including every function call) has a value, the question then becomes: “why should I use return?” There needs to be a positive reason, since the default is not to use it.

One such positive reason is to signal early exit from a function, say in a guard clause:

f = function (a, b) {
    if (! precondition(a)) return() # same as `return(NULL)`!
    calculation(b)
}

This is a valid, non-redundant use of return. However, such guard clauses are rare in R compared to other languages, and since every expression has a value, a regular if does not require return:

sign = function (num) {
    if (num > 0) {
        1
    } else if (num < 0) {
        -1
    } else {
        0
    }
}

We can even rewrite f like this:

f = function (a, b) {
    if (precondition(a)) calculation(b)
}

… where if (cond) expr is the same as if (cond) expr else NULL.

Finally, I’d like to forestall three common objections:

  1. Some people argue that using return adds clarity, because it signals “this function returns a value”. But as explained above, every function returns something in R. Thinking of return as a marker of returning a value isn’t just redundant, it’s actively misleading.

  2. Relatedly, the Zen of Python has a marvellous guideline that should always be followed:

    Explicit is better than implicit.

    How does dropping redundant return not violate this? Because the return value of a function in a functional language is always explicit: it’s its last expression. This is again the same argument about explicitness vs redundancy.

    In fact, if you want explicitness, use it to highlight the exception to the rule: mark functions that don’t return a meaningful value, which are only called for their side-effects (such as cat). Except R has a better marker than return for this case: invisible. For instance, I would write

    save_results = function (results, file) {
        # … code that writes the results to a file …
        invisible()
    }
    
  3. But what about long functions? Won’t it be easy to lose track of what is being returned?

    Two answers: first, not really. The rule is clear: the last expression of a function is its value. There’s nothing to keep track of.

    But more importantly, the problem in long functions isn’t the lack of explicit return markers. It’s the length of the function. Long functions almost (?) always violate the single responsibility principle and even when they don’t they will benefit from being broken apart for readability.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 1
    Maybe I should add that some people advocate for using `return` to make it more similar to other languages. But that’s a bad argument: other functional programming languages tend not to use `return` either. It’s only *imperative* languages, where not every expression has a value, that use it. – Konrad Rudolph Nov 29 '19 at 09:24
  • 1
    I came to this Question with the opinion that using `return` supports explicitly better, and read your answer with full criticism. Your answer has led me to reflect upon that view. I think that the need to use `return` for explicitly (at least in my own case), is tied to a need to better be able to revise my functions at a later time point. With the notion that my functions simply might be too complex, I can now see that a goal for improving my programming style, would be to strive for structuring the codes to maintain explicity without a `return`. Thank you for those reflections and insight!! – Kasper Thystrup Karstensen Jun 25 '20 at 08:30
14

A problem with not putting 'return' explicitly at the end is that if one adds additional statements at the end of the method, suddenly the return value is wrong:

foo <- function() {
    dosomething()
}

This returns the value of dosomething().

Now we come along the next day and add a new line:

foo <- function() {
    dosomething()
    dosomething2()
}

We wanted our code to return the value of dosomething(), but instead it no longer does.

With an explicit return, this becomes really obvious:

foo <- function() {
    return( dosomething() )
    dosomething2()
}

We can see that there is something strange about this code, and fix it:

foo <- function() {
    dosomething2()
    return( dosomething() )
}
Hugh Perkins
  • 7,975
  • 7
  • 63
  • 71
  • 1
    yes, actually I find that an explicit return() is useful when debugging; once the code is cleaned up, its need is less compelling and I prefer the elegance of not having it ... – PatrickT Jan 15 '14 at 09:01
  • But this isn’t actually a problem in real code, it’s purely theoretical. Code which *could* suffer from this has a much bigger problem: an obscure, brittle code flow that is so non-obvious that simple additions break it. – Konrad Rudolph Mar 28 '17 at 14:26
  • @KonradRudolph I think you're kind of doing a No-True Scotsman on it ;-) "If this is a problem in your code, you are a bad programmer!". I dont really agree. I think that whilst you can get away with taking short-cuts on small pieces of code, where you know every line by heart, this will come back to bite you as your code gets larger. – Hugh Perkins Mar 29 '17 at 08:00
  • 2
    @HughPerkins It’s not a *No true Scotsman*; rather, it’s an empirical observation about code complexity, backed up by decades of software engineering best practice: keep individual functions short and code flow obvious. And omitting `return` isn’t a shortcut, it’s the *proper* style in functional programming. Using unnecessary `return` function calls is an instance of [cargo cult programming](https://en.wikipedia.org/wiki/Cargo_cult_programming). – Konrad Rudolph Mar 29 '17 at 08:54
  • Well ... I don't see how this prevents you from adding something after your `return` statement and not noticing that it won't be executed. You could just as well add a comment after the value you want to return e.g. `dosomething() # this is my return value, don't add anything after it unless you know goddam well what you are doing` – lebatsnok May 08 '17 at 10:59
  • You could add a comment, but it would be non-standard, and a much higher cognitive overload. It may be that experienced r programmers over time develop an intuition for mentally flagging the last line as the return value. However, going from 'advanced programmers might have such an intuition' to 'all programmers have such an intuition' seems not unplausible, but might be naive in a corporate environment, which I suppose is the angle I'm coming from, mostly. – Hugh Perkins May 08 '17 at 12:44
6

I think of return as a trick. As a general rule, the value of the last expression evaluated in a function becomes the function's value -- and this general pattern is found in many places. All of the following evaluate to 3:

local({
1
2
3
})

eval(expression({
1
2
3
}))

(function() {
1
2
3
})()

What return does is not really returning a value (this is done with or without it) but "breaking out" of the function in an irregular way. In that sense, it is the closest equivalent of GOTO statement in R (there are also break and next). I use return very rarely and never at the end of a function.

 if(a) {
   return(a)
 } else {
   return(b)
 }

... this can be rewritten as if(a) a else b which is much better readable and less curly-bracketish. No need for return at all here. My prototypical case of use of "return" would be something like ...

ugly <- function(species, x, y){
   if(length(species)>1) stop("First argument is too long.")
   if(species=="Mickey Mouse") return("You're kidding!")
   ### do some calculations 
   if(grepl("mouse", species)) {
      ## do some more calculations
      if(species=="Dormouse") return(paste0("You're sleeping until", x+y))
      ## do some more calculations
      return(paste0("You're a mouse and will be eating for ", x^y, " more minutes."))
      }
   ## some more ugly conditions
   # ...
   ### finally
   return("The end")
   }

Generally, the need for many return's suggests that the problem is either ugly or badly structured.

[EDIT]

return doesn't really need a function to work: you can use it to break out of a set of expressions to be evaluated.

getout <- TRUE 
# if getout==TRUE then the value of EXP, LOC, and FUN will be "OUTTA HERE"
# .... if getout==FALSE then it will be `3` for all these variables    

EXP <- eval(expression({
   1
   2
   if(getout) return("OUTTA HERE")
   3
   }))

LOC <- local({
   1
   2
   if(getout) return("OUTTA HERE")
   3
   })

FUN <- (function(){
   1
   2
   if(getout) return("OUTTA HERE")
   3
   })()

identical(EXP,LOC)
identical(EXP,FUN)
lebatsnok
  • 6,329
  • 2
  • 21
  • 22
  • Today I found a case where one may actually need `return` (my ugly example above is highly artificial): suppose you need to test whether a value is `NULL` or `NA`: in these cases, return an empty string, otherwise return the `character` value. But a test of `is.na(NULL)` gives an error, so it looks like it can only be done with `if(is.null(x)) return("")` and then continuing with `if(is.na(x)) .....`. (One can use `length(x)==0` instead of `is.null(x)` but still, it is not possible to use `length(x)==0 | is.na(x)` if `x` is `NULL`.) – lebatsnok May 16 '17 at 06:48
  • 2
    That's because you used `|` (vectorised OR where both sides are evaluated) instead of `||` (short circuit OR, not vectorised, where predicates are evaluated in turn). Consider `if (TRUE | stop()) print(1)` versus `if (TRUE || stop()) print(1)` – asachet Aug 19 '19 at 11:34
4

The argument of redundancy has come up a lot here. In my opinion that is not reason enough to omit return(). Redundancy is not automatically a bad thing. When used strategically, redundancy makes code clearer and more maintenable.

Consider this example: Function parameters often have default values. So specifying a value that is the same as the default is redundant. Except it makes obvious the behaviour I expect. No need to pull up the function manpage to remind myself what the defaults are. And no worry about a future version of the function changing its defaults.

With a negligible performance penalty for calling return() (as per the benchmarks posted here by others) it comes down to style rather than right and wrong. For something to be "wrong", there needs to be a clear disadvantage, and nobody here has demonstrated satisfactorily that including or omitting return() has a consistent disadvantage. It seems very case-specific and user-specific.

So here is where I stand on this.

function(){
  #do stuff
  ...
  abcd
}

I am uncomfortable with "orphan" variables like in the example above. Was abcd going to be part of a statement I didn't finish writing? Is it a remnant of a splice/edit in my code and needs to be deleted? Did I accidentally paste/move something from somewhere else?

function(){
  #do stuff
  ...
  return(abdc)
}

By contrast, this second example makes it obvious to me that it is an intended return value, rather than some accident or incomplete code. For me this redundancy is absolutely not useless.

Of course, once the function is finished and working I could remove the return. But removing it is in itself a redundant extra step, and in my view more useless than including return() in the first place.

All that said, I do not use return() in short unnamed one-liner functions. There it makes up a large fraction of the function's code and therefore mostly causes visual clutter that makes code less legible. But for larger formally defined and named functions, I use it and will likely continue to so.

cymon
  • 413
  • 2
  • 9
  • “Was abcd going to be part of a statement I didn't finish writing?” — How is this different from *any other expression* you write, though? This, I think is the core of our disagreement. Having a variable stand on its own might be peculiar in an imperative programming language but it’s completely normal and expected in a functional programming language. The issue, I claim, is simply that you’re not familiar with functional programming (the fact that you talk about “statements” instead of “expressions” reinforces this). – Konrad Rudolph Nov 29 '19 at 11:08
  • 1
    It is different because every other statement usually does something in a more obvious way: It's an assignment, a comparison, a function call... Yes my first coding steps were in imperative languages and I still use imperative languages. Having uniform visual cues across languages (wherever the languages allow it) makes my work easier. A `return()` in R costs nothing. It is objectively redundant, but being "useless" is your subjective judgement. Redundant and useless are not necessarily synonyms. THAT's where we disagree. – cymon Nov 29 '19 at 13:25
  • Also, I am not a software engineer nor computer scientist. Don't read too much nuance into my use of terminology. – cymon Nov 29 '19 at 13:29
  • Just to clarify: “Redundant and useless are not necessarily synonyms. THAT's where we disagree.” — No, I totally agree with that, and I explicitly made that point in my answer. Redundancy can be helpful or even [*crucial*](https://en.wikipedia.org/wiki/Redundancy_%28engineering%29). But this needs to be actively shown, not assumed. I understand your argument for why you think this holds for `return`, and even though I’m not convinced I think it’s potentially valid (it definitely is in an imperative language … my belief is that it doesn’t translate to functional languages). – Konrad Rudolph Nov 29 '19 at 14:13
2

return can increase code readability:

foo <- function() {
    if (a) return(a)       
    b     
}
Eldar Agalarov
  • 4,849
  • 4
  • 30
  • 38
  • 3
    *Maybe* it can, at that. But it doesn’t do it in your example. Instead it obscures (or rather, complexifies) the code flow. – Konrad Rudolph Mar 28 '17 at 14:25
  • 1
    your function can be simplified to: `foo <- function() a || b` (which is IMO more readable; in any case, there is no "pure" readability but readability in someone's opinion: there are people who say assembly language is perfectly readable) – lebatsnok Aug 21 '19 at 15:30