Archive for May, 2017

Holy War: This seems wrong

This works:

["23"].map({ Int($0) }) // works

But this doesn’t, presumably because of the defaulted radix argument for public init?(_ text: String, radix: Int = default):

["23"].map(Int.init) // nope
["23"].map(Int.init(_:)) // nope

But this does work:

[("23", 10)].map(Int.init(_:radix:)) // works

and this:

zip(["23"], repeatElement(10, count: .max))
    .map(Int.init(_:radix:)) // works

What do you think? Should this splattage be splermissable or splorbidden?


For those who “wish for this every day”, you can always extend Int:

extension Int {
    /// provides map-specific `String` initialization
    /// e.g. `["23"].map(Int.init(string:))`
    public init?(string value: String) {
        self.init(value, radix: 10)

Grepping for parentheses

Just because I had to do this today and thought I’d share. Either use the -E option, for example,

grep -E "let \(" */*.swift

or use egrep directly:

egrep "let \(" */*.swift

Both egrep and grep -E use extended regular expressions, allowing you to use a simple backslash rather than trying to get your shell to cooperate with hyper-escaping. You can use the same approach with sed as well:

echo "(hi)" | sed -E "s/\(/[/"

I hope this helps someone.

Evolving Label-Directed Tuple Assignments

You may be familiar with standard “tuple shuffles”. In the most common form, you use tuples to rearrange data without intermediate values:

var item1 = "x"
var item2 = "y"

// swap values
(item1, item2) = (item2, item1)
print("\(item1), \(item2)") // "y, x"

You streamline this approach by incorporating tuples into the declaration as well as the value swap:

// declare `item1` and `item2`
var (item1, item2) = ("x", "y")

// swap values
(item1, item2) = (item2, item1)
print("\(item1), \(item2)") // "y, x"

However, you can also use tuple labels to mix and match declarations with values. Right now on Swift Evolution, this is being referred to (incorrectly in my opinion) as a “tuple shuffle”:

// declare `value`
let value = (x: "x", y: "y")

// declare `item1` and `item2`
var (y: item1, x: item2) = value // y, x
print("\(item1), \(item2)") // "y, x"

// use label-based re-assignment
(y: item1, x: item2) = (x: item1, y: item2) //(y "x", x "y")
print("\(item1), \(item2)") // "x, y"

This Swift language feature, regardless of its name, is both obscure, and according to a recent  evolution list discussion, a source of unnecessarily compiler complexity.

Robert Widman has introduced a draft proposal to deprecate label-based declaration:

[This] is an undocumented feature of Swift in which one can re-order the indices of a tuple by writing a pattern that describes a permutation in a syntax reminiscent of adding type-annotations to a parameter list…it can be used to simultaneously [deconstruct] and reorder a tuple…(and)…map parameter labels out of order in a call expression.

Their inclusion in the language complicates every part of the compiler stack, uses a syntax that can be confused for type annotations, contradicts the goals of earlier SE’s (see SE-0060), and is applied inconsistently in the language in general.

There’s been a lively discussion on the Swift Evolution list about the proposal. I thought it was a fairly obvious and simple win. The draft has generated dozens and dozens of replies. Members have discussed both the nuances and possible side effects of the proposed change.

I agree with T.J. Usiyan in disliking the following pattern:

// Declare using labels
let rgba: (r: Int, g: Int, b: Int, a: Int) = (255, 255, 255, 0)

// Declare using re-ordered labels
let argb: (a: Int, r: Int, g: Int, b: Int) = rgba 
// This is the line I have issue with

print(argb.a) // "0"

This unintuitive approach runs counter to Swift’s philosophy of clarity and simplicity. Consider Joe Groff’s default parameter proposal SE-0060 and Austin Zheng’s function argument label type significance proposal SE-0111. Why not ignore label order and focus on type checking? I think the “correct” behavior should act like this instead:


// Declare using re-ordered labels
let argb: (a: Int, r: Int, g: Int, b: Int) = rgba 
// (Int, Int, Int, Int) assigned to (Int, Int, Int, Int)

print(argb.a) // "255"

I’d rename the proposal to “Removing the Ordering Significance of Tuple Argument Labels in Declarations”, and ensure that tuple argument labels aren’t considered when typing the new constant in the previous example.

What do you think?