Archive for March 10, 2017

Friday, March 10, 2017

Making Swift Enums and Structs Equatable

Ole Begemann:

The downside of not having a default case is, of course, more boilerplate to write. […] This isnʼt fun to write, and it would get even worse with more cases. The number of states the switch statement must distinguish grows quadratically with the number of cases in the enum.

[…]

You can make this considerably more manageable with some intelligent application of the _ placeholder pattern. While we saw above that a single default clause is not enough, one pattern per case is.

Ole Begemann:

Unfortunately, like the enum example I talked about in the previous post, this conformance to Equatable is very fragile: every time you add a property to the struct, you have to remember to also update the implementation of the == function. If you forget, your Equatable conformance will be broken, and depending on how good your tests are this bug has the potential to go undetected for a long time — the compiler wonʼt be able to help you here.

[…]

It occurred to me to use the standard libraryʼs dump function as a safeguard. dump is interesting because it uses Swiftʼs reflection capabilities to create a string representation of a value or object that includes all storage fields.

[…]

The biggest drawback of the solution might be that dump is not a perfectly reliable way to determine equality. It should be pretty good at avoiding false negatives, but youʼll probably see some false positives, i.e. values that really are equal but whose dump outputs are different.

Rust’s Language Ergonomics Initiative

Aaron Turon (via Joe Groff, Hacker News):

There are three dimensions of the reasoning footprint for implicitness:

  • Applicability. Where are you allowed to elide implied information? Is there any heads-up that this might be happening?
  • Power. What influence does the elided information have? Can it radically change program behavior or its types?
  • Context-dependence. How much of do you have to know about the rest of the code to know what is being implied, i.e. how elided details will be filled in? Is there always a clear place to look?

The basic thesis of this post is that implicit features should balance these three dimensions. If a feature is large in one of the dimensions, it’s best to strongly limit it in the other two.

The ? operator in Rust is a good example of this kind of tradeoff. It explicitly (but concisely) marks a point where you will bail out of the current context on an error, possibly doing an implicit conversion on the way. The fact that it’s marked means the feature has strongly limited applicability: you’ll never be surprised that it’s coming into play. On the other hand, it’s fairly powerful, and somewhat context-dependent, since the conversion can depend on the type where ? is used, and the type expected in the scope it’s jumping to. Altogether, this careful balance makes error handling in Rust feels as ergonomic as working with exceptions while avoiding some of their well-known downsides.

St. Clair Software Leaves the Mac App Store

Jon Gotow:

For both applications, complying with Apple’s sandboxing and feature constraints to get them approved for sale would have required significant rewrites. And in Jettison’s case, it would also require that buyers download a separate helper app to enable its full functionality. I realize that some people will be put off or inconvenienced by the fact that these apps are no longer in the Mac App Store – my apologies if you’re one of those folks, but it just doesn’t make sense for Jettison and HistoryHound.

Their other two products are App Tamer, which I’ve been meaning to try to reduce Dropbox’s CPU use, and the venerable Default Folder X. Those are probably impossible to sandbox.

Update (2017-03-11): See also: Sip and Videoloupe (via Bad Uncle Leo).

Time Out 2’s Supporter Business Model

David Sinclair:

A year after release, the supporter model is still working well. If you’re not familiar, the basic idea is that someone can download Time Out and use it for free, but some features only work for an hour at a time, as often as they like. So they can try all of the functionality, at their own pace, and decide if the advanced features are useful to them. If so, they can become a supporter for three, six, or twelve months. This permanently unlocks all of the current features as a reward. Even when the supporter period expires, those features remain fully available. So they can choose to extend their supporter status, or just keep using the app without paying any more. Of course, I hope that people do renew, to help fund ongoing sustainable development.

At present, about 9% of people who download Time Out end up purchasing one of the supporter options... which is a reasonable "conversion rate", which can often average more like 5% for normal trial apps. I feel pretty comfortable with that. But I’m also happy that people who choose not to become a supporter can still use a great break reminder tool to help them get or stay healthy.

[…]

Looking at both editions combined, you can see that most of the purchases were through the Mac App Store[…] Again, combining them into one chart, you can see that [revenue is] pretty much neck-and-neck for direct vs Mac App Store, due to the larger slice of the pie that Apple takes.

Playing Jenga With Swift’s Type Checker

Vincent Esche (via Todd Ditchendorf):

One would expect both of these minimalistic programs to be semantically equivalent and thus be handled identically by the compiler, no?

The answer to this question and many more can be found in the Swift project’s official documentation on its “Type Checker Design and Implementation” (emphasis mine):

Swift implements bi-directional type inference using a constraint-based type checker that is reminiscent of the classical Hindley-Milner type inference algorithm. […]

The Swift language contains a number of features not part of the Hindley-Milner type system, including constrained polymorphic types and function overloading, which complicate the presentation and implementation somewhat. On the other hand, Swift limits the scope of type inference to a single expression or statement, for purely practical reasons: we expect that we can provide better performance and vastly better diagnostics when the problem is limited in scope.

[…]

Repeat after me: “Swift limits the scope of type inference to a single expression or statement”.