Idea: change "@noreturn func f()" to "func f() noreturn"


(Jacob Bandes-Storch) #1

Premise: there are multiple ways of describing control-/data-flow when a
function is called:

    func x() *-> T* // x returns a value, of type T, to the caller
    func x() *throws* // x may throw an error to the caller
    func x() *throws -> T* // x may throw an error, and also return a value
    func x(...) *rethrows* ... // if a closure argument can throw an error,
x may also throw
    *@noreturn* func x() // x never returns to the caller

"noreturn" is currently spelled as an attribute, but like "throws" /
"rethrows" / "-> T", it's really describing how control flow works.

IMO this calls for consistency: whatever happens "after" the function is
called should appear "after" the parameter list.

    func x() *noreturn* {
        ...
    }

Thoughts?

Jacob


(Joe Groff) #2

We really don't even need a special syntactic form or attribute for 'no return' at all. We could provide a standard unconstructible type:

public /*closed*/ enum NoReturn {}

and it would be impossible for a function that returns NoReturn to return normally.

-Joe

···

On Feb 25, 2016, at 1:44 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

Premise: there are multiple ways of describing control-/data-flow when a function is called:

    func x() -> T // x returns a value, of type T, to the caller
    func x() throws // x may throw an error to the caller
    func x() throws -> T // x may throw an error, and also return a value
    func x(...) rethrows ... // if a closure argument can throw an error, x may also throw
    @noreturn func x() // x never returns to the caller

"noreturn" is currently spelled as an attribute, but like "throws" / "rethrows" / "-> T", it's really describing how control flow works.

IMO this calls for consistency: whatever happens "after" the function is called should appear "after" the parameter list.

    func x() noreturn {
        ...
    }

Thoughts?


(Chris Lattner) #3

This would require taking noreturn as a keyword (so we could use it in the type grammar). @noreturn is uncommon enough to be not worth doing that IMO. It is also non-primal to the decl it is modifying, which makes it a perfect attribute.

-Chris

···

On Feb 25, 2016, at 1:44 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

Premise: there are multiple ways of describing control-/data-flow when a function is called:

    func x() -> T // x returns a value, of type T, to the caller
    func x() throws // x may throw an error to the caller
    func x() throws -> T // x may throw an error, and also return a value
    func x(...) rethrows ... // if a closure argument can throw an error, x may also throw
    @noreturn func x() // x never returns to the caller

"noreturn" is currently spelled as an attribute, but like "throws" / "rethrows" / "-> T", it's really describing how control flow works.

IMO this calls for consistency: whatever happens "after" the function is called should appear "after" the parameter list.

    func x() noreturn {
        ...
    }

Thoughts?


(Radek Pietruszewski) #4

The difference though is that throws/rethrows is a part of type signature, @noreturn isn’t and has no reason to be AFAICT. It’s just an attribute of the method…

— Radek

···

On 25 Feb 2016, at 22:44, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

Premise: there are multiple ways of describing control-/data-flow when a function is called:

    func x() -> T // x returns a value, of type T, to the caller
    func x() throws // x may throw an error to the caller
    func x() throws -> T // x may throw an error, and also return a value
    func x(...) rethrows ... // if a closure argument can throw an error, x may also throw
    @noreturn func x() // x never returns to the caller

"noreturn" is currently spelled as an attribute, but like "throws" / "rethrows" / "-> T", it's really describing how control flow works.

IMO this calls for consistency: whatever happens "after" the function is called should appear "after" the parameter list.

    func x() noreturn {
        ...
    }

Thoughts?

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


(Jordan Rose) #5

"noreturn" is a part of a type signature; a @noreturn method cannot be overridden by a method that isn't @noreturn*, and you could have a closure that's guaranteed to not return.

* This isn't true in Objective-C, but it is in Swift.

Jordan

···

On Feb 25, 2016, at 14:38, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:

The difference though is that throws/rethrows is a part of type signature, @noreturn isn’t and has no reason to be AFAICT. It’s just an attribute of the method…

— Radek

On 25 Feb 2016, at 22:44, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Premise: there are multiple ways of describing control-/data-flow when a function is called:

    func x() -> T // x returns a value, of type T, to the caller
    func x() throws // x may throw an error to the caller
    func x() throws -> T // x may throw an error, and also return a value
    func x(...) rethrows ... // if a closure argument can throw an error, x may also throw
    @noreturn func x() // x never returns to the caller

