Learning Swift Attempt #4 - Operator Overloading & Objective-C Bridging
Hey guys, this is Mac Heads 101, and today I'm going to be experimenting with some features of Swift that I don't truly understand yet and that I want to learn better.
So the first thing I want to play around with is operator overloading. Let's go ahead, and I'll create a new playground by just clicking on "Get started with the playground," and I'm going to call it "Operators." I think to learn operator overloading, what I'm going to do is I'm going to make a class that just wraps an Int
. We'll have operators like plus and minus and stuff like that, and the class will act the same way that an Int
will, but it'll be, uh, well, it'll be its own class with my operator.
So I'll create my number, and of course, I need a way to hold the number, and I'll also need a way to initialize it, so I guess I can do like that. Already, I'm not sure about a playground. Can I do my number 3
or numbers
? When I do this, it actually shows the object I just created; it shows the number attribute. I don't know what this i
thing does.
Well, apparently the i
thing freezes the playground. Wow! Okay, so like I've said before, it's still a beta. Let's try that again. If I click this i
thing—wow, that is very consistent—so the i
thing is evil. Yeah, never touch that. When I click the other thing, this comes up. That is kind of funny. Alright! But anyway, yeah, so it runs our code live and shows us what we've just created.
So it shows us the object we just made. Now, I knew how to do all this from the last tutorials; I figured it out. But I don't know how to overload an operator. Okay, this looks like it's it, and of course, I'm going to replace left and right with my numbers.
And basically, first off, I don't know what infix is here. The arithmetic addition operator is a binary operator because it operates on two objects and two targets, and is said to be infix because it appears between those two targets. So what are the other things besides infix? Prefix, infix, and postfix? Whoa! What does the triple plus operator do? This is just an example of an operator, I guess.
So, operator prefix, we could do prefix assignment func inout vector
. Neat! So, we could use prefix, suffix, whatever. Infix—in this case, we're using infix because the plus goes between the two arguments. So we are literally typing the code that will get called when you do plus some other number.
So what we'd really like this to be is equivalent to my number 8
. We want it to be a number with the value of eight, so here we're going to return number left.dot oh
, and I need to make a way to get the number in the thing, or do I? Can I just do left.dot number
? Okay, that works, so that's good.
And here, oh yeah, it's not eight! Who am I? You guys, if you were here, I would ask you to slap me on the back of the head. Three plus four is seven! Okay, just for future reference, it's seven, not eight. But anyway, here it is. It says seven. I was very confused when I saw seven. I thought it should be eight; I just did the addition wrong in my head. That's hilarious!
Okay, so we got the plus operator down. We can also do a minus operator. Minus operator, and if I do this, it should come back out to be four. Whoops! I forgot to replace plus with minus there. I was like 10; that's wrong! So this is cool; we actually overloaded these operators! This was a lot easier than I expected it to be.
Can I do like minus? Can I overload that and make the right thing an Int? And I'll just subtract right from there. Can I do like -2? Yes! So not only can the operators act on two of the same type, but they can act on like something on the left and a different thing on the right.
So I actually made it so I can subtract an Int from a my number
object. This pretty much answered all my questions about operator overloading. There was one thing from the last video that I want to get straight, so I want to figure out how switch statements work.
I'm going to do that in the context of a my number
object. So if I do switch my number number 3
, and I'll do a case: my number number 2
, case: my number number 3
, case: my number number 4
. Here, I'll print out two, three, and four. And I also need a default, I think.
And now, if I remember from the last video, it looks like the operator I need is tilde equals. I don't know what tilde equals does, but I feel like it's the same thing as equals equals, at least for numbers. So when I'm doing it tilde equals here, I could probably use an equals equals here. I don't know; I won't mess around with tilde equals. That I really don't truly understand what it is, but I get that switch statements use it instead of double equals—the normal double equals.
So remember, if I click on this, I can see the console output, and it did indeed print out three. Wow, this is obnoxious how small it makes my code. Yeah, so now it's too big again. So anyway, it looks like it did print out three correctly.
I could also overload the equals equals operator. I also want to try. So the other day, switching a string didn't work, so I wonder if I can implement the tilde equals operator on a string. Well, first, let's just print out payback! Yo! Yo! I don't know what this is.
Okay, well, it looks like this actually works, but I don't know it didn't work last time. It says "Hey back," so it got that we typed "hey." What were we doing last time where it didn't work? I think maybe we had a string exclamation point, and that didn't work.
So a string exclamation point, you can't switch. What if I do a string question mark? And then I do the exclamation point here to unwrap it. You can't do that, so that just gives you a string. So you can't switch a string exclamation point by default; you can just switch a string.
What happens? Can you switch a string question mark? You shouldn't be able to—no. What happens if I now go and I'll just do it here? Can I implement my own tilde equals for a string exclamation point? And I'll just do like that.
Yes, and well, so now how can I see what it prints? It prints "Hey back." Nice! So I don't know how operator overloading works with these exclamation point types. Like, obviously, I can use the e double equals operator, but if the string has a tilde equals operator, it strikes me as odd that the exclamation point type doesn't.
So maybe what the exclamation point or what the tilde equals has that's special about it is the way it compares some sort of pointer or container or something like that—how it compares the actual object and doesn't compare the object contained inside or something like that. Well, I don't want to speculate because I don't actually know the difference, and it's hard to find other documentation, so I haven't been able to figure it out.
So if you guys know what the difference is between tilde equals and double equals, certainly let me know. I would be very interested to know. But here we've discovered at least one difference: when you use it, like this explicitly unwrapped type, you can't use tilde equals by default.
But anyway, I feel like I understand operator overloading pretty well now. We've only done infix operators, but I think I probably could figure out, based on their example, how to do a prefix or suffix operator too.
Now, the second thing I want to play with that I find a little bit more interesting is using Objective-C code in Swift so that I can experiment more with how pointers work and just figure out how to—how, you know, what the point of exclamation point is and why all these functions use it.
So I'm going to go ahead and create a new—I guess I have to create a new project. Wow! Alright! Yeah, I guess I could create a command line tool; that's all I really need. I'll make it in Swift, and I'll call it, uh, "Obscene Bridge."
So it's in Swift, and I have a main.swift here that prints "Hello, world!" and when I run it, it prints that. What I want though is I want to be able to create an Objective-C class. I create a new Objective-C file; I'll call it "MyClass." Neat!
Adding this file will create a mixed Swift and Objective-C target. Okay, well, I'm not sure what that did, and I'm also going to create a header file for MyClass.m
. It's weird it didn't generate—I could have done coco class, but I think that's Swift and not Objective-C. So that's weird, but it didn't generate the Objective-C class for me.
I'm going to have to type out the @interface
. Okay, well, let's go ahead and do it. I will call it "MyClass," as I've already named the file, and capital "MyClass." I think I'm probably gonna have to import Foundation. I'm just going to make it a class that compares a number, and I'll make a two-end message.
Wow, I really—I haven't typed out all this Objective-C stuff from scratch for a long time, and I'm not used to it at all because Xcode usually would generate it for me. Okay, so here's my very basic Objective-C class. I don't know what this is. Is this like Swift code or is this Objective-C code? It looks like "use this file to import your targets."
Okay, ah, alright! This looks very confusing. Your Objective-C bridging file imports every Objective-C header you want to expose to Swift. Ah! So I'm going to import MyClass.h
, and now in Swift, is it just magical? Can I just do "MyClass"?
Yeah, can I do MyClass number 3.dot to int
? Yes! Oh, and look at that, the type of this is CInt
. And because it's an int in the Objective-C code, if I had an int that was—uh, like here, what happens if I do this? What if I do—I force this to be an int and I pass myNumber
here because this seems to want to take an CInt
, but I'm giving it an int.
Can I cast this? Why is it giving me an error? So when I pass three, that works. How can I convert my number to CInt
? Huh, that one, so can I do CInt(myNumber)
? Interesting! So there's a different in type in Objective-C than there is in Swift, and I guess that's because this is a like a real class.
This is a class with a—you know, it's a subclass of signed integer. Convert to integer literal. I mean, I don't really know what this does, but it's kind of cool. And this is a neat feature! I'm just reading the header right here, and I see this extension. It's making int into a hashable and into a printable—and I assume these are protocols.
So this must be the equivalent of an Objective-C category, you know, where you can add, uh, like variables and functions. So extensions are kind of cool. You know, I totally forgot about Objective-C categories! I wonder—I didn't even wonder how they existed in Swift, but I guess they do.
Anyway, so this instantiates our Objective-C class and converts it to an integer, and I think this will just work out straight up. Like, if I do this, it should print out three. Well, not when I got rid of the "m" there. Yeah, so it did print out three, so it worked.
Now, I'm trying to contemplate the simplest way to test this. I want to see what happens if I have a delegate method that passes a pointer to my Swift code and what the difference between exclamation point and no exclamation point is. So I'm going to create a new thing called "MyDelegate," just for fun, and it's going to just be like—okay, I totally don't remember Objective-C trying to use all these curly braces that are just not right.
So how about I got my class, and I gotta do a forward declaration. So here's what I'm up to. Basically, I'm making this delegate that I'm going to implement in here, so I'm going to make a sum class because my class is already taken, and I'll have like that. And here I will make something like pass to a delegate; it's delegate—I mean this is not very good code that I'm writing, but it's for learning, so I'm not sure why it's being, uh, not suggesting things in it.
There's no errors or anything, so that's good. So I'm going to do this guy. I don't care about this anymore. I'm going to create a sum class. So essentially, I'm creating a new Objective-C class passing to it my Swift class, and then the Objective-C class will call this method on my Swift class.
So now when I print out here, if I print out instance.dot to int
, will it print out the number? It should print out three still. It does! So it actually passed this thing. Now, I want to see what happens when I pass nil. So how about I make another map? This shouldn't even be on here, but pass nil to—actually, you know, I'll make it a static method; that way, it seems more appropriate. Woohoo!
So now what if I do MyClass.passNilTo(instance)
? It's going to try to convert nil to an int. Now, my theory is because it's this exclamation point type, and we're trying to call a method on it, we will get that same runtime error we've seen before. And we do "can't unwrap optional.none."
Now, what I really wanted to know is what happens if I get rid of the exclamation point? Because there's no compilation errors, but if this just says, okay, there's no way it's going to be nil or anything—it's just an instance of the object—and my Objective-C code isn't just passing an instance of the object.
I want to know what happens. Oh! So it prints out zero, which makes me believe that it actually just still passed a pointer, and it's trying to run toInt
as if an instance is a pointer. And what normally happens in the Objective-C runtime when you try to run a selector on a nil object is you get zero or nil or something like that all back. So in that case, that's what we're getting. Neat!
So when you don't have a, uh, an exclamation point, it always just treats it like an Objective-C object. Now, what if I do like this? This should have the same effect. No, it doesn't! So when you chain with question mark, it just returns nil if you can't send the selector. If you use no question mark and no wrapper, it will have the Objective-C way of doing things and just return zero.
Okay, so that's good to know. I'm very intrigued by this. So now I know the difference between exclamation point and no exclamation point. So exclamation point actually gives you more safety around pointers, although some people don't like that safety, including me.
So I'm actually probably never going to use exclamation point, at least until I learn to value it. This is pretty cool! So I'm pretty proud of what I figured out in this video. I hope you guys were interested in this; this was certainly different than the other three videos I've made so far because in this video, I wasn't really making an app or any goal. I was just aiming to learn about the language, and I certainly did.
But anyway, thanks for watching Mac Heads 101. Subscribe and goodbye!