Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Lion: Cocoa Autolayout Release Notes (developer.apple.com)
114 points by cpr on July 21, 2011 | hide | past | favorite | 25 comments


Some of that document is out of date - Interface Builder does have support for Auto Layout now. Auto Layout also has a space now. ;-) I like to spell it [Auto]-[Layout] (see the ASCII art programming language part of that document).

People may also be interested in the WWDC session on Auto Layout: http://goo.gl/5sSgK (requires free developer account).

Some interesting aspects of the system to me:

(1) The use of fairly simple but freeform constraints. The numerical solver is based on work in this paper, http://goo.gl/6fHdd. They end up covering really a lot of stuff you want to do in a natural way, and with a single constraint object with few properties.

(2) The emphasis on visualization. Most of the time constraints are created visually, in Interface Builder, by dragging objects around and snapping them together. When doing layout in source code, you use an ASCII art inspired format string that visually looks like the interface you're trying to create. When debugging at runtime, you can ask a window to draw constraints on screen, so that you can see what they are. (The debugging support itself is also interesting.)

(3) The reworking of how layout fits into Cocoa's model-view-controller design. Previously, too much was in the controller layer - to do layout you ended up having to say things that you didn't really know, because it was data intrinsically known by the view layer. By reworking the layering, the views can take responsibility for those aspects of layout that are intrinsically known to the view. This takes a lot of pressure off, because (a) you don't have to specify things you don't know, (b) there's less work to do because the views are doing some of it, (c) a lot of the time the views are coming out of AppKit, so you never have to write the view parts at all. It also aligns the easiest thing to do (don't mess with the views) with the right thing to do (use standard OS behavior). If you want to make it do something unusual, you can, but you have to say so. Your code records the places you intentionally deviated.

[Disclosure - I worked on this.]


> When doing layout in source code, you use an ASCII art inspired format string that visually looks like the interface you're trying to create.

This is a cool idea. Instead of specifying layout inside strings, did you consider syntactic sugar or macros to do it in code?


Yes… let's talk macros first. Actually, first first you should look at multi-dimensional analog literals if you haven't seen it, http://weegen.home.xs4all.nl/eelis/analogliterals.xhtml. Awesome/yikes.

Okay, back. What are the reasons to consider macros? Probably, compile time checking and ability to directly use variables that are in scope (e.g., fooButton for some button).

The goal of compile time checking is really debugging, to make it easy to find and fix mistakes. Now, in a format string, we don't have compile time checking, but we can have really good, descriptive error messages. Our diagnostics were inspired by those in clang, http://blog.llvm.org/2010/04/amazing-feats-of-clang-error-re..., right down to the carat pointing at the problem within the code. Maybe we could have done that with macros? I guess I didn't really try that hard, but usually if you mess up a macro, you're going to get something really cryptic from the compiler. Also, it's wayyyy easier for the client to grok and feel comfortable with a format string than with a crazy macro system. You know how we're parsing the string. You could implement it yourself if you had to. It's understandable, and you can see that there won't be side effects. Now consider that multi-dimensional analog literals link above. Does it work? Heck yeah! Do you want black magic like that in your code, with behavior you don't understand (at least without way more investment in understanding than we want to require)? Probably not! Plus, we're likely to have to compromise on the visual design of the language now and/or in the future to contort it into what's technically possible in macros over ObjC. This will also hurt debugging, in that you'll be less likely to quickly understand what your code says. So for debugging, I don't think macros are actually going to be a win, despite the compile time checking. And really, the above concerns are enough to kill macros for me.

Plus, we might be able to recover most of the compile time checking anyway. I'd love to see clang's __attribute__ format extended to do checking of Cocoa visual format strings. http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html#i.... We have a bug tracking this.

Ability to directly use variables is a positive for macros. As is, we have to pass a dictionary on the side that maps identifiers to actual view objects. In python you could pass locals(), but ObjC doesn't maintain a symbol table at runtime. For this we actually do pull a skankier-than-usual macro trick to make things easier.

    id views = NSDictionaryOfVariableBindings(fooButton, barButton);
expands to something equivalent to

    id views = _NSDictionaryOfVariableBindings(@"fooButton, barButton", fooButton, barButton, nil);
and _NSDictionaryOfVariableBindings parses the comma separated string to make a dictionary mapping @"fooButton" -> fooButton.

    #define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil)
    APPKIT_EXTERN NSDictionary *_NSDictionaryOfVariableBindings(NSString *commaSeparatedKeysString, id firstValue, ...); // not for direct use

Okay, last, why not make this an actual part of Objective-C, like regexes are in some languages or like LINQ is in C#.

I feel like the reasoning here is more wishy-washy, so I don't know, maybe it's wrong and we'll revisit it. Our system has a continuum from leaf code on which nothing else depends, like apps, down through AppKit, Foundation, and Objective-C. The continuum isn't really defined by what framework some code is in, it's defined by how much sits on top of it in the dependency stack. As you go down toward the deeper and more built-upon parts of the system, reliability becomes more and more important, and our ability to cheaply change our minds if an interface isn't working out goes down. The standards for simplicity and wide applicability go up and up. Objective-C's deep. You can literally learn _all_ of Obj-C in a weekend if you know C. We like that. In recent releases we have relayered things like memory management (GC, ARC) and properties from being framework conventions to being formal parts of the language. But that's where the language is right now. There's a pretty clear divide between language and framework, and the language doesn't reach up and violate the layering much. If we're thinking about moving something like these layout format strings into the language, we should also be thinking about printf-style format strings (or other templating), Core Data predicates, regular expressions and lots of other Cocoa-ness - basically obliterating the existence of any kind of layer boundary between ObjC and Cocoa. These would be extremely controversial changes, inside and outside of Apple. That doesn't necessarily make them wrong, but I'm not confident they're right. Anyway, it's something that could be considered in the future.