"noreturn" is currently spelled as an attribute, but like "throws" / "rethrows" / "-> T", it's really describing how control flow works.

IMO this calls for consistency: whatever happens "after" the function is called should appear "after" the parameter list.

    func x() noreturn {
        ...
    }

Thoughts?

Jacob
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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


(Radek Pietruszewski) #6

Ah, that’s a neat idea! Not sure it’s an improvement though to have a magic type that changes how the compiler treats your method, rather than a rather explicit *attribute* on the method…

— Radek

···

On 25 Feb 2016, at 23:12, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 25, 2016, at 1:44 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Premise: there are multiple ways of describing control-/data-flow when a function is called:

    func x() -> T // x returns a value, of type T, to the caller
    func x() throws // x may throw an error to the caller
    func x() throws -> T // x may throw an error, and also return a value
    func x(...) rethrows ... // if a closure argument can throw an error, x may also throw
    @noreturn func x() // x never returns to the caller

"noreturn" is currently spelled as an attribute, but like "throws" / "rethrows" / "-> T", it's really describing how control flow works.

IMO this calls for consistency: whatever happens "after" the function is called should appear "after" the parameter list.

    func x() noreturn {
        ...
    }

Thoughts?

We really don't even need a special syntactic form or attribute for 'no return' at all. We could provide a standard unconstructible type:

public /*closed*/ enum NoReturn {}

and it would be impossible for a function that returns NoReturn to return normally.

-Joe

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


(Radek Pietruszewski) #7

I stand corrected! In this case, I change my position.

`func x() noreturn { … }` isn’t that bad on a second look.

— Radek

···

On 26 Feb 2016, at 00:04, Jordan Rose <jordan_rose@apple.com> wrote:

"noreturn" is a part of a type signature; a @noreturn method cannot be overridden by a method that isn't @noreturn*, and you could have a closure that's guaranteed to not return.

* This isn't true in Objective-C, but it is in Swift.

Jordan

On Feb 25, 2016, at 14:38, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

The difference though is that throws/rethrows is a part of type signature, @noreturn isn’t and has no reason to be AFAICT. It’s just an attribute of the method…

— Radek

On 25 Feb 2016, at 22:44, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Premise: there are multiple ways of describing control-/data-flow when a function is called:

    func x() -> T // x returns a value, of type T, to the caller
    func x() throws // x may throw an error to the caller
    func x() throws -> T // x may throw an error, and also return a value
    func x(...) rethrows ... // if a closure argument can throw an error, x may also throw
    @noreturn func x() // x never returns to the caller

"noreturn" is currently spelled as an attribute, but like "throws" / "rethrows" / "-> T", it's really describing how control flow works.

IMO this calls for consistency: whatever happens "after" the function is called should appear "after" the parameter list.

    func x() noreturn {
        ...
    }

Thoughts?

Jacob
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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


(Joe Groff) #8

There's no magic. If you can't construct a value of your return type, you can't return.

-Joe

···

On Feb 25, 2016, at 2:40 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

Ah, that’s a neat idea! Not sure it’s an improvement though to have a magic type that changes how the compiler treats your method, rather than a rather explicit *attribute* on the method…


(Radek Pietruszewski) #9

The magic is somewhere else. Calling a @noreturn function allows you to do things you can’t otherwise do:

func foo() -> Int {
  fatalError()
}

···

On 25 Feb 2016, at 23:40, Joe Groff <jgroff@apple.com> wrote:

On Feb 25, 2016, at 2:40 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

Ah, that’s a neat idea! Not sure it’s an improvement though to have a magic type that changes how the compiler treats your method, rather than a rather explicit *attribute* on the method…

There's no magic. If you can't construct a value of your return type, you can't return.

-Joe


(Jean-Daniel) #10

Just curious about how you would implement such function if there is no compile magic ?

How do you tell the compiler is it not an error that your function never return while it is declared to return something ?

···

Le 25 févr. 2016 à 23:40, Joe Groff via swift-evolution <swift-evolution@swift.org> a écrit :

On Feb 25, 2016, at 2:40 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

Ah, that’s a neat idea! Not sure it’s an improvement though to have a magic type that changes how the compiler treats your method, rather than a rather explicit *attribute* on the method…

There's no magic. If you can't construct a value of your return type, you can't return.


(Joe Groff) #11

I see. The unreachable code check arguably ought to also accept this if fatalError returns any uninhabited type, since it'll never be able return if that's the case.

