Archive for February 20, 2017

Monday, February 20, 2017

Provide Custom Collections for Dictionary Keys and Values

SE-0154:

This proposal address two problems:

  • While a dictionary’s keys collection is fine for iteration, its implementation is inefficient when looking up a specific key, because LazyMapCollection doesn’t know how to forward lookups to the underlying dictionary storage.
  • Dictionaries do not offer value-mutating APIs. The mutating key-based subscript wraps values in an Optional. This prevents types with copy-on-write optimizations from recognizing they are singly referenced.

[…]

Dictionary values can be modified through the keyed subscript by direct reassignment or by using optional chaining. Both of these statements append 1 to the array stored by the key "one":

// Direct re-assignment
dict["one"] = (dict["one"] ?? []) + [1]

// Optional chaining
dict["one"]?.append(1)

Both approaches present problems.

The proposed solution is an improvement but still seems a bit awkward.

Update (2017-02-20): Airspeed Velocity:

There are other changes likely for Swift 4 that would make this less awkward (e.g. to supply a default value when subscripting).

It’s just that this particular change was ABI impacting (changes the type of Dictionary.Value) so was proposed during stage 1.

Dash 4

Kapeli (tweet):

Docset Playgrounds – Most docsets now show “Play” buttons which let you quickly test snippets of code

[…]

Search Using Selected Text – This feature has been completely remade and is now more reliable, even in apps that don’t support system services.

[…]

Tab Improvements – You can now reopen the last closed tab, duplicate tabs and close all tabs except for the selected one

[…]

You can now copy the external URL of documentation pages for easier sharing

To make the Play button show up for Apple’s documentation, make sure that the language is set to Swift.

Ruby’s reject!

Accidentally Quadratic (Hacker News):

The code used to be linear, but it regressed in response to bug #2545, which concerned the behavior when the block passed to reject! executed a break or otherwise exited early. Because reject! is in-place, any partial modifications it makes are still visible after an early exit, and reject! was leaving the array in a nonsensical state. The obvious fix was to ensure that the array was always in a consistent state, which is what resulted in the “delete every time” behavior.

I find this interesting as a cautionary tale of how several of Ruby’s features (here, ubiquitous mutability, blocks, and nonlocal exits) interact to create suprising edge cases that need to be addressed, and how addressing those edge cases can easily result in yet more problems (here, quadratic performance).