Archive for the ‘Various Frustrations’ Category

Dear Erica: How do I simplify `Swift.print`?

Dear Erica:

In other languages (Python mostly comes to mind, but I think ml and probably Haskell as well) you can essentially create a new name for a function by assigning it to a variable and use that instead.  All type information and usage follows with it.

I use it a lot in Python to have a local variable that’s  already bound to some otherwise nested module call. It saves some lookup time and textual typing. (Gotta be explicit since syntactic typing is relevant in Swift.) In trying to work around the problem of “print” calling  NSDocument.print, I tried declaring a val at the top level:

let Print = Swift.print // for print to console

The compiler seemed happy with the definition but when I tried to use it as in:

Print(“in makeWindowControllers”)

I got:

Hitting Fix did nothing but I wasn’t really expecting much (this is Xcode 9.0 beta). I assumed it wasn’t  telling me to literally put <#String#> in as a second parameter but that the type inference was inferring a type of String for  parameter #2  It didn’t really make any sense (why would a second parameter be required for a variadic argument?) If two, why not 3…?

So I tried the following but to no avail:

Print(“in makeWindowControllers","two”)

One can obviously write a full function which works fine:

func Print(_ items:Any...) -> () {
    print(items) 
} 

Print("in makeWindowControllers")

It’s pretty simple but seems unnecessarily heavyweight. I can’t seem to find any way to do a variadic closure. Is this possibly a bug or am I missing something obvious? Is there any reason the simple value declaration shouldn’t work? I know I’ve seen complaints about the lack of an Apply function in Swift. Not sure if this is related. My functional mojo is somewhat lacking…

This is a terrific question, and I’m going to answer it in several parts.

First, the full signature of Swift’s version of print is

public func print<Target>(_ items: Any...,
    separator: String = default, 
    terminator: String = default, 
    to output: inout Target) 
    where Target : TextOutputStream

See all those default items?  They don’t travel nicely to closures.  Second, take careful note of the variadic items, because you can’t pass them along by redirecting them to another function. Your “full function” actually prints an array of the items you pass:

Print("Hello world") // prints ["Hello World"]

The only way around this for 10.12 and earlier is to re-implement print (or a reasonable facsimile). Having tried that this morning, I warn you, it is a doozy. Seriously. You wouldn’t believe how many functions and files go into this one little call.

Fortunately, this name-overlap problem (NSView.print vs Swift.print, etc) is fixed in High Sierra. The 10.13 release notes write:

print() methods in Swift: NSWindow, NSView, NSDocument’s print() instance methods have been renamed to printWindow(), printView(), and printDocument() respectively in Swift 4. This fixes the unexpected experience where adding debug logging to a subclass of one of these instances shows a print panel instead.

You can help the variadics don’t propagate cause (“El viva variadics!“) by filing a radar. Go ahead and dupe, mentioning rdar://problem/12134482.

For the moment, here’s a less capable workaround you can use. It does pretty much what you want with slightly reduced capabilities (and complexity) compared to the built-in Swift.print solution.

public func sprint(
    _ items: Any...,
    separator: String = " ",
    terminator: String = "\n")
{
    var prefix = ""
    for item in items {
        Swift.print(prefix, terminator: "")
        Swift.print(item, terminator: "")
        prefix = separator
    }
    Swift.print(terminator)
}

It’s kind of a production-unfriendly workaround for just avoiding Swift.print, but I hope this helps anyway.

Thanks Dave, Tim, Stephen, Caleb

Beta 3 Playground Workarounds

Adding Resources and Sources folders to Playgrounds

Until they’re fixed, you may have to add them by hand.

  1. Right-click/control-click.
  2. Show package contents
  3. You can add new Resources and Sources files at the top level
  4. Alternatively, navigate down to individual pages (which are finally in Beta 3!) by showing their package contents and add them there

Fortunately under Beta 3 you don’t have to manually add pages, as the new page functionality is finally back.

Creating New Playgrounds