-Joe

···

On Feb 25, 2016, at 2:43 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

On 25 Feb 2016, at 23:40, Joe Groff <jgroff@apple.com> wrote:

On Feb 25, 2016, at 2:40 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

Ah, that’s a neat idea! Not sure it’s an improvement though to have a magic type that changes how the compiler treats your method, rather than a rather explicit *attribute* on the method…

There's no magic. If you can't construct a value of your return type, you can't return.

-Joe

The magic is somewhere else. Calling a @noreturn function allows you to do things you can’t otherwise do:

func foo() -> Int {
  fatalError()
}


(Radek Pietruszewski) #12

Would that actually be useful today? (i.e. aside from your idea) To me, having a NoReturn return type seems more magic and less obvious than an attribute.

— Radek

···

On 25 Feb 2016, at 23:47, Joe Groff <jgroff@apple.com> wrote:

On Feb 25, 2016, at 2:43 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

On 25 Feb 2016, at 23:40, Joe Groff <jgroff@apple.com> wrote:

On Feb 25, 2016, at 2:40 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

Ah, that’s a neat idea! Not sure it’s an improvement though to have a magic type that changes how the compiler treats your method, rather than a rather explicit *attribute* on the method…

There's no magic. If you can't construct a value of your return type, you can't return.

-Joe

The magic is somewhere else. Calling a @noreturn function allows you to do things you can’t otherwise do:

func foo() -> Int {
  fatalError()
}

I see. The unreachable code check arguably ought to also accept this if fatalError returns any uninhabited type, since it'll never be able return if that's the case.

-Joe


(Joe Groff) #13

The compiler can tell statically that a closed, empty enum type is uninhabited, and thereby figure out that it's impossible for a function returning an uninhabited type can't possibly return.

-Joe

···

On Feb 25, 2016, at 11:39 PM, Jean-Daniel Dupas <mailing@xenonium.com> wrote:

Le 25 févr. 2016 à 23:40, Joe Groff via swift-evolution <swift-evolution@swift.org> a écrit :

On Feb 25, 2016, at 2:40 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

Ah, that’s a neat idea! Not sure it’s an improvement though to have a magic type that changes how the compiler treats your method, rather than a rather explicit *attribute* on the method…

There's no magic. If you can't construct a value of your return type, you can't return.

Just curious about how you would implement such function if there is no compile magic ?

How do you tell the compiler is it not an error that your function never return while it is declared to return something ?


(Jacob Bandes-Storch) #14

I also want to start a discussion (in a separate thread) about allowing
@noreturn functions to "return" any type, so that the unreachable code
checks can allow you to do things like "let value = fatalError()". For this
sort of thing, I think it's nice that noreturn is not an actual uninhabited
type, but has special meaning w.r.t. control flow, and could in fact be
part of the type signature.

Jacob

···

On Thu, Feb 25, 2016 at 2:51 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

> On 25 Feb 2016, at 23:47, Joe Groff <jgroff@apple.com> wrote:
>
>
>> On Feb 25, 2016, at 2:43 PM, Radosław Pietruszewski <radexpl@gmail.com> > wrote:
>>
>>> On 25 Feb 2016, at 23:40, Joe Groff <jgroff@apple.com> wrote:
>>>
>>>
>>>> On Feb 25, 2016, at 2:40 PM, Radosław Pietruszewski < > radexpl@gmail.com> wrote:
>>>>
>>>> Ah, that’s a neat idea! Not sure it’s an improvement though to have a
magic type that changes how the compiler treats your method, rather than a
rather explicit *attribute* on the method…
>>>
>>> There's no magic. If you can't construct a value of your return type,
you can't return.
>>>
>>> -Joe
>>
>>
>> The magic is somewhere else. Calling a @noreturn function allows you to
do things you can’t otherwise do:
>>
>> func foo() -> Int {
>> fatalError()
>> }
>
> I see. The unreachable code check arguably ought to also accept this if
fatalError returns any uninhabited type, since it'll never be able return
if that's the case.
>
> -Joe

Would that actually be useful today? (i.e. aside from your idea) To me,
having a NoReturn return type seems more magic and less obvious than an
attribute.

— Radek


(Joe Groff) #15

