hoplon / javelin

Spreadsheet-like dataflow programming in ClojureScript.
803 stars 44 forks source link

Breaking change proposal #7

Closed micha closed 10 years ago

micha commented 10 years ago

See CHANGES.md in the optimo branch and the updated README.md

Please let me know what you guys think before this is merged...

cemerick commented 10 years ago

Will look at the impl in detail later, but two questions:

  1. +1 to the strict enforcement of input vs. formula cells, but why noise things up with = (…) args, rather than advertising input and restricting cell to formulas? I actually misread the formula cell examples as providing some kind of sugared, single-argument =(…) syntax, before snapping to and realizing that that's not possible. The "formula cells take two arguments" doc confuses even further, as long as the examples (and typical usage) presents the = and following list as (visually) a single token.
  2. I'd be bummed if I couldn't use cells directly as IWatchables. I do this now in a couple of circumstances to add purely side-effecty stuff that I don't want to risk exposing to the macro magic, and I suspect I'll need it at some point to be able to detach dynamically-created cells for GC purposes (at the moment, I'm successfully not caring, but that could change).

Thanks for continuing to develop the lib! :-)

micha commented 10 years ago

OK, so:

;; the IWatchable way
(add-watch my-cell ::key (fn [_ _ _ _] (perform-side-effect)))
;; the Cell way
(cell =((fn [_] (perform-side-effect)) my-cell))
;; note that the cell macro doesn't walk anonymous fns
;; you can get a cell's previous value by (.-prev my-cell)
cemerick commented 10 years ago

No, I think the connection with = is good, I'm just chafing at the overloading of cell, since inputs and formulas here have completely disjoint functionality / semantics (unless you're contemplating tackling possibly-recurrent, propagator-style networks, but I assume not?), and reusing it for inputs and formulas forces the dummy = symbol notation. Maybe cell and cell= would be simpler all around? Hopefully I'm doing more than bikeshedding here.

The majority of my usage is necessarily dynamic (we can skype sometime if you want details, or maybe @alandipert can fill you in if he remembers what I blathered about in STL), and what feels like a large amount of it to boot. (Up to ~3000 cells allocated over and over based on user interaction, each set hooked up to the [relatively very small] UI that is statically allocated.) Like I said, maybe IANGI, but GC is something lingering in the back of my mind. I can always file an issue / hack around if/when it comes up. :-)

I sometimes avoid putting side-effecty stuff in cells because the code walking doesn't play nicely with some forms; I remember having issues with for, doseq, and try at various times in the past. Maybe whatever was causing that has been fixed since; sorry, I should have created issues with some examples for each.

alandipert commented 10 years ago

I don't care much where the syntax lands, but will admit (cell =(...)) looks cool. I also like the general idea of separating input/formula semantics syntactically, and think the current situation with quote is less than awesome.

All things considered I'm with Chas on cell and cell= being the provided API. IMO (cell =(...)) is too magical in that (cell =x) looks like it might work, but wouldn't - at least not without additional, complicating sorcery.

Re: add-watch vs. 'the cell way' for side-effecting leaves, the one asymmetry I see is the ability to remove-watch on IWatchables vs. the current inability to remove attached cells. As I think usage of both remove-watch and cell detachment are probably bad things to be doing without precise motivating perf/GC reasons, I don't see the need to add either, yet.

micha commented 10 years ago

OK, I like cell=, too. So maybe that part is settled. I will make modifications and we can see how it feels.

micha commented 10 years ago

@cemerick Wrapping your doseq or for expression in an anonymous fn will protect it from the cell= macro. Anonymous functions are opaque to the cell= macro—it doesn't descend into them or code-walk their bodies. So you could do this, for example:

;; macro gets confused with this
(cell= (doseq [x my-cell] (perform-side-effect x)))

;; macro doesn't descend into fn here, so doseq is protected
(cell= (#(doseq [x %] (perform-side-effect x)) my-cell))