They’re no longer listed in the File > New dialog. Instead choose File > New > Playground (Command-Shift-Option-N) or open “Welcome to Xcode” (Command-Shift-1) and click “Get started with a playground”.

Most of the obvious alternatives (like Command-Control-N, which creates new workspaces) are already taken, but if you don’t mind using the menu for that, I think it’s a nicer key binding for “New Playground”. If you want to mess with this open prefs (Command-comma), type playgrounds into the search field, and edit the key binding for “New > Playground”

Don’t forget that new playground page is “Command-Option-N”.

Lessons Learned: iOS Extensions and Keychain Accessibility

Today’s lesson is courtesy of Rizwan Sattar, who writes:

If you’re building a notification service or content extension, keep in mind that these extensions will run even after a device restart, before the first unlock. Normally Apple recommends to set your Keychain items as kSecAttrAccessibleAfterFirstUnlock for “items that need to be accessed by background applications”. When you’re accessing the keychain for things in your notification extensions, you’ll want to set it to kSecAttrAccessibleAlways or kSecAttrAccessibleAlwaysThisDeviceOnly, etc instead.

Thanks Rizwan!

Dropbox’s very bad not okay UX on iOS

Consider this question for a second: why do people own Dropbox? So they can put stuff into it and grab stuff out. Sure, there are other features but that mission statement pretty much the bottom line for iOS use. So why is Dropbox’s iOS client so horrible?

Start with the main menu bar. After selecting an item that you want to open in another app, which of these icons do you tap? The garbage one is clearly wrong, but the ellipsis is a very muddy choice. This should obviously use the (user-facing) share/(developer-facing) actions icon instead.

Apple’s design team agrees.

Once tapped, what’s the next step for “Open in”? Move and copy make sense but you have to tap “Export”, which finally uses the actions icon to give the hint that you want to open the selected file in another application. Bad naming, although it does appear properly as the first action.

Once tapped, you next have to find “Open In”. I have a couple of blockers installed (which shouldn’t even appear in this action sheet), so you have to scroll right to find the right icon.

It’s only after I scroll right that I finally locate “Open In” and can start the progress of opening my file in an appropriate application.

To summarize:

  • The ellipsis is a bad choice. It should be the Action/Share icon and it should directly open the Action Sheet.
  • Rename and Move should be placed into a separate “File actions” menu, along with discard (the trash can). They don’t belong grouped with the Action/Share sheet, which has a specific and conventional meaning in iOS.
  • The app should use care, especially with known file extensions, to limit the options presented in the sheet. “Open In” should be about the only choice for an epub extension file, and the other actions should be constrained to the invoked context.
  • Dropbox made me sad.

Holy War: Why I utterly loathe the new app switcher in iOS 11

Beta 3 Update: iOS 11 Beta 3 now supports swipe-up-to-close instead of the tiny little “x” buttons.

Under iOS 10, you could switch between apps or remove an app from the “recent list” by following these simple steps:

  1. Double-click the Home button to see recently used apps.
  2. Swipe left or right to find the app that you want to use.
  3. Tap the app or swipe upwards to quit/remove it from the list.

  • Each page was  clear and easy to identify. The app name and icon appeared on top.
  • The nearly full size rolodex presentation ensured that users with poor eyesight could easily identify each app.
  • The swipe area to select or remove an app was large, supporting users with a wide range of dexterity skills and motor limitations.

It was a great system that worked well.

In iOS 11, Apple redesigned. It decided to combine this recently used apps list with the control center, so that you could put as much information on-screen at once as possible. This produced an interface with teeny tiny images, and lots of user confusion overload.

In other words, in the current beta and the presentation at WWDC, they espoused a system that is best used by nimble millenials who unlike most every fidget-spinner-ing millenial I have ever met, would not be overwhelmed by sensory overload when presented with far too much information on a single screen.

In my opinion, this new design doesn’t work for the young, the old, the millenial, the seasoned pro, the able, the dis, the hawkeyed, or the near blind. Apple basically disregarded every rule of human usability and thrown it all together into a jumbled disorganized mess:

