Add an implicit return nil if function reaches end before return explicitly called


(Logan Sease) #1

I believe Swift should no longer require an explicit return on all functions and instead do an implicit nil return if the function reaches the end of its control flow and has an optional return type.

This could be useful to keep code clean and compact, by only having to write code for cases that our function handles and just returning nil otherwise automatically.

Consider:

func toInt(string : String?) -> Int?
{
  if let s = string
  {
    return s.intValue
  }

  //Make this return implicitly happen instead of requiring it.
  //return nil
}

This also very much goes along with the implicit return within a guard statement that I have seen proposed. Here:

func toInt(string: String?) -> Int?
{
  guard let s = string else {
     //this could be implicitly returned using the same logic, since the guard means we have reached the end of our code path without returning
    //return nil
  }
  return s.toInt()
}

These methods could be re-written as so:

This could allow us to write the examples below much cleaner
func toInt(string : String?) -> Int?
{
  if let s = string
  {
    return s.toInt()
  }
}

func toInt(string: String?) -> Int?
{
  guard let s = string else {}
  return s.toInt()
}

// it would be even cooler if we could omit the else {} and make them not it return by default. But that’s another thing all together
func toInt(string: String?) -> Int?
{
  guard let s = string
  return s.toInt()
}

Thanks for reading my first post to the Swift open source discussion board!
-Logan


(Gwynne Raskind) #2

I thought of this myself at one point, but I looked at a list of other languages to see if they did it and, if so, how much it actually improved anything.

The only language I could find that I have experience in which does this outside of closures was Bash shell scripting, and there wasn’t much to judge there because return doesn’t even mean the same thing in a shell script that it does in most programming languages. Nonetheless, it felt weird to me; lack of a return statement has always been for void functions ("there’s nothing *to* return").

Adding this to Swift would create a lot of confusing cases - if the return type is already Optional, can I then write "return" instead of "return nil" for places in the control flow that need to return without falling off the closing brace? If it isn’t, do I have to make it Optional, or will the compiler do that for me? If it does it for me, will it add a second level of Optional to the first one? ('cause while "Int??" (for example) might have uses, there are almost certainly better ways to express it.) Which of these options for behavior will be the least confusing? How do I tell the compiler "Don’t do that, warn me/error instead", especially when returning Optionals already? If I have to annotate functions I want explicit errors for, do I have to effectively put back a different form of the very @warn_unused_result attribute we just finally got rid of needing for the common case? How does this interact with error handling, especially in the presence of closures and "rethrows"? How does this interact with the implicit return from closures, and do closures now get the same semantics? Does "{}" in function type context now implicitly mean "{ ()->Void? in return nil }"? And if so, how can that change be justified given that it will change the semantics of many closures (workitems for DispatchQueue.async() come to mind) to be effectively wrong? If that isn’t the effect, how do you resolve the confusion developers will experience when they try to mix the enclosing function’s implicit return with a closure’s? What defines a function’s exit point for the purposes of the implicit return? The "end" of a function isn’t always where it seems to be. Can this be expressed reasonably by SIL in its current form without adding considerable extra logic to the compiler? Would this save enough code (a single, fairly short line per function) to justify so massive a semantic change, especially given that it violates the expectations of almost every language Swift typically replaces (C, C++, Objective-C, C#, Java, Perl, PHP, Python, Ruby, just to name a few)?

Ultimately I don’t feel like this would add anything but confusion to the language; couldn’t your example be rewritten as "func toInt(string: String?) -> Int? { return string?.intValue }"? Optional chaining would usually solve such cases more cleanly in my experience.

-- Gwynne Raskind

···

On Jun 22, 2016, at 14:44, Logan Sease via swift-evolution <swift-evolution@swift.org> wrote:

I believe Swift should no longer require an explicit return on all functions and instead do an implicit nil return if the function reaches the end of its control flow and has an optional return type.

This could be useful to keep code clean and compact, by only having to write code for cases that our function handles and just returning nil otherwise automatically.

Consider:

func toInt(string : String?) -> Int?
{
  if let s = string
  {
    return s.intValue
  }

  //Make this return implicitly happen instead of requiring it.
  //return nil
}

This also very much goes along with the implicit return within a guard statement that I have seen proposed. Here:

func toInt(string: String?) -> Int?
{
  guard let s = string else {
     //this could be implicitly returned using the same logic, since the guard means we have reached the end of our code path without returning
    //return nil
  }
  return s.toInt()
}

These methods could be re-written as so:

This could allow us to write the examples below much cleaner
func toInt(string : String?) -> Int?
{
  if let s = string
  {
    return s.toInt()
  }
}

func toInt(string: String?) -> Int?
{
  guard let s = string else {}
  return s.toInt()
}

// it would be even cooler if we could omit the else {} and make them not it return by default. But that’s another thing all together
func toInt(string: String?) -> Int?
{
  guard let s = string
  return s.toInt()
}

Thanks for reading my first post to the Swift open source discussion board!
-Logan

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Logan Sease) #3

