HNHacker News
TopNewBestAskShowJobs

grayrest

1,959 karma · joined May 10, 2009

front end guy
submissionscomments
grayrest··on Microsoft Edge gets native ECMAScript 7 async/await support in latest build
The problem isn't the propagation, it's the propagation by default. He wants errors that occur in development to pop a stack trace as soon as the error occurs without needing to attach a .catch handler.
grayrest··on Microsoft Edge gets native ECMAScript 7 async/await support in latest build
I wish the we were getting F#'s computation expressions+asynchronous workflows (monad sugar) instead of C#'s async/await.
grayrest··on Redox: A Rust Operating System
The same region/ownership discipline that Rust provides to handle memory turns out to be useful in other contexts. One is resource usage: you have to close a file handle after opening it, etc. Patterns for cleaning up after yourself are common in many languages. What Rust provides is a way to describe how long something should live and a way to enforce correct usage through compile time type checks. This can be used to ensure people using the library are unable to do the wrong thing. As a simple example, using a mutex incorrectly in safe Rust will not compile. More complex examples:

https://medium.com/@tomaka/the-glium-library-5be149d87dc1

https://blog.mozilla.org/research/2014/08/26/javascript-serv...

grayrest··on New React Developer Tools
Not so much confusing as my own ignorance. My last pass through Polymer was two years (I think) ago and there's been a number of changes to the components specs that I've been ignoring. At the time I saw a lot of excellent examples/docs related to encapsulation and none related to content insertion. I'll take another look later this year.
grayrest··on The React digest – A hand-picked weekly selection of the best React JavaScript resources
I can! The idea of unidirectional dataflow is pretty good but the rest of the ideas in Flux aren't as good. For Facebook's implementation, I find making a change requires a bunch of related changes in a bunch of files and I don't like having stores chain.

If you stick all your data into a single big tree/store, you can inspect/serialize and pull off tricks like snapshotting, session recording, simple undo/redo, and time travelling debugging. I do my day to day development in clojurescript (re-frame) so I'm not necessarily up to date but I believe Redux is currently on top for doing this pattern in javascript land.

grayrest··on Steve Yegge Grades His Own Predictions
I interpret it as shared state concurrency. That is, multiple threads sharing the same address space performing reads and writes on shared data: atomics, mutexes, etc. From the update I understand that he's considering things like Actors, Communicating Sequential Processes (goroutines), and data partitioning divide+conquer (MapReduce) approaches as different even if they happen to be implemented on different threads sharing the memory space.

I'm not sure on the relative prevalence but I can say that I've read relatively little about what he's calling multi-threaded programming. Mostly just a handful of lock-free data structures from the C++ guys and Rust's take on how they can do it while avoiding data races due to the type system. The alternatives, on the other hand, have been on HN pretty much continuously since HN started up.