Compare this screen, with its dock, its windows, and its nearly two dozen control affordances to the iOS 10 version.  It’s a big jumbled insane mishmash of a UI design mess.

The controls in particular are unlabeled. Consider the timer, alarm, and stopwatch icons. They’re nearly identical and randomly scattered. And I can’t for the life of me remember what the dot is to the right of the camera.

As I constantly harp on about, a key factor in enhancing usability is to prioritize recognition over recall. As much as the Apple engineers have aimed to make all the buttons recognizable, they really aren’t.

You have to remember what a lot of these items do: the man in a circle, the magnifying glass, the three different clock faces, etc. You must further remember what happens when you tap and hold these as several of these items have secondary panels with embedded controls beneath them.

This 3-in-1 design breaks George A. Miller’s basic rule of working memory. Miller’s rule argues that you should not present the user with an overwhelming number of interactive items at once. The user cannot effectively remember and strategize interactions when shown more than seven or nine items at a single time. It’s as if Apple didn’t bother passing this screen through a usability evaluation process.

Working memory is not all that’s wrong with this design. In iOS 10, you just tapped or swiped up to manage apps. Those are both relatively large motor functions that require little fine control. That makes them an excellent match for a wide range of user ages and abilities. (Plus the pictures are all big and easy to recognize!)

Compare with iOS 11. To remove an app from the recents list, here’s what you have to do:

  1. Enter the control center. (In an improvement over iOS 10, this can be done with double tap, even if you’ve disabled swipe-up for the control center.)
  2. Swipe left and right to locate the app of interest.
  3. Tap and hold any app screen until the “X” buttons appear (and, maddeningly, the icons and app names disappear). This wait is short but frustrating.
  4. Tap exactly on the “X” to dismiss any app. This usually takes me upwards of three or four tries because the “X” is so small, my coordination is bad, and apparently I may need to re-align my touches with the OS.

In the end, the new control center a big giant mess trying to do too much in a massive design mishmash. I wish Apple would go back to its original design, although I wouldn’t mind some way to access the control center from the App Switcher.

Update: Oh you have to be kidding me:

If you like my posts and you want to say thanks for helping to prevent the meltdown of global civilization (“But if I’m right, and we can swap out that screen shot… Lenny, you will have saved the lives of millions of registered voters”), consider buying a book.  Save the Turtle, save the World. Choose the form of your Constructor. Thanks, all!

The problem with Swift Playground localization

Starting in Swift Playgrounds 2, you can now use localized strings to guide the narration of your interactive lessons. As the screenshot above demonstrates, you can used localizable markup to provide the most appropriate text for titles, introductory text, and feedback.

However, what you can’t do is localize Swift members. Your French and Chinese consumers must tell Byte to moveForward(), not avancer() or 向前移动().

One of the guiding principles of the Swift language is demonstrated in its embrace of unicode for identifier symbols. This approach accommodates programmers and programming styles from many languages and cultures.

Xcode 9 has introduced major advances in code refactoring. It seems an obvious win to allow that technology to be applied to Swift Playgrounds 2, enabling identifier localization.

That’s because identifiers play such a key role in Swift Playgrounds. Unlike standard development tasks, where it’s unnecessary to create idiomatic APIs like IUContrôleurDeNavigation, the point of Swift Playgrounds is to teach and instruct. It uses small, limited, controlled API exposure, nearly all custom and supporting of the teaching story.

The anthropomorphized Byte character acts as a stand-in for the learner coder. And in doing so, it should communicate with commands that this coder identifies with, turnLeft and moveForward, not incomprehensibleForeignPhrase1 and evenMoreConfusingForeignPhrase2.

I think this is an opportunity waiting to happen, and I can’t imagine it would be all that hard to implement given the expansive identifier suite and the limited API visibility presented in a typical playgroundBook.

What do you think? Is it too much to ask for a localizable.Members.plist?

Bug reporter complaints

I wasn’t part of the bug reporter preview but having used it today, I’ve got to say that I am not a huge fan of the updated interface. It may be pretty, but for me it’s harder to use. I’d rather see icons and names at the start of the entry screen than scroll through three pages of iconless text (and their subtables) as I try to recognize the phrase that best matches my issue.