So this particular construct is one that comes from the ruby language.
In Ruby, you don’t explicitly have to return at all, but rather your last statement will always return by default.
I am NOT advocating this exactly for swift… I get that it could lead to errors and confusion.

But here is my logic:
If the function returns an optional, this basically means that it may not return something. So then, why require the function to call a return explicitly at the end of the function?
Instead, I believe if we reach the end of the function and a return has not been called, we should implicitly return nil… because logically, we are not returning anything, so requiring the function to explicitly return seems redundant.

···

On Jun 22, 2016, at 5:31 PM, Gwynne Raskind <gwynne@darkrainfall.org> wrote:

I thought of this myself at one point, but I looked at a list of other languages to see if they did it and, if so, how much it actually improved anything.

The only language I could find that I have experience in which does this outside of closures was Bash shell scripting, and there wasn’t much to judge there because return doesn’t even mean the same thing in a shell script that it does in most programming languages. Nonetheless, it felt weird to me; lack of a return statement has always been for void functions ("there’s nothing *to* return").

Adding this to Swift would create a lot of confusing cases - if the return type is already Optional, can I then write "return" instead of "return nil" for places in the control flow that need to return without falling off the closing brace? If it isn’t, do I have to make it Optional, or will the compiler do that for me? If it does it for me, will it add a second level of Optional to the first one? ('cause while "Int??" (for example) might have uses, there are almost certainly better ways to express it.) Which of these options for behavior will be the least confusing? How do I tell the compiler "Don’t do that, warn me/error instead", especially when returning Optionals already? If I have to annotate functions I want explicit errors for, do I have to effectively put back a different form of the very @warn_unused_result attribute we just finally got rid of needing for the common case? How does this interact with error handling, especially in the presence of closures and "rethrows"? How does this interact with the implicit return from closures, and do closures now get the same semantics? Does "{}" in function type context now implicitly mean "{ ()->Void? in return nil }"? And if so, how can that change be justified given that it will change the semantics of many closures (workitems for DispatchQueue.async() come to mind) to be effectively wrong? If that isn’t the effect, how do you resolve the confusion developers will experience when they try to mix the enclosing function’s implicit return with a closure’s? What defines a function’s exit point for the purposes of the implicit return? The "end" of a function isn’t always where it seems to be. Can this be expressed reasonably by SIL in its current form without adding considerable extra logic to the compiler? Would this save enough code (a single, fairly short line per function) to justify so massive a semantic change, especially given that it violates the expectations of almost every language Swift typically replaces (C, C++, Objective-C, C#, Java, Perl, PHP, Python, Ruby, just to name a few)?

Ultimately I don’t feel like this would add anything but confusion to the language; couldn’t your example be rewritten as "func toInt(string: String?) -> Int? { return string?.intValue }"? Optional chaining would usually solve such cases more cleanly in my experience.

-- Gwynne Raskind

On Jun 22, 2016, at 14:44, Logan Sease via swift-evolution <swift-evolution@swift.org> wrote:

I believe Swift should no longer require an explicit return on all functions and instead do an implicit nil return if the function reaches the end of its control flow and has an optional return type.

This could be useful to keep code clean and compact, by only having to write code for cases that our function handles and just returning nil otherwise automatically.

Consider:

func toInt(string : String?) -> Int?
{
  if let s = string
  {
    return s.intValue
  }

  //Make this return implicitly happen instead of requiring it.
  //return nil
}

This also very much goes along with the implicit return within a guard statement that I have seen proposed. Here:

func toInt(string: String?) -> Int?
{
  guard let s = string else {
     //this could be implicitly returned using the same logic, since the guard means we have reached the end of our code path without returning
    //return nil
  }
  return s.toInt()
}

These methods could be re-written as so:

This could allow us to write the examples below much cleaner
func toInt(string : String?) -> Int?
{
  if let s = string
  {
    return s.toInt()
  }
}

func toInt(string: String?) -> Int?
{
  guard let s = string else {}
  return s.toInt()
}

// it would be even cooler if we could omit the else {} and make them not it return by default. But that’s another thing all together
func toInt(string: String?) -> Int?
{
  guard let s = string
  return s.toInt()
}

Thanks for reading my first post to the Swift open source discussion board!
-Logan

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Xiaodi Wu) #4

So this particular construct is one that comes from the ruby language.
In Ruby, you don’t explicitly have to return at all, but rather your last
statement will always return by default.
I am NOT advocating this exactly for swift… I get that it could lead to
errors and confusion.

