Saturday, May 21, 2016

What's Missing in the Discussion about Dynamic Swift

There have been some great posts recently on the need for dynamic features in Swift.

I think Gus Muller really nails it with his description of adding an "Add Layer Mask" menu item to Acorn that directly talks to the addLayerMask: implementation:

With that in place, I can add a new menu item named "Add Layer Mask" with an action of addLayerMask: and a target of nil. Then in the layer class (or subclass if it's only specific to a bitmap or shape layer) I add a single method named addLayerMask:, and I'm pretty much done after writing the code to do the real work.

[..]

What I didn't add was a giant switch statement like we did in the bad old days of classic Mac OS programming. What I didn't add was glue code in various locations setting up targets and actions at runtime that would have to be massaged and updated whenever I changed something. I'm not checking a list of selectors and casting classes around to make the right calls.

The last part is the important bit, I think: no need to add boiler-plate glue code. IMHO, glue code is what is currently killing us, productivity-wise. It is sort of like software's dark matter, largely invisible but making up 90% of the mass of our software universe.

After giving some great  examples, Brent Simmons spells it out:

In case it’s not clear: with recent and future articles I’m documenting problems that Mac and iOS developers solve using the dynamic features of the Objective-C runtime. My point isn’t to argue that Swift itself should have similar features — I think it should, but that’s not the point. The point is that these problems will need solving in a possible future world without the Objective-C runtime. These kinds of problems should be considered as that world is being designed. The answers don’t have to be the same answers as Objective-C — but they need to be good answers, better than (for instance) writing a script to generate some code.
Again, that's a really important point: it's not that us old Objective-C hands are saying "we must have dynamic features", it's that there are problems that need solving that are solved really, really well with dynamic features, and really, really poorly in languages lacking such dynamic features.

However, many of these dynamic features are definitely hacks, with various issues, some of which I talk about in The Siren Call of KVO and (Cocoa) Bindings. I think everyone would like to have these sorts of features implemented in a way that is not hacky, and that the compiler can help us with, somehow.

I am not aware of any technology or technique that makes this possible, i.e. that gives us the power of a dynamic runtime when it comes to building these types of generic architectural adapters in a statically type-safe way. And the direction that Objective-C has been going, and that Swift follows with a vengeance is to remove those dynamic features in deference to static features.

So that's a big worry. However, an even bigger worry, at least for me, is that Apple will take Brent's concern extremely literally, and provide static solutions for exactly the specific problems outlined (and maybe a few others they can think of). There are some early indicators that this will be the case, for example that you can use CoreData from Swift, but you couldn't actually build it.

And that would be missing the point of dynamic languages almost completely.

The truly amazing thing about KVC, CoreData, bindings, HOM, NSUndoManager and so on is that none of them were known when Objective-C was designed, and none of them needed specific language/compiler support to implement.

Instead, the language was and is sufficiently malleable that its users can think up these things and then go to implement them. So instead of being an afterthought, a legacy concern or a feature grudgingly and minimally implemented, the metasystem should be the primary focus of new language development. (And unsurprisingly, that's the case in Objective-Smalltalk).

To quote Alan Kay:

If you focus on just messaging - and realize that a good metasystem can late bind the various 2nd level architectures used in objects - then much of the language-, UI-, and OS based discussions on this thread are really quite moot.

[..]

I think I recall also pointing out that it is vitally important not just to have a complete metasystem, but to have fences that help guard the crossing of metaboundaries. [..assignment..] I would say that a system that allowed other metathings to be done in the ordinary course of programming (like changing what inheritance means, or what is an instance) is a bad design. (I believe that systems should allow these things, but the design should be such that there are clear fences that have to be crossed when serious extensions are made.)

[..]

I would suggest that more progress could be made if the smart and talented Squeak list would think more about what the next step in metaprogramming should be - how can we get great power, parsimony, AND security of meaning?

Note that Objective-C's metasystem does allow changing meta-things in the normal course of programming, and it is rather ad-hoc about which things it allows us to change and which it does not. It is a bad design, as far as metasystems are concerned. However, even a bad metasystem is better than no metasystem. Or to quote Guy Steele (again):
This is the nub of what I want to say. A language design can no longer be a thing. It must be a pattern—a pattern for growth—a pattern for growing the pattern for defining the patterns that programmers can use for their real work and their main goal.
The solution to bad metasystems is not to ban metasystems, it is to design better metasystems that allow these things in a more disciplined and more flexible way.

As usual, discussion here or on HN.