I've already communicated this with you, Greg & Alex, but I thought I'd shoot the mailing list a summary...
Heads-up: code snippets are coffeescript
My focus has been on high-level declaration of constraints, not so much solver API. My API goals thus far:
- Chain-able, ie.
100 <= w <= 1000 <= w2...
- Close-as-possible resemblance to natural forms of equality and inequality equations. This also makes the Ometa language parsing pretty straightforward.
- Higher-ordered constraint objects that contain constraint primitives. Maybe current
c.Constraint
should bec.ConstraintPrimitive
? A chained constraint equation would contain many constraint primitives. This would also allow subclassing of constraints that internally setup many constraint primitives. - Convention & hooks for subclassing core Constraint object for implementing custom relationships such as "inside", "left-of", etc... I imagine a plugin-like eco-system, where the API can expand to include W3C's grid-layout templates and Apples Visual Format Language for ASCII style configuration.
- Normalize API for
c.Variable
&c.LinearExpression
so linear expressions can be treated just like variables... ie.linearExpression.value()
- "Retained-mode" where state of system can be more intuitively inspected. Naturally as I begin hacking Cassowary, I encapsulated much of its API with my own helpers.
So, to express: 100 <= box3.width <= 1000
My first crack looked like:
c.leq(100, box3.width, c.strong)
c.leq(box3.width, 1000, c.strong)
I wanted a single declaration, so tried method chaining like so:
c(100)['<='](box3.width)['<='](100).strength('strong')
But, method names like <=
was too weird and I lost the data interpabality inherent with JSON, so I moved to a JSON API like:
# returns single constraint
Constraint.create
id: 'box3WidthMinMax'
c: [100, '<=', box3.width, '<=', 1000]
strength: c.strong
# returns array of constraints
Constraint.create [
id: 'box3WidthMinMax'
c: [100, '<=', box3.width, '<=', 1000]
,
id: 'box2WidthMinMax'
c: [50, '<=', box2.width, '<=', box3.width]
]
I prefer a pure JSON configuration, seems more authentically JS, but I'm not satisfied with the c
key for the constraint configuration. And, as Alex points out, the strengths always stick out like a wart. Using an Array for the constraint configuration seems like the right way to accommodate chain-able operators and for configuring Apple-style ASCII layout. For example:
button1.right + 100 == button2.left !strong
menu.left + 10 == button1.left !strong
button2.right + 10 == menu.right !strong
In Apple's VFL, is equivalent to strongly requiring, inside menu
:
h: |-[button1]-100-[button2]-|
Which could be configured w/ JSON like so:
{
h: ['|','-',[button1],100,[button2],'-','|']
inside: menu
offset: 10
weight: strong
}
ConstraintCSS is the best API simply b/c we can write the (in)equality statements in their natural form. Likewise, the best JS API would be something like a CoffeeScript extension that allows the constraint statements to be written in their unaltered form...
This message's Markdown source: gist.github.com/2288542