I admit I might be hopelessly in the language implementor's bubble here. From a semantic perspective, returning any uninhabited type (it doesn't need to be a specific one) feels less magic to me than having a special attribute or syntactic form for 'no return', since it achieves the desired semantics without additional language features. It also composes obviously with other aspects of function types like `throws` and currying (should we decide to add it back), whereas a special form needs to explicitly describe its interaction with those features.

-Joe

···

On Feb 25, 2016, at 2:51 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

On 25 Feb 2016, at 23:47, Joe Groff <jgroff@apple.com> wrote:

On Feb 25, 2016, at 2:43 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

On 25 Feb 2016, at 23:40, Joe Groff <jgroff@apple.com> wrote:

On Feb 25, 2016, at 2:40 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

Ah, that’s a neat idea! Not sure it’s an improvement though to have a magic type that changes how the compiler treats your method, rather than a rather explicit *attribute* on the method…

There's no magic. If you can't construct a value of your return type, you can't return.

-Joe

The magic is somewhere else. Calling a @noreturn function allows you to do things you can’t otherwise do:

func foo() -> Int {
  fatalError()
}

I see. The unreachable code check arguably ought to also accept this if fatalError returns any uninhabited type, since it'll never be able return if that's the case.

-Joe

Would that actually be useful today? (i.e. aside from your idea) To me, having a NoReturn return type seems more magic and less obvious than an attribute.


(Andrew Trick) #16

This makes perfect sense to me:
func x() noreturn throws -> T

It could override a function that is not noreturn.

But it isn’t nearly common enough to warrant a qualifying keyword. Just from a language documentation perspective I would leave @noreturn as an attribute even though it’s technically part of the type.

-Andy

···

On Feb 25, 2016, at 3:07 PM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 25, 2016, at 2:51 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

On 25 Feb 2016, at 23:47, Joe Groff <jgroff@apple.com> wrote:

On Feb 25, 2016, at 2:43 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

On 25 Feb 2016, at 23:40, Joe Groff <jgroff@apple.com> wrote:

On Feb 25, 2016, at 2:40 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

Ah, that’s a neat idea! Not sure it’s an improvement though to have a magic type that changes how the compiler treats your method, rather than a rather explicit *attribute* on the method…

There's no magic. If you can't construct a value of your return type, you can't return.

-Joe

The magic is somewhere else. Calling a @noreturn function allows you to do things you can’t otherwise do:

func foo() -> Int {
  fatalError()
}

I see. The unreachable code check arguably ought to also accept this if fatalError returns any uninhabited type, since it'll never be able return if that's the case.

-Joe

Would that actually be useful today? (i.e. aside from your idea) To me, having a NoReturn return type seems more magic and less obvious than an attribute.

I admit I might be hopelessly in the language implementor's bubble here. From a semantic perspective, returning any uninhabited type (it doesn't need to be a specific one) feels less magic to me than having a special attribute or syntactic form for 'no return', since it achieves the desired semantics without additional language features. It also composes obviously with other aspects of function types like `throws` and currying (should we decide to add it back), whereas a special form needs to explicitly describe its interaction with those features.


(Howard Lovatt) #17

The NoReturn type would have to be a bottom type so that a method returning
an X could be overridden with NoReturn. I think that would be compiler
magic in Swift rather than an enum you couldn't instantiate. +1 to changing
to a type rather than an annotation, it reads a lot better to me.

···

On Saturday, 27 February 2016, Joe Groff via swift-evolution < swift-evolution@swift.org> wrote:

> On Feb 25, 2016, at 11:39 PM, Jean-Daniel Dupas <mailing@xenonium.com > <javascript:;>> wrote:
>
>
>> Le 25 févr. 2016 à 23:40, Joe Groff via swift-evolution < > swift-evolution@swift.org <javascript:;>> a écrit :
>>
>>
>>> On Feb 25, 2016, at 2:40 PM, Radosław Pietruszewski <radexpl@gmail.com > <javascript:;>> wrote:
>>>
>>> Ah, that’s a neat idea! Not sure it’s an improvement though to have a
magic type that changes how the compiler treats your method, rather than a
rather explicit *attribute* on the method…
>>
>> There's no magic. If you can't construct a value of your return type,
you can't return.
>
> Just curious about how you would implement such function if there is no
compile magic ?
>
> How do you tell the compiler is it not an error that your function never
return while it is declared to return something ?

The compiler can tell statically that a closed, empty enum type is
uninhabited, and thereby figure out that it's impossible for a function
returning an uninhabited type can't possibly return.

-Joe

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <javascript:;>
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-- Howard.