Lion: Cocoa Autolayout Release Notes
developer.apple.com
developer.apple.com
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.]
This is a cool idea. Instead of specifying layout inside strings, did you consider syntactic sugar or macros to do it in code?
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.
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.
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.
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).
Apple's done nothing original here.
Lots of people do original things, but not very well.
Has anything been done towards this direction to generate CSS layouts? It seems like it could cure some headaches.
Demos: http://developer.apple.com/library/mac/#samplecode/Cocoa_Aut...
It's one of the most brilliant yet underappreciated bits of software I've come across. Are there others?
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. ;)
But it's not clear to me constraint-based layout deals well with dynamic content; this may be a tradeoff.
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.
Is there a link to a pdf version or something, somewhere?