grayrest··on New React Developer Tools
The basic idea is to have your components take optional params that are themselves components. ESPseudoish code:

    // In your components...
    let DefaultListItem = (content) => <li className="foo">{content}</li>

    let DefaultList = (items, Li=DefaultListItem) => <ul>{items.map(Li)}</ul>

    let SortableItem = (content) => <li className="handle" on-drag={(e) => dispatch('dragStart', hash(content))>{content}</li>

    let SortableList = (items, Li=SortableItem) => <DefaultList {...this.props} />

    let EditableList = (items, List=DefaultList, Li=SortableItem) => {
      <div><List {...this.props} /><button>Edit</button></div>
    }

    let SearchResultHighlighter = (text) => <span className="imagine-this-highlighted">{text}</span>

    // -- In use...
    let source = ['foo', 'bar', 'baz']
    render(<SortableList items={ source.map(SearchResultHighlighter) } />)

    let ImageItem = (url) => <li><img src={url} /></li>
    render(<EditableList items={ source.map(x => x + '.jpg') } Li={ImageItem} />)

There's a lot of design space to play around with. For a widely reusable library, I want something like Clojure's protocols or Rust's traits so I can indicate to people what the component needs/provides without them looking at the source.
grayrest··on New React Developer Tools
I've thought about why widget libraries don't work on the web since 2008. In 2007 I was making iOS webapps, in 2008 Apple put out the SDK and the native apps were better. I decided that the native apps were better because the devs didn't blow 60% of their time budget building a poor, custom widget library. The problems I've encountered:

The first and most basic is that the expectation on the web is that every project will have a unique look and feel. This greatly limits the adoption of frameworks based on desktop widget library concepts (dojo, ext, sencha, cappuccino, sproutcore). The times I've used these frameworks, I spend as much time fighting the look and feel as I would building an interface from scratch. This isn't a problem if you're look and feel insensitive and desktop style widget libraries do get picked up for internal corporate apps.

The second problem is size. The need to download everything, desire for reduced page load times, and lack of dead code elimination has historically made web devs more sensitive to the size of their libraries. This was a problem for libraries like YUI2, which had excellent components that simply had an option for anything somebody at yahoo wanted but adding a new widget would frequently add hundreds of K to the download. This is a reduced concern with the increased capabilities of mobile and I believe that the combination of HTTP2, having a standard module system, increased tooling (e.g. webpack), universal/isomorphic JS, and ServiceWorker provide the means to more or less eliminate this as a core problem.

The third problem is CSS. The language provides no tools for abstraction when the target markup (your widget) is fixed. Happily, this problem is solved via sass. You can separate style concerns into mixins (or placeholders) and compose them into either widget or instance specific rules and avoid the cascade.

The fourth problem is component composition. In order to get more code reuse, you need to be able to build up bigger widgets from small pieces and then make a lot of useful small pieces. Stateful components don't compose particularly well and I've spent a lot of time on this (in yui3, knockout, and angular) before I found React's virtual dom approach two years ago. With the vdom, it's possible to view components as functions projecting state onto a virutal DOM. Composition can then be solved by creating higher order components and using normal functional programming composition and code reuse. With care put in to how larger components are designed, it's possible (I've done it) to swap out sub components to customize behavior on a per-instance basis. I consider the core problem solved but I haven't seen the equivalent of an underscore for react components yet.

The fifth problem is widget interaction. I define widgets as components that are an isolated concern (and generally maintain internal state): Autocomplete instead of FooList. Since the components are generally stateful and produce events, you have to have a protocol for having them interact with each other and the rest of the app. As an example, a FOO widget is a React component has PropTypes that get compiled into a Falcor query and all its event handlers call a function `dispatch` with an object shaped like X. Everybody comes up with this in their app but without a consensus on what the approach is, everybody's widget libraries are parochial. This is an active area of development and Web Components is Google's take on the problem. Facebook is also very interested in this with Flux/GraphQL.

Once all the problems are solved (I believe we're relatively close) then we should see widget libraries come into their own. I'm estimating about 3 years before someone starts really winning the widget library battle and we get a "standard" set of widgets you're looking for. I believe that something from the React or Ember communities are the likely source and Polymer has an outside chance (I don't see how component composition works in Polymer).

grayrest··on Forging an Alliance for Royalty-Free Video
Daala came up in the HN thread when Cisco announced Thor:

https://news.ycombinator.com/item?id=10042849

grayrest··on The Beauty of Clojure
> You've written a ClojureScript webapp using the Angular framework

I know this is an example but Angular is terrible with Clojurescript. Clojure has an opinionated idea of how state should change over time and that opinion does not include two-way bound attributes. The reason the cljs community is virtually all React is because dom diffing makes the UI effectively a projection from state and that is epochal-time compatible.

> How do You make sure that after changing it everything works - even the most obscure option that only one user uses?

Depends how your app is designed. In the general case where, say, you're doing the equivalent replacing Angular with Ember you just have to do it and lean on tests/QA. I have just recently finished such a refactor and it's about as fun as you're implying.