In my/the ideal world, clang would have some plugin feature where it knows that it must pass that string to some external DLL for validation. Ideally, that DLL should be able to generate code (just as the C preprocessor), but I fear that would require quite some interface between plug-ins and clang.

I think it already would be a big win if that DLL only could use the compiler state to issue error messages.

Open problem is how clang would know that a string needs external validation. I think a variant on the @"string" format might work:

    id myConstraint = @layout"[button]-[textField]";

    id myRegex = @regex"^[a-z]+$";
(I say might because the C++ grammar has some corners that may deliver surprises here; with (im)proper function overloading, the compiler might find a way to interpret @layout as taking the address of layout)

The link between prefix and DLL should be a command-line argument to clang. Problem, of course, is that you give up compatibility with other compilers. Also, this is more clunky than it needs to be; in a 'proper language' like Lisp the integration would be seamless.


Thanks for an awesome answer. I agree that your approach with format strings is right, but it was great to hear reasoning against the other options.

I agree that macros are dangerous for an embedded language. In our iOS C++ framework, they have their uses, mainly if we want to reduce boilerplate code, when

- bridging ObjC/C++ worlds

- creating e.g. record data types with JSON parsing & other common functionality for records

- creating handle objects for refcounted objects

but for more complex "embedded languages" we have resorted to C++ templates. Properly used, the give us very nice APIs, but build times are quite bad.

Sidenote: I'd love to get an email notification (opt-in per my comment) from HN if someone answers/comments on my comment. Your answer went unnoticed by me for 2 weeks.


I wonder how this constraint approach fits together with classic design principles. For example, an often used design principle is that of grid systems. Does the constraint approach somehow naturally include the grid systems approach?


I wonder about the NSDictionaryOfVariableBindings used in the example. Never have seen that before, very interesting.


It's also new with this API.


The syntax is crazy, but brilliant. I would never have thought of it myself, but now that I've seen it it's obvious.

The main thing I wonder is whether the syntax is supported by vanilla objective c, or if Apple is cheating a little (i.e. building support for new hotness into the compiler).


I did this years ago, in a project called Claro, and then again in http://ihate.rubyforge.org/profligacy/lel.html and pretty much every GUI framework I've done. I got the idea from Wiki syntax and the Cassowary constraint solver as well as Knuth's algorithm.

Apple's done nothing original here.


I think whether they've done it well is more important than if they've done something original.

Lots of people do original things, but not very well.


This is awesome. This concept of building elastic layouts with ASCII code is new to me and I agree with @jamesaguilar that it's one of those obvious yet genius ideas.

Has anything been done towards this direction to generate CSS layouts? It seems like it could cure some headaches.



The visual format is supplied to the layout system as a string. It's completely independent of the Objective-C language syntax.



The first time I saw compiled constraint based mini-languages like this was in OpenLaszlo:

http://www.openlaszlo.org/

It's one of the most brilliant yet underappreciated bits of software I've come across. Are there others?


I love the constraint system in OpenLaszlo too, and I've used OpenLaszlo for many projects. The "Garnet" user interface system, developed in the 90's by Brad Meyers at CMU, also has constraints for laying out user interfaces. I worked on both Garnet at CMU and OpenLaszlo at Laszlo Systems. Here's a description and comparison of the two systems, that I wrote a while ago:

Constraints and Prototypes in Garnet and Laszlo: http://www.donhopkins.com/drupal/node/69

"Once you've tasted a programming language with constraints, you will not want to go back. Programming without constraints is like writing in machine language: error prone, low level, tedious, inefficient and mind numbing."

"Constraints are like structured programming for variables: In the same way that it's better to use loops and conditionals instead of gotos, it's also better to use declarative programming that says what you mean, instead of imperative peeks and pokes and side effects."

A description of OpenLaszlo:

What is OpenLaszlo, and what's it good for? http://www.donhopkins.com/drupal/node/124

I also worked briefly on a cross platform gui system called Galaxy, for a company called Visix, which had a constraint system called "springs and struts". But it turned out they were evil so I left. (The company, not the springs and struts. ;)


The whole boxes-and-glue model reminds of TeX. Sure, constraint-based layout models are nothing new, but here we've got some specific similarities: line-based processing, optional arguments (H|V) in front, and especially priorities. Assigning priorities to different constraints is what allows TeX to degrade gracefully... before manifesting myriads of hard-to-trace bugs.


Is this really the first constraint-based layout system in OSX land?


No. The existing Cocoa system was constraint based too, just more restrictive constraints (view to superview only). CoreAnimation had a constraint based layout system, Carbon had a constraint-based system.. just "constraint-based" doesn't capture what's interesting.


Ok. Still miles away from what WPF proposes...


The WPF system is hierarchical rather than constraint-based. I've done a variety of complex (I mean really complex) WPF layouts that need to scale, and they're complex and fiddly. In many cases I would rather have had a constraint system. When you try to align things to a layout grid in any way, for example, it becomes very awkward.

But it's not clear to me constraint-based layout deals well with dynamic content; this may be a tradeoff.


I was told that WPF could produce "swastika" layouts. Ie, something along the lines:

        aaaaa bb
        aaaaa bb
              bb
        dd    bb
        dd    bb
        dd
        dd ccccc
        dd ccccc
This is as tabular as "grid" from Tk. You can resize any of "a", "b", "c" or "d" widgets and everything will resize accordingly.

So I have an impression that WPF is constraint-based.


How so?


This document is too long to read on a screen (yes, I'm old). I got it into Instapaper, but would prefer physical paper.

Is there a link to a pdf version or something, somewhere?




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: