User interfaces are not pure functions of the model (2018)

When I first saw React.js I took a quick peek and thought that was cool, they finally figured out how to make a Cocoa-like MVC UI framework in JavaScript.

Of course they could have just used Cappuccino, but "details". A few more details were that their version of drawRect: was called render() and returned HTML instead of drawing in a graphics context, but that's just the reality of living in a browser. And of course there was React-Canvas.

Overall, however, using a true MVC UI framework seemed like a big step up from directly manipulating the DOM on user input, at least for real applications.

Imagine my surprise when I heard about React.native! It looked like they took what I assumed was an implementation detail as the main feature. A closer look confirmed my suspicions.

Fortunately, the React.js team was kind enough to put their basic ideas in writing: React - Basic Theoretical Concepts (also discussed on HN). So I took a look and after a bit of reading I decided it would be useful to do a side-by-side comparison with the equivalents of these concepts in Cocoa as far as I understand them. React Cocoa Transformation

The basic premise of React is that user interfaces are simply a projection of data into a different data form. The same input gives the same output. A simple pure function.

function NameBox(name) { return { fontWeight: 'bold', labelContent: name }; } Transformation One of the fundamental principles of Cocoa, and MVC in general, is that user interfaces are a projection of data into a different form of data, specifically bits onto a screen. The same input gives the same output. A simple method: -(void)drawRect:(NSRect)aRect { ... } Due to the fact that screens and the bits they contain are quite expensive, we use the screen as an accumulator instead of returning the bits from the method.

We do not make the (unwarranted) assumption that this transformation can or should be expressed as a pure function. That would be nice, but there are plenty of reasons why it's not a good idea, some pretty obvious.

Abstraction

However, you cannot integrate a complex user interface into a single function. It is important that user interfaces can be abstracted into reusable elements that do not disclose their implementation details. Like calling one function from another.

function FancyUserBox(user) { come back { borderStyle: '1px solid blue', Child content: [ 'Last name: ', NameBox(user.firstName + ' ' + user.last name) ] }; } { first name: 'Sebastian', name: 'Markbåge' } -> { borderStyle: '1px solid blue', Child content: [ 'Last name: ', { fontWeight: 'bold', labelContent: 'Sebastian Markbåge' } ] }; Abstraction While it's possible to render an entire UI in the drawRect:: method of a single view, and NSOpenGLView users tend to do this, it's generally better to break complex UIs into reusable parts that do not disclose their implementation details.

Fortunately, we have such reusable parts, they are called objects, and we can group them into classes. Following MVC naming conventions, we call objects that represent UI views, in Cocoa they are an instance of NSView or its subclasses, in CocoaTouch the common superclass called UIView.

Composition

To achieve truly reusable functionality, it's not enough to just reuse sheets and create new containers for them. You should also be able to create abstractions from the containers that make up other abstractions. The way I think of "composition" is that they combine two or more different abstractions into a new one.

function FancyBox(children) { come back { borderStyle: '1px solid blue', children: children }; } function UserBox(user) { return FancyBox([ 'Last name: ', NameBox(user.firstName + ' ' + user.last name) ]); } Composition

To achieve truly reusable functionality, it's not enough to just reuse sheets and create new containers for them. You must also b...

When I first saw React.js I took a quick peek and thought that was cool, they finally figured out how to make a Cocoa-like MVC UI framework in JavaScript.

Of course they could have just used Cappuccino, but "details". A few more details were that their version of drawRect: was called render() and returned HTML instead of drawing in a graphics context, but that's just the reality of living in a browser. And of course there was React-Canvas.

Overall, however, using a true MVC UI framework seemed like a big step up from directly manipulating the DOM on user input, at least for real applications.

Imagine my surprise when I heard about React.native! It looked like they took what I assumed was an implementation detail as the main feature. A closer look confirmed my suspicions.

Fortunately, the React.js team was kind enough to put their basic ideas in writing: React - Basic Theoretical Concepts (also discussed on HN). So I took a look and after a bit of reading I decided it would be useful to do a side-by-side comparison with the equivalents of these concepts in Cocoa as far as I understand them. React Cocoa Transformation

The basic premise of React is that user interfaces are simply a projection of data into a different data form. The same input gives the same output. A simple pure function.

function NameBox(name) { return { fontWeight: 'bold', labelContent: name }; } Transformation One of the fundamental principles of Cocoa, and MVC in general, is that user interfaces are a projection of data into a different form of data, specifically bits onto a screen. The same input gives the same output. A simple method: -(void)drawRect:(NSRect)aRect { ... } Due to the fact that screens and the bits they contain are quite expensive, we use the screen as an accumulator instead of returning the bits from the method.

We do not make the (unwarranted) assumption that this transformation can or should be expressed as a pure function. That would be nice, but there are plenty of reasons why it's not a good idea, some pretty obvious.

Abstraction

However, you cannot integrate a complex user interface into a single function. It is important that user interfaces can be abstracted into reusable elements that do not disclose their implementation details. Like calling one function from another.

function FancyUserBox(user) { come back { borderStyle: '1px solid blue', Child content: [ 'Last name: ', NameBox(user.firstName + ' ' + user.last name) ] }; } { first name: 'Sebastian', name: 'Markbåge' } -> { borderStyle: '1px solid blue', Child content: [ 'Last name: ', { fontWeight: 'bold', labelContent: 'Sebastian Markbåge' } ] }; Abstraction While it's possible to render an entire UI in the drawRect:: method of a single view, and NSOpenGLView users tend to do this, it's generally better to break complex UIs into reusable parts that do not disclose their implementation details.

Fortunately, we have such reusable parts, they are called objects, and we can group them into classes. Following MVC naming conventions, we call objects that represent UI views, in Cocoa they are an instance of NSView or its subclasses, in CocoaTouch the common superclass called UIView.

Composition

To achieve truly reusable functionality, it's not enough to just reuse sheets and create new containers for them. You should also be able to create abstractions from the containers that make up other abstractions. The way I think of "composition" is that they combine two or more different abstractions into a new one.

function FancyBox(children) { come back { borderStyle: '1px solid blue', children: children }; } function UserBox(user) { return FancyBox([ 'Last name: ', NameBox(user.firstName + ' ' + user.last name) ]); } Composition

To achieve truly reusable functionality, it's not enough to just reuse sheets and create new containers for them. You must also b...

What's Your Reaction?

like

dislike

love

funny

angry

sad

wow