Swift TIL 12

Posted on 2020-07-18 10:16 +0100 in TIL • Tagged with Swift, Apple • 3 min read

First a small aside: To be honest, the T part of TIL is getting to be less and less true with this series of posts, but the posts themselves serve a useful purpose for me. As I've been reading the book I'm working through, I've also been making notes on my iPad in the Apple Notes application. I'm not really convinced that that's the best final location for such notes, so early on I made an extra step in keeping track of what I'm doing and trying to reinforce what I'm learning: transfer the notes into Org-Mode documents in my notebook repository.

This repository contains lots of Org-Mode files, broken down into subject directories, that hang on to longer-form information I want to keep track of regarding software development and general operating system use. I'm sure you know the sort of thing, the things where you know you know them but you can't always retain all the detail -- so having the detail where you know you'll find it is useful.

So I've made that part of the process: read book, find thing worth noting, note in Apple Notes, a wee while later re-read and test out by writing sample code and transfer to the Org-Mode notebook. During that latter step I sometimes also write up something that I really liked or found interesting here to further reinforce the learning process.

The "TIL" I wanted to note quickly today is how happy I was to see that Swift has something that's a reasonably recent addition to Emacs Lisp: conditional binding. Skipping off into Emacs Lisp for a moment, it would be very common for me to find myself writing something like this (this actually happens in all languages really):

(let ((foo (get-something-from-elsewhere)))
  (when foo
    (do-something-with foo)))

Quite simply: I'd get a value from elsewhere, that value could possibly be nil to mark that there was a failure to get a value, but that failure wasn't in any way fatal or even a problem worthy of note: I just needed to skip along. But that binding followed by the test was always a little jarring. And then, back in 25.1, if-let and when-let got added (of course, this being Lisp, it would have been very simple to add them anyway), and it was easier to write the code so it looked just a little nicer:

(when-let ((foo (get-something-from-elsewhere)))
  (do-something-with foo))

It's a small difference, but I find it a pleasing one.

So of course I was pleased to find that Swift has something similar with if and Optional values, where you can write something like:

if let foo = getSomethingFromElsewhere() {
    // Do something with foo but only if it's not nil
}

Which means you can do things like this (not that I'd really do things like this, but it was a handy test on the command line):

func oddRand() -> Int? {

    let n = Int.random( in: 0...99 )

    if n % 2 == 0 {
        return nil
    }

    return n
}

for _ in 0...10 {
    if let n = oddRand() {
        print( n )
    } else {
        print( "Nope" )
    }
}

As usual... of course that's horrible code, it was just thrown together to test/experience the language feature on the command line.

I like it though. I figure all the best languages have conditional binding. ;-)


Swift TIL 11

Posted on 2020-07-11 21:34 +0100 in TIL • Tagged with Swift, Apple • 2 min read

This is one of those things, especially this little play to help appreciate the feature, that I'm filing under "kinda cool, but I am never doing this in production".

So Swift has operator overriding, and then some. Moreover, operators are, in effect, functions, just with some extra syntax support. None of this is new to me, I've worked in and with other languages that have this ability, expect... I don't ever recall working in a language that, at the time I did, supported creating brand new operators (okay, fine, Lisp is a bit of an outlier here and there's all sorts of fun conversations to be had there -- but still, let's stick with more "conventional" syntax here). Support always seemed to be about extending the ability of an existing operator.

Swift though... yeah, you get to pick from a huge character space when it comes to creating operators.

Which got me thinking... How cool would it be to have a prefix operator that turns a floating point number into a currency-friendly number (you know, the sort of number type that can be used for currency-friendly calculations).

Swift has the decimal type which, at first glance anyway, looks to be a sensible candidate; even if it isn't (and, really, how to actually sensibly handle currency is a whole series of blog posts in their own right, that I have no wish to write myself because such things are a previous working life for me, and other people have doubtless done a very comprehensive job elsewhere over the years) it will serve as a good stand-in for the little bit of horror I'm going to write next.

So... Let's say we want to use £ as a prefix operator to say "see this number? make it a decimal", we could do something as simple as this:

import Foundation

prefix operator £
prefix func £( n : Decimal ) -> Decimal { n }

print( £1.20 + £0.75 + £0.01 )

