16

This one is probably easy. We know that the operator &+ does modular arithmetic on integers (wraps around), while the operator + causes an error.

$ swift
  1> var x: Int8 = 100
x: Int8 = 100
  2> x &+ x
$R0: Int8 = -56
  3> x + x
Execution interrupted. Enter Swift code to recover and continue.

What kind of error is this? I can't catch it and I can't turn it in to an optional:

  4> do {try x + x} catch {print("got it")}
Execution interrupted. Enter Swift code to recover and continue.
  5> try? x + x
Execution interrupted. Enter Swift code to recover and continue.

I'm pretty sure this kind of error is the same kind of error from this Stack Overflow question (a divide-by-zero) but I don't know if this kind of error can be trapped. What simple thing am I missing? Can it be trapped or not? If so, how?

halfer
  • 19,824
  • 17
  • 99
  • 186
Ray Toal
  • 86,166
  • 18
  • 182
  • 232

2 Answers2

24

Distinguish between an exception and a runtime error. An exception is thrown and can be caught. A runtime error stops your program dead in its tracks. Adding and getting an overflow is a runtime error, plain and simple. There is nothing to catch.

The point of an operator like &+ is that it doesn't error and it doesn't tell you there was a problem. That is the whole point.

If you think you might overflow, and you want to know whether you did, use static methods like addWithOverflow. It returns a tuple consisting of the result and a Bool stating whether there was an overflow.

var x: Int8 = 100
let result = x &+ x // -56

x = 100
let result2 = Int8.addWithOverflow(x,x) // (-56, true)
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thanks, I know it's not a thrown error (exception as you say, though Apple seems to avoid that term), since it can't be caught; I was wondering if there is some way to "trap it" anyway. It may be that runtime errors in Swift are untrappable; that would be a fine answer. I just can't find any information that says explicitly that that is the case. Do you have a reference? I guess I could have stated the question better. I'd like to know for sure these _can't_ be handled. – Ray Toal Mar 13 '16 at 18:37
  • An uncaught exception is a runtime error. But not every runtime error is a trappable exception. When the docs tell you that something "is a runtime error" they are telling you that you can never get away with doing this thing; it will stop your program dead. For example, out-of-range is a runtime error. – matt Mar 13 '16 at 18:40
  • 1
    BTW I understand your question (in your comment), but all I can tell you it's a design decision. I had some discussion about why they didn't make things like out-of-range a catchable exception, and the answer was above my pay grade; it seems that this would be just too expensive. You'd need to talk to a computer scientist to learn more about that. :) – matt Mar 13 '16 at 18:46
  • Got it. I'm just unable to find anything that actually says runtime errors halt the program in either The Swift Language Guide or The Swift Language Reference. Either I am a bad searcher or the authors thought that went without saying. I guess I have to look in the source code. :) – Ray Toal Mar 13 '16 at 18:47
  • 1
    Or you could just believe me. :) Anyway, I hope you understand that my point is: the idea that all runtime errors might be trappable is not at all silly, and many languages work that way. (You probably already knew that.) But Objective-C and Swift don't. In the case of something like out-of-range it would be really cool to have some special syntax that means "I'm willing to pay the extra price here, please let me catch this rather than crashing my program." In effect, that's what they've done with integer overflow. But for other stuff like out-of-range, there isn't anything like that. – matt Mar 13 '16 at 18:53
  • Unwrap of `nil` is another example. Your job is to guard _against_ unwrap of `nil`, and Swift gives you oodles of tools so you can do just that. But if you _do_ unwrap `nil`, your app is dead. – matt Mar 13 '16 at 18:54
  • You've convinced me. :) Yes, trapping _everything_ is sometimes funny (Java's `OutOfMemoryError` comes to mind) and not at all required for a language design. Your unwrapping `nil` is a great example. And I see how it relates to the integer overflow. You get `&+` and you get `addWithOverflow` as the very tools to guard against overflow with `+`, so there's no point in making _yet another_ way to trap it! I am enlightened. – Ray Toal Mar 13 '16 at 19:26
  • The problem between getting a runtime error for unwrapping nil can easily be prevented in code because Swift assists me with warnings and hints, so that Xcode and the syntax points out where this can happen. But with an Int overflow, there is no such warning: I can call Int32(x), where x is a UInt32 with a too-high value, and nothing warns me that this can crash my app. Or do I miss something? – Thomas Tempelmann Aug 11 '17 at 13:10
  • 2
    @ThomasTempelmann It's a long-standing complaint, solved in Swift 4, so upgrade to Xcode 9 and be happy – matt Aug 11 '17 at 13:37
  • I want to do `Int64.addWithOverflow()` (which I just tried and I think worked) –  May 14 '21 at 17:36
  • This answer was written a long time ago. Consider reading the docs: https://developer.apple.com/documentation/swift/int64 – matt May 14 '21 at 19:18
8

Looks like this has become a non-static method in Swift 5, addingReportingOverflow(_:).

So for example,

UInt8.max.addingReportingOverflow(1)

will return (partialValue: 0, overflow: true) See more on the Int manual page

And of course the normal arithmetic operators that start with & to allow overflow without returning overflow reports,

UInt8.max &+ 1

would return 0 as a UInt8

grego
  • 480
  • 6
  • 8