It’s funny because this design is a clearly cognitive mismatch between how I used to find the right items, which was just a matter of a single-screen scan, and trying to construct or detect the right verbal phrase that now matches the target issue. The new system is hitting the wrong part of my brain.

If you look at it, it’s laid out very nicely, with big clear areas to enter text and the “drop a screenshot” system is vastly improved over the old system. (Nice job there!) I like the font choices, can live with the sickly purple, and a lot of thought has gone into streamlining issue entry.

That said, the whitespace feels like there’s too much there, the left-to-right range of field width is too hard to scan to review the information you’ve entered, and as I mentioned before, the ‘What are you seeing an issue with?” tables are a little too much for me to process.

If I were to redesign it, I’d:

  • Change the wording to be more business-like: “Classify this issue:”, not “How would you classify this issue?”. “Affected Product or Area”, not “What are you seeing an issue with?”. “Bug or Suggestion”, not “What kind of issue are you reporting” (with the bias being towards ‘bug’, since that’s the primary purpose of the tool.) “Reproducing the issue”, not “What steps can we take to reproduce this issue”, and so forth.
  • In the prompt text, I’d eliminate weasel words. “Step-by-step instructions to reproduce this problem”, not “Please provide a step-by-step set of instructions to reproduce the problem (if possible).”
  • I’d cut back massively on the vertical whitespace, allowing more of the report to be seen at once. There’s just too much floaty gray for my taste.
  • I’d apply one of the “optimal line length” studies, which suggests anywhere between 50 and 75 characters per line for text (which is most of what this tool provides) and 80-160 characters for code entry. (I’d also consider a code-specific “related code” field.) The current width is about 98 characters if I counted correctly. It is very hard to track from the right back to the left while maintaining vertical positioning.
  • I’d explicitly mention Markdown/Common Mark support for bullets and numbering, as well as other markup.
  • I’d change the Suggestion/Bug toggle into either a radio control or a visual toggle with Bug, which should be to the left, pre-selected.
  • I’d massively increase the size of the “Cancel/Save/Submit” buttons and move them from the bottom bar to the main field under attachments.
  • Finally, I’d add a specific call out on completion. Thank the developer for taking time from their busy workday and express appreciation for participating in the radar process. Enroll them either in a rewards-for-radars program or a random giftcard giveaway for the month. It’s a small price to sweeten that “Radar or GTFO” message and it lowers frustration of typing into a big, faceless, low-feedback system.

Those are my thoughts. What are yours?

Xcode Autocomplete Frustrations

A year after it debuted, Xcode’s enhanced autocomplete features continue to struggle with overly liberal matches:

In this example, several of the matching text results display few commonalities with my search phrase . There’s really no reason that “fatale” should match CFDataGetLength(theData: CFData!).

It shouldn’t be hard to create heuristics that count the number of matched chunks, their distance from each other, to build a score related to whether the match is chunky (a good thing for keywords) and singular (another good thing for discerning developer intent).

Successful autocompletion promotes good matches and discards inappropriate ones. “upper” should score high on CFStringUppercase and low on CGScreenUpdateOperation and CSSMERR_TP_INVALID_CERTGROUP_POINTER.

That’s not the only problem with autocomplete. Image literal completion is a big problem. Xcode often prioritizes images over code APIs. When starting to type “picker”, Xcode should not suggest “picture-of-lovely-cat”. Here are some real world examples of this issue:

One developer told me that while typing in for closures, that eighty percent of the time, he gets a random autocompleted image literal instead of the keyword he’s shooting for:

Surely, this is an obvious place to introduce autocomplete preferences that allow you to exclude literals from the API list. The auto complete for image literals should act more like colors, offering an Image Literal entry point to a image picker instead of clogging the API name space:

It would certainly get rid of those inappropriate in matches.

Thanks Olivier Halligon, Andrew Campoli, and everyone else who gave me feedback and direction for this post.

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.