Type Inference Issue in Swift Playgrounds

I am using Swift in one of my high school computer science classes and have been for the last few years. There is a playground that has them try to add a String and an Int to show type safety and up until this year it has always generated the appropriate error. Today, to my surprise, when we did

var x = "banana" + 1

no error was thrown and when I printed the value of x it said 1. When trying this same code in a repl.it with Swift 5.1 I did get the appropriate error. Is this an issue with playgrounds (happened both in the app and in XCode) or am I missing something here?
I tried this here in my office and I got the expected error. Specifically:
  1. Using Xcode 12.0 on macOS 10.15.5 I created a new playground (File > New > Playground > macOS > Blank).

  2. I replaced the contents of with your snippet.

  3. It spat out the error:

Code Block
error: MyPlayground.playground:1:18: error: binary operator '+' cannot be applied to operands of type 'String' and 'Int'
var x = "banana" + 1
~~~~~~~~ ^ ~


Please repeat this at your end and see what you get.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Yes, XCode gives the appropriate error. It is specifically the playgrounds app that seems to have the issue (and only with some of the playgrounds that are part of the Apple Learn to Code iBook).

For example, just had a student turn in something where they multiplied 2 * "Pi" (instead of using the constant Pi they put a string)...the playgrounds app evaluated that expression as zero.

When I open this same playground file in XCode it gives the expected error. And if I open a new blank playground in the app and type in that line it gives the error. I'm going to chalk this up to something in a few of these pre-made playground files causing this odd result. Consider this closed, thanks for responding!
Playgrounds like that usually include library code to reduce boilerplate and allow the reader to focus on the specific lesson involved. It’s possible that this library code is doing something (that I’d consider) weird, like adding operate overloads.

Can you point me to a specific playground that exhibits the problem?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Quinn,

Here's the details on the playground with this problem


In 'Develop in Swift Explorations' on page 5 titled "Type Safety" of the playground assignment "Types" , Apple's instructions are to uncomment a line of code with "banana" + 1 and check out the compiling error. That makes sense since you can't just add Strings and Ints in Swift, but the Playground compiler seems totally okay with just ignoring the String and compiles anyway. 

Can you please provide a workaround for this problem?

Thanks
Well, that’s exciting. I used Books to download Develop in Swift Explorations and then, an page 11, clicked “Download student materials”. In the resulting directory I opened Types.playground and then, on the Type Safety page, I uncommented line 10, that is:

Code Block
//"banana" + 1


Like you, I’d expect this to yield an error. Moreover, when I put that line in a new playground it does error. There’s something about the context of this playground that’s causing the problem.

To investigate this further I first deleted all the other playground pages, just to make sure there wasn’t some cross talk going on. That didn’t help.

I then went into raw mode (Editor > Hide Raw Markup) and deleted everything except the problematic line. Still no dice.

I then deleted Sources/SimpleFileIO.swift and that fixed the problem, that is, once I deleted that file the uncommented line generated an error.

Some trial and error reveals that this is the root of the problem:

Code Block
extension Int: ExpressibleByStringLiteral {
public typealias StringLiteralType = String
public init(stringLiteral: String) {
var value = 0
if let represented = Int(stringLiteral) {
value = represented
}
self.init(value)
}
}


This extends Int so it can be expressed by a string literal. So, here’s what’s going on:
  1. Swift is looking for a way for "banana" + 1 to make sense.

  2. It has two overloads on +, one that takes two Int values and one that takes two String values.

  3. The String overload is useless but the Int overload can work if it can convert "banana" to an Int. And that’s exactly that this extension allows it to do.

So, there’s a bunch of lessons here:
  • This is clearly a bug in the playground and I recommend that you file a bug report about that. Please post your bug number, just for the record.

  • Swift lore is that you should not extend types you don’t ‘own’ (Int in this example) to conform to protocols you don’t own (ExpressibleByStringLiteral), so this was never a good design choice.

  • Even if you ignore that, the implementation of this extension makes no sense. When you implement one of these ExpressibleByXxx protocols, you should not fail silently (in this case returning a default value of 0) if the literal is malformed. Rather, you should crash out (with a fatalError) because a malformed literal is obviously a programming error. Changing the code to do that would’ve made this problem much easier to find.

As to how you should work around this, the obvious choice here is to remove that extension from SimpleFileIO.swift. Unfortunately I don’t know enough about the playground to see whether that’ll have collateral damage. You should do that, and then work through the playground to see what else breaks.

If you hit a problem you can’t resolve, post the details here and I’ll take a look.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Thank you. Here's the bug report number: FB9025013
Hi all,

I'm the curriculum designer responsible for this playground. Thanks for pointing out the error, and thanks @eskimo for the sleuthing!

First off, please know that I discovered this bug and fixed the playground back in December, and I thought the fixed playground had already been uploaded to that URL, but it apparently has not, so that will be done soon. I've responded to the feedback report (note that it says that the fixed file is already there).

The extension to Int in question was part of some early explorations I was doing when writing SimpleFileIO.swift and was left in the file unintentionally. (Oops!) The goal of the API in that file was to provide code that fails as rarely as possible, as beginning students might get stymied by having their code crash. Instead, with the key/value reading functions, the caller-supplied default value is used if either the key isn't present or the value can't be initialized with the string in the file.

One can quibble with that API design approach, for sure, and the functions for reading structs don't work this way—they throw as informative errors as possible.

Anyway, thought it might be helpful to chime in here so you have a little backstory. :-)

_swift
 Instructional Designer
Type Inference Issue in Swift Playgrounds
 
 
Q