Horrifically and delightfully, it works:

$ swift run
[3/3] Linking opover
1.96

I know, I know, I feel bad for even trying. But it's also kinda cool that the language has this.

It gets better though...

While reading up on what characters can and can't be used as operators, one thing that stood out was the fact that, more or less, any character that isn't a valid identifier can be used as an operator. So... hang on, we can use "emoji" as identifiers?

Like this?

import Foundation

prefix operator £
prefix func £( n : Decimal ) -> Decimal { n }

let 💵 = £1.20 + £0.75 + £0.01

print( 💵 )

Why yes. Yes we can. 😈


Swift TIL 10

Posted on 2020-07-05 15:27 +0100 in TIL • Tagged with Swift, Apple • 2 min read

My leisurely journey into getting to know Swift by reading and then making notes to myself in my blog continues, and this weekend I encountered defer. As I was reading about Swift I did keep wondering when something like try (it has try), catch (it has catch) and finally (it doesn't have finally, but...) might crop up. This weekend I hit the part of the book that covered this sort of thing.

Given Swift's apparent general reliance on not throwing errors but instead using Optional and nil to signify issues, it sort of came as no surprise that its approach to implementing something like try...finally is actually divorced from try. I'm not sure how I feel about it yet, but defer makes sense.

Here's an utterly useless bit of code that demonstrates how it works:

func add( _ n1 : Int, _ n2 : Int ) -> Int {

    defer {
        print( "Huh! We did some adding!" )
    }

    print( "About to do the add and then return" )
    return n1 + n2
}

print( add( 2, 2 ) )

When run, the output is this:

$ swift run
[3/3] Linking try-defer
About to do the add and then return
Huh! We did some adding!
4

A defer (and there can be multiple) is tied to the block that it's declared in, and is executed when the block exits. This is, of course, going to be really handy for things like resource-management where you don't want to be leaking something, although I can imagine a few other uses too (none of which are really going to be novel for someone who's coded in other languages with similar constructs).

What I find interesting about this is that one or more defer blocks can be declared at various locations within a block of code; this obviously makes sense in that you might not want to be handling the tidy-up of something you've not got around to creating yet. But there's also part of me feels uneasy about the "exit" code being declared further up the body of code, rather than down towards the end. On the other hand I think I do appreciate the idea of, up front, writing "look, any time there's a GTFO in the code that follows, this will happen" -- you're made aware pretty quickly of what to expect.

Anyway, it's good to know Swift has something similar to a finally.


Swift TIL 9

Posted on 2020-06-30 21:02 +0100 in TIL • Tagged with Swift, Apple • 2 min read

Some may be happy to know that the frequency of these little notes to myself may reduce real soon, as I'm sort of caught up with my notes, mostly, and I'm unlikely to pick up the book that I'm reading for a couple or so days now

I'm used to the idea of structures and classes from other languages, going way back, but as I first started reading about Swift it wasn't obvious to me why it had them both too. At first glance they appeared to be very similar. It was only as I got a little further into reading that I found out one huge difference (there are others, that pretty much stem from this one): objects created from classes are reference types (which you'd expect, of course), structures on the other hand are value types.

A quick illustration of the difference, in my head anyway, can be found if I go back to using an observer. Take this daft bit of illustrative code for example:

class Person {
    var name : String = "No name"
}

var dave = Person() {
    didSet {
        print( "dave was set" )
    }
}

dave.name = "Dave"

If I run that, I get no output. That makes sense. The variable dave is initialised to an instance of a Person but is never subsequently set to anything else. The following assignment is to a property of the object. We're working on a reference to an existing object.

But simply change Person to being a struct:

struct Person {
    var name : String = "No name"
}

var dave = Person() {
    didSet {
        print( "dave was set" )
    }
}

dave.name = "Dave"

and the output looks like this:

$ swift run
[3/3] Linking ref-vs-val
dave was set

That's because the assignment to dave.name means a new value is created.

This, of course, is just the tip of the iceberg; there are all sorts of other things to keep in mind that follow on from this, generally relating to mutability (or the lack thereof). I also imagine this means that, when there's no obvious benefit either way, the choice of using class vs struct is something that could have performance implications. That's something for me to look into more another day; but this is a note here to myself that it's a thing to keep in mind.


Swift TIL 8

Posted on 2020-06-29 22:48 +0100 in TIL • Tagged with Swift, Apple • 3 min read

Although I read up on it a few days back, it was only this evening that I fired up Emacs (well of course I'm testing Swift with Emacs, what did you think I'd do?!?) and dabbled with some code to really get a feel for how casting works in Swift.

Swift seems to be one of those languages that does it with a keyword rather than a non-keyword approach. The two main keywords being as? and as!. I kind of like how there's a polite version and a bossy version. Having the two makes a lot of sense from what I read too.

To try and illustrate my understanding so far (and do keep in mind I'm not writing this with the express purpose of explaining it to anyone else -- I'm writing this to try and retain it all in my head by working through it), here's a bit of utterly pointless and highly-contrived code that defines three classes in a fairly ordinary hierarchy:

class Animal {}

class Dog : Animal {}

class Cat : Animal {
    func beAdorable() {
        print( "Purrrrrr!" )
    }
}

So, so far, so good: we have animals, we have dogs which are a kind of animal, and we have cats, which are also a kind of animal, but they have the special ability of actually being adorable. 😼

Now, for the purposes of just testing all of this out, here's a horrible function that makes little sense other than for testing:

func adore( _ a : Animal ) {
    ( a as! Cat ).beAdorable()
}

Given an animal, it forces it to be a cat (by casting it with as!), and then asks it to be adorable (because, of course, cats always do as they're asked).

So, if we then had:

adore( Cat() )

we'd get what we expect when run:

Purrrrrr!

So far so good. But what about:

adore( Dog() )

Yeah, that's not so good:

~/d/p/s/casting$ swift run
[3/3] Linking casting
Could not cast value of type 'casting.Dog' (0x10a1f8830) to 'casting.Cat' (0x10a1f88c0).
fish: 'swift run' terminated by signal SIGABRT (Abort)

One way around this would be to use as?, which has the effect of casting the result to an Optional. This means I can re-write the adore function like this:

func adore( _ a : Animal ) {
    ( a as? Cat )?.beAdorable()
}

Now, if a can be cast to a Cat, you get an optional that wraps the Cat, otherwise you get an optional that wraps nil (hence the second ? before attempting to call the beAdorable member function).

So now, if I run the problematic dog call above again:

~/d/p/s/casting$ swift run
[3/3] Linking casting

In other words, no output at all. Which is the idea here.

I think I like this, I think it makes sense, and I think I can see why both as! and as? exist. The latter also means, of course, that you can do something like:

func adore( _ a : Animal ) {
    let cat = a as? Cat
    if cat != nil {
        cat!.beAdorable()
    } else {
        print( "That totally wasn't a cat" )
    }
}

which, in the messy dog call again, now results in:

~/d/p/s/casting$ swift run
[3/3] Linking casting
That totally wasn't a cat

Or, of course, the same effect could be had with:

func adore( _ a : Animal ) {
    if a is Cat {
        ( a as! Cat ).beAdorable()
    } else {
        print( "That totally wasn't a cat" )
    }
}

It should be stressed, of course, that the example code is terrible design, so given the above I'd ensure I never end up in this sort of situation in the first place. But for the purposes of writing and compiling and running code and seeing what the different situations result in, it helped.


Swift TIL 7

Posted on 2020-06-28 16:25 +0100 in TIL • Tagged with Swift, Apple • 1 min read

This post is very much a case of me writing it down to try and get it all straight in my head, and to make sure it sticks. The other day I was reading about Swift's types and type-equality checks, and as I'd expect from plenty of other languages I've worked with, there's a way for checking that two types are the same, such that super/subclasses aren't taken into account, and a way where they are. So, given this silly code:

class Animal {}

class Cat : Animal {}

print( Cat.self == Animal.self )          // False
print( Cat.self is Animal.Type )          // True
print( type( of: Cat() ) is Animal.Type ) // True

it's made clear that == checks for strict equality and a super/subclass relationship isn't taken into account. On the other hand is does take it into account.

Only... what's with this whole .self sometimes and .Type other times business? That took a little bit of writing code and playing to get comfortable with. Here's how I understand it now (and do feel free to correct me below if I'm way off):

Given the above code, Animal.Type is the type of a value that expresses the type of Animal. On the other hand, Animal.self is a value that is the type of an Animal. Yeah, I know, that still reads oddly. But written as code:

let feline : Cat.Type = Cat.self

I think it makes a lot more sense. And having got there I felt I better understood it. I'm not 100% sure I'm 100% with it, but I'm getting there.


Swift TIL 6

Posted on 2020-06-27 21:23 +0100 in TIL • Tagged with Swift, Apple • 1 min read

I'm going to file this one under "it seems really unnecessary, but it's also kinda cool". While reading up about protocols the book I'm reading introduced the ExpressibleBy*Literal protocols, where the * is one of a number of obvious literals. For example: ExpressibleByStringLiteral. As you might imagine, it lets you create a class that can be initialised with a literal value, as opposed to needing to appear to call the constructor for a class.

So, for a silly example:

class Hello : ExpressibleByStringLiteral {

    private let what : String

    required init( stringLiteral what : String ) {
        self.what = what
    }

    func say() {
        print( "Hello, \(self.what)!" )
    }
}

You could, of course, write this:

let v1 = Hello( "world" )
v1.say()

but because of ExpressibleByStringLiteral you can also write:

let v2 : Hello = "universe"
v2.say()

Now, sure, in this case it saves you nothing, but this does also mean that parameters of functions whose type uses one of the `ExpressibleBy*Literal protocols can be passed a literal, rather than a "long-hand" instantiated object. For example:

func Greet( _ h : Hello ) {
    h.say()
}

Greet( "davep" )

I can see that being quite handy.


Swift TIL 5

Posted on 2020-06-26 15:44 +0100 in TIL • Tagged with Swift, Apple • 1 min read

I'm going to file this one under "it makes perfect sense, but I don't think it aids in making the code readable" -- something which I'm finding is a bit of a theme with Swift.

In Swift self gets used and gets used in a way you'd expect from many other languages. So far so good. But, it seems, Self is also a thing too, and it's different from self. Whereas self is the current instance, Self is the current type. So consider this:

class Greeting {

    class func message() -> String {
        "Ayup!"
    }

    func message() -> String {
        "Well hello there"
    }

    func emit() {
        print( Self.message() )
        print( self.message() )
    }
}

Greeting().emit()

When run, the output is:

Ayup!
Well hello there

It makes sense that that's the case. I actually really like the ability to use Self rather than having to use Greeting, but damn that's really setting things up for either mistyping or misreading code. You're going to want to hope that your development environment makes it super obvious what's a value and what's a type when it comes to using font choices.


Swift TIL 4

Posted on 2020-06-25 13:21 +0100 in TIL • Tagged with Swift, Apple • 1 min read

Some languages favour a "one way to do it" approach, some favour "there's more than one way to do it". I'm not sure I'm at a point where I have a feel for what Swift's approach is, but I'm getting the impression it's more the latter than the former.

If there was one thing that made me think that, it was when I found out that Swift's bool type has a toggle method.

var cool = false

print( cool )
cool = !cool
print( cool )
cool.toggle()
print( cool )

giving:

$ swift run
false
true
false

I can see a number of reasons why that's actually going to be handy -- the main one being when you want to throw around a toggling method -- but it still struck me as rather odd on first reading. I also think it's worth me making a personal note about it because foo.toggle() isn't going to stand out as much as foo = !foo when reading code. At least not for a short while.


Swift TIL 3

Posted on 2020-06-24 16:38 +0100 in TIL • Tagged with Swift, Apple • 1 min read

Today's little "Swift TIL" is observers. While reading up on the language I was delighted to find that it has observer support baked right into the language, for any sort of variable. So code like this:

var name  = "David" {

    willSet( new ) {
        print( "About to change name from \(name) to \(new)" )
    }

    didSet( old ) {
        print( "Name changed from \(old) to \(name)" )
    }
}

name = "davep"

Does what you'd imagine:

About to change name from David to davep
Name changed from David to davep

Not only can I see how that'd be useful for the main sorts of purposes that Swift is put to, I can think of many times when I'd have benefitted from that in my general day-to-day work. Of course, you can create an observer approach in any language really, but having an idiom that's part of the language feels nice and tidy.