With the refactor, I have a better plan going forward! We're now on the re-frame model. All state is now in the global atom (instead of mostly being in the atom but some being component-local), dataflow is unidirectional, and we're capturing all non-determinant actions as event params. Together, it means serializing the state atom and a sequence of events allows playback on the changed code. At least in theory. I wound up having to ship rewrite delayed features and haven't taken the time to build recording/playback support.

grayrest··on The Beauty of Clojure
If it's particularly confusing you can always use swiss arrows[0] instead:

   (-<> (range 10)
        (map #(+ % 2) <>)
        (reduce + <>))

[0] https://github.com/rplevy/swiss-arrows

It's more common in functional languages and called a thrush or pipe operator.

F#:

    [|0..9|] |> Seq.map ((+) 2) |> Seq.sum
Javascript (Ramda):

    R.pipe(R.range(0,10), R.map(R.add(2)), R.sum)();

    //With slightly more magic
    let {pipe, range, map, add, sum} = R;
    pipe(range(0), map(add(2)), sum)(10);
grayrest··on Planck is a ClojureScript REPL and script execution environment
This is an extension of Ambly [0], which is basically the same thing but for iOS. I believe Ambly was developed because Clojurescript's startup time makes it more practical than clojure on a mobile device. David Nolen has posted benchmarks showing jsc runs clojurescript faster than v8 but I don't believe that was the primary motivation here.

[0] https://github.com/omcljs/ambly

grayrest··on Mozilla's Servo Engine Now Capable of Rendering GitHub
Processor power use scales with frequency as well. See [0], specifically the 'Low Memory and Power Devices' section, which shows power savings running 4 cores at lower frequency versus 1 core at max frequency. I think they eventually decided that running at max frequency on all processors and sleeping wound up being most efficient but that's my memory and could be completely incorrect.

[0] http://blogs.s-osg.org/servo-adapting-c-to-work-on-the-web/

grayrest··on Mozilla's Servo Engine Now Capable of Rendering GitHub
If you're interested in checking out the progress, the build process[0] is really easy.

Here's the current page: http://i.imgur.com/NmRNaRz.png

If you want to poke around more, servo shell[1] lets you switch starting pages without having to re-run from the command line.

[0] https://github.com/servo/servo [1] https://github.com/glennw/servo-shell

grayrest··on Is Angular 2.0 ready?
I doubt he's specifically looking for Angular jobs or likely any job at all. It's likely he's getting contacted by recruiters or just seeing job ads. The current trend is react but I run across node+angular postings regularly.
grayrest··on Redux 1.0
You're more or less correct.

One of the not-immediately-obvious problems with the React pattern of passing data in via attrs and actions via callbacks is that the parent component needs to accept all the data/callbacks that all its child components require and its parent in turn needs to do the same. In many projects you wind up needing an additional chunk of data on a child component and that change requiring edits in 8 additional components to pipe around the data.

The Realy/GraphQL (also Falcor from Netflix) idea is that an individual component knows what data it needs and having it describe the data it needs and those requirements being aggregated into a hiearchical query over the graph of data present on the server. Structuring your data requirements this way solves both client side (the problem I mention above) and server side problems (supporting multiple client apps with similar but not the same data requirements, only having to write the code to expose a table as part of a query instead of having to shape it to various endpoints).

At least that's the idea. I find Relay as released to be unpleasant just like I found Flux as originally released to be unpleasant. Now that the code is out there expect a million Relay re-implementations before a rough consensus winner emerges. I expect the winner to look something like a combination of react-resolver with some redux middleware.

grayrest··on Rust in 2016
Is there an RFC or thread covering the IDE integration plans?
grayrest··on Announcing Rust 1.2
Does it open the door to being able to incrementally update the representation and have the compiler used as a library for IDE support?
grayrest··on Pure UI
> How did you capture and render text input, and how did you handle new lines when the text wrapped? How do you handle paragraphs, especially when a user would delete text?

For rendering, I had a component that rendered the block element by splitting the text string at the indicies specified by the text ranges, inserting the appropriate tags, and dangerouslySetInnerHTMLing the text. I'd probably just manually generate vDOM nodes if I were to revisit it.

I didn't do line breaking, moving up/down was done using the caretPositionFromPoint code: create range, get it's bounding box to get initial x/y, getClientRects to get the position for the next line, caretPositionFromPoint, get block text index.

In this case (I did mention it was basic) I wound up not having to do cross-block operations because the UI never had more than one. I had a plan but not having to do it makes me happy.

In conclusion, you're probably better off just using an existing RTE.

grayrest··on Pure UI
> Have you done large apps ?

At work we're at 10k loc which isn't huge but it's fairly large for a clojurescript app. Middleware on event handlers is a great abstraction. It's only been a few weeks since the refactor and there are only three of us on the team but I'm not foreseeing any scaling problems. The only changes we made are about 20 middlewares and namespacing our event keywords. We experimented with a forked version of the framework and running multiple re-frame apps nested inside each other but it wound up not being worth the effort.

The only scaling hazard I know of is that re-frame has an internal global atom so that might cause a problem if you're mixing multiple re-frame apps on a single page but it doesn't affect us and reworking the framework to not use a global isn't too difficult.

grayrest··on Pure UI
I've done a basic RTE in React for a client. I've done three now and RTEs are always annoying but the difficulty in this case is largely in how you model it. I chose to create a JS object per block element (usually a paragraph) consisting of the text as a string and a set of text ranges (start/end/type). Input was via hidden text field that's updated as you change blocks and the mapping from x+y screen coordinates (click, arrow up/down across block boundaries) to text field offset is doable by writing a shim for caretPositionFromPoint.

I started with just using contentEditable but you have even more exciting cross browser issues, the output is both inconsistent between browsers and terrible, and you can't do controlled input because updating the editable content DOM at all breaks undo.

With the virtual DOM model, updates are roughly O(n) where n is the size of the virtual DOM. The way to handle very large amounts of input is to window the input data and only vdom render/diff the subset of the data that's currently visible.

grayrest··on Pure UI
Not at all. I've written/cleaned-up a few dozen Backbone apps. They work great when they're small and are generally a mess once they scale. An example: how do you use a datepicker component in your pure state->DOM system and guarantee setup/cleanup of DOM event listeners?

As for when you'd want to read from the DOM in a well architected app, the easy example is drag and drop. Unless your drop targets have fixed sizes or your needs are simple enough to purely get away with mouseenter/mouseleave events then you need to query the DOM for node sizes. Other situations I've run into are text breaking and rich text editing.

grayrest··on Pure UI
It's Backbone. A pure state -> DOM function is also called a template. It works when the app is simple. The problem is that you do NOT want a pure state -> DOM function. It blows away state of things like mounted subcomponents and input fields. Look forward to lots of ad-hoc DOM coordination as your app grows.

Giving up efficiency in the slow part (DOM updates) in exchange for efficiency in the fast part (determining what changed) is backwards.

grayrest··on React.js Introduction for People Who Know Just Enough JQuery
Have you done Backbone? The idea is that you define everything in terms of models and that when one of those models change you call render() to run it through your templates and you're done. This is a simple conceptual model, the framework needed to execute it is simple (and well written in the case of Backbone), and it works really well for simple applications. The problem arises when you can't just call render: when you have input fields, when your rendered DOM has event listeners, when you're using a component with it's own internal state (e.g. a jQuery datepicker), or when you're doing something like a grid and generating too many DOM nodes. Unless you know this is coming and have a plan for dealing with it (e.g. the many Backbone addons), this is a complexity land mine since it does not show up in the small apps you build while testing out the framework.

You can (and I do) view the React render as an idempotent projection from state to DOM, otherwise known as a template. React is a very fancy template system. You build your fragments (components) up into views, pass in your data, and render the entire page as if you're rendering it from scratch. It handles or provides hooks for all the situations I mentioned in the previous paragraph and React's internals ensure that it's reasonably performant by default. Having everything conceptually fully render from scratch every change means there's no separate handling for the initial render versus updates to the initial render (e.g. you have an accordion, render it with an ejs template but toggle it open/close by toggling classes). It makes the Backbone model work in a way that's easy to reason about.

A real world example: I've implemented (B2B, not something I can link) a drag and drop layout builder as a contract. The workalike they wanted, which I had also worked on but didn't design, was ~6k lines of node/class manipulation and mousenter/leave hit testing while my React version worked out to be around 600 lines, most of which were generating virtual screen position hitboxes for the various drop zones. Hovering/dropping in a zone changes attributes in a list of JS objects and the visual feedback is handled by the rendering code you'd need to draw the layout anyway plus another 20% for the drop previewing/hovering.

Most savings aren't as dramatic but in general you wind up spending less effort getting your views right. The LoC isn't always that much lower but it's template code instead of manipulation code. There are other benefits like component composition just working, server side rendering, putting all your app state in one place lets you do session recording and time travelling debugging but this post is long enough as is.

grayrest··on Why ClojureScript Matters
> I've been thinking a lot about how to bring this back into the JS world. I have yet to find any good literature on it, but I will be exploring this area more.

The JS equivalent of figwheel is React Hot Loader[1]. There's a port of core.async[2] but I've also seen people using Babelized ES7 async/await for avoiding callbacks. The reloaded workflow is just a pattern around building objects with a topological sort for order initialization. I expect you could build a JS version in ~200 lines of code.

[1] https://github.com/gaearon/react-hot-loader [2] https://github.com/ubolonton/js-csp

I'm unaware of editor integration between an editor and browser runtime a la slime/nrepl. I think LightTable had a basic implementation but it's been a while and I could be remembering it incorrectly.

grayrest··on Running Lisp in Production
You need leiningen (it's in most package managers):

https://github.com/technomancy/leiningen

Clone the repo, `lein figwheel`, http://localhost:3449/index.html

grayrest··on Atom 1.0
Background processes don't block the main thread, the extension points are better thought out and the development experience in working on extensions is a LOT better, js/coffee are better languages than vimL, and display is not limited to a fixed grid of text cells.

The downsides are that it's comparatively slow. The vim keybinding emulation isn't great but I can now use it without getting frustrated using ^[ to get back to normal mode.

I still use Vim for most things but I do Clojure/Clojurescript in Emacs evil-mode, and Typescript in Atom.

grayrest··on Atom 1.0
If you have a setup that works for you, probably not. Atom's main advantage is that it's in a DOM environment and people could do neat things with it but at the moment the efforts have gone into putting it roughly at feature parity with ST3.
grayrest··on Rust for Clojurists
It's not something I've explored or really care to pursue, but I've sat though at least a half dozen talks on audio synthesis in Clojure including one by Rich himself. They do signal generation in Clojure that feeds data into another system that does the real-time portion.

I agree that Clojure isn't suited to hard real time systems and it's not hard to come up with drawbacks to the above approach but you just happened to pick an example that a lot of people in the Clojure community seem to care about.

grayrest··on Rust for Clojurists
There aren't that many things you can't do in Clojure, the main place Rust has an edge is in efficiency. I plan on doing an Avro implementation but other projects (mostly work-related) have a higher priority.

In terms of larger projects, the Servo guys always seem to encourage people learning Rust to get involved. One of the projects I'm most interested in is Frank McSherry's timely/differental dataflow repos. I wanted a Rust implementation of Naiad when I first read the paper so I was quite pleased to see one of the authors do an implementation, even if it doesn't seem to be a full time pursuit.

[1] https://github.com/frankmcsherry/timely-dataflow/

Most first-rust-projects that are announced on reddit/discourse seem to be games (Piston), simple web apps, raytracers, or datastructures.

← PreviousPage 9 of 23Next →