But here is my logic:
If the function returns an optional, this basically means that it may not
return something.

() and nil are not the same.

So then, why require the function to call a return explicitly at the end of

the function?
Instead, I believe if we reach the end of the function and a return has
not been called, we should implicitly return nil… because logically, we are
not returning anything, so requiring the function to explicitly return
seems redundant.

You are returning nil, which isn't "not returning anything." Notice also
that you must write `return nil` and not just `return`.

···

On Tue, Jun 28, 2016 at 12:10 PM, Logan Sease via swift-evolution < swift-evolution@swift.org> wrote:

> On Jun 22, 2016, at 5:31 PM, Gwynne Raskind <gwynne@darkrainfall.org> > wrote:
>
> I thought of this myself at one point, but I looked at a list of other
languages to see if they did it and, if so, how much it actually improved
anything.
>
> The only language I could find that I have experience in which does this
outside of closures was Bash shell scripting, and there wasn’t much to
judge there because return doesn’t even mean the same thing in a shell
script that it does in most programming languages. Nonetheless, it felt
weird to me; lack of a return statement has always been for void functions
("there’s nothing *to* return").
>
> Adding this to Swift would create a lot of confusing cases - if the
return type is already Optional, can I then write "return" instead of
"return nil" for places in the control flow that need to return without
falling off the closing brace? If it isn’t, do I have to make it Optional,
or will the compiler do that for me? If it does it for me, will it add a
second level of Optional to the first one? ('cause while "Int??" (for
example) might have uses, there are almost certainly better ways to express
it.) Which of these options for behavior will be the least confusing? How
do I tell the compiler "Don’t do that, warn me/error instead", especially
when returning Optionals already? If I have to annotate functions I want
explicit errors for, do I have to effectively put back a different form of
the very @warn_unused_result attribute we just finally got rid of needing
for the common case? How does this interact with error handling, especially
in the presence of closures and "rethrows"? How does this interact with the
implicit return from closures, and do closures now get the same semantics?
Does "{}" in function type context now implicitly mean "{ ()->Void? in
return nil }"? And if so, how can that change be justified given that it
will change the semantics of many closures (workitems for
DispatchQueue.async() come to mind) to be effectively wrong? If that isn’t
the effect, how do you resolve the confusion developers will experience
when they try to mix the enclosing function’s implicit return with a
closure’s? What defines a function’s exit point for the purposes of the
implicit return? The "end" of a function isn’t always where it seems to be.
Can this be expressed reasonably by SIL in its current form without adding
considerable extra logic to the compiler? Would this save enough code (a
single, fairly short line per function) to justify so massive a semantic
change, especially given that it violates the expectations of almost every
language Swift typically replaces (C, C++, Objective-C, C#, Java, Perl,
PHP, Python, Ruby, just to name a few)?
>
> Ultimately I don’t feel like this would add anything but confusion to
the language; couldn’t your example be rewritten as "func toInt(string:
String?) -> Int? { return string?.intValue }"? Optional chaining would
usually solve such cases more cleanly in my experience.
>
> -- Gwynne Raskind
>
>
>
>> On Jun 22, 2016, at 14:44, Logan Sease via swift-evolution < > swift-evolution@swift.org> wrote:
>>
>> I believe Swift should no longer require an explicit return on all
functions and instead do an implicit nil return if the function reaches the
end of its control flow and has an optional return type.
>>
>> This could be useful to keep code clean and compact, by only having to
write code for cases that our function handles and just returning nil
otherwise automatically.
>>
>>
>> Consider:
>>
>> func toInt(string : String?) -> Int?
>> {
>> if let s = string
>> {
>> return s.intValue
>> }
>>
>> //Make this return implicitly happen instead of requiring it.
>> //return nil
>> }
>>
>>
>>
>> This also very much goes along with the implicit return within a guard
statement that I have seen proposed. Here:
>>
>> func toInt(string: String?) -> Int?
>> {
>> guard let s = string else {
>> //this could be implicitly returned using the same logic,
since the guard means we have reached the end of our code path without
returning
>> //return nil
>> }
>> return s.toInt()
>> }
>>
>>
>> These methods could be re-written as so:
>>
>> This could allow us to write the examples below much cleaner
>> func toInt(string : String?) -> Int?
>> {
>> if let s = string
>> {
>> return s.toInt()
>> }
>> }
>>
>> func toInt(string: String?) -> Int?
>> {
>> guard let s = string else {}
>> return s.toInt()
>> }
>>
>> // it would be even cooler if we could omit the else {} and make them
not it return by default. But that’s another thing all together
>> func toInt(string: String?) -> Int?
>> {
>> guard let s = string
>> return s.toInt()
>> }
>>
>>
>> Thanks for reading my first post to the Swift open source discussion
board!
>> -Logan
>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution