A question about insertValueB/insertValueE type signature

8 views
Skip to first unread message

artyom.shalkhakov

unread,
Apr 10, 2009, 12:25:04 AM4/10/09
to Flapjax
Hello,

insertValueB has "type" of Behavior a * (Dom . Array id) -> void

Is it intensional that insertValueB/insertValueE return "void"? In
FRAN, for example, functions are of type

(auxilliary parameters here) * Element -> Element

which allows nesting and is very convenient in my opionion.

So, the question is why not use this style?

Cheers,
Artyom Shalkhakov.

Arjun Guha

unread,
Apr 11, 2009, 8:02:49 AM4/11/09
to fla...@googlegroups.com
I don't think there is any particular reason. You're right that
nesting would be convenient.

Leo, any thoughts on this?

Arjun

Leo Meyerovich

unread,
Apr 11, 2009, 3:07:16 PM4/11/09
to fla...@googlegroups.com
I'd like to see a use case that would be clearer with this.

Inserting values in flapjax is normally very compositional with clear
single assignments. E.g., x = DIV(time).

InsertDomB / insertValueB are the exception. Nesting them within code
returns us to the inverted style we're trying to avoid, so I'm not sure
we should endorse it. Furthermore, mixing together both an assignment
and a composition might be very misleading. Generally, I only expect one
side effect, not multiple as in insertDomB(DIV(insertValueB(time, 'x')).
That was my reasoning originally, and it hasn't changed much since then.

Again, perhaps there is a clear use case?

Artyom Shalkhakov

unread,
Apr 12, 2009, 2:56:18 AM4/12/09
to fla...@googlegroups.com
Hi,

2009/4/12 Leo Meyerovich <lmey...@gmail.com>:


> InsertDomB / insertValueB are the exception. Nesting them within code
> returns us to the inverted style we're trying to avoid, so I'm not sure
> we should endorse it.

Could you give more details on what an "inverted style" is? I don't
quite get it.

> Again, perhaps there is a clear use case?

I was tinkering with Flapjax-based animation library, the goal being animating
elements of existing web-pages. (No supplanting of default browser behavior,
just adding some eye-candy via unobtrusive scripting).

(Basically, all I need is "reactive CSS properties" with proper units and a way
to easily assign them to elements.)

Since I don't know what kind of API to settle on, I have tried to find
prior work
similar to the task at hand. I found "Composing reactive animations" by Conal
Elliott, which describes an interface very much like I posted.

ATM, using the library is tedious:

> var elem = document.getElementById('foo');
> var a = anim(power(3.0))(-30.0, 0.0);
> var posB = liftB(a, moveB(clicksE(elem), 25, 250));
> insertValueB(liftB(function(x) {return x + "em";}, posB), elem, 'style', 'left');
>

Implementation details:

> var anim = function(f) {
> return function(a,b) {
> return function(x) { return a + (b - a) * f(x); }
> }
> }
> // an example easing function
> var power = function(y) { return function(x) { return Math.pow(x,y); } }
>
> // moveB :: EventStream a * [Behavior] Int * [Behavior] Int -> Behavior Float
> // very much like what Arjun showed me months ago
> function moveB(ev,step,duration) {
> var timerB = timerB(step);
> var startB = startsWith(snapshotE(ev,timeB), 0);
> return liftB(function(a,b,d) {return Math.min((b - a)/d, 1.0);},
> startB, timeB, duration);
> }

I tried to abstract some details out, by defining a bunch of functions analogous
to:

> // one function for one animatable css property :)
> var left = function(b, elem) {
> insertValueB(b, elem, 'style', 'left');
> return elem;
> }

(and fiddling with anim function), so they could be composed and abstracted out,
just like in Fran. Then I noticed that insertValueB doesn't return anything, and
an inquiry popped up.

Cheers,
Artyom Shalkhakov.

PS sorry for posting so much code

Leo Meyerovich

unread,
Apr 12, 2009, 4:23:42 AM4/12/09
to fla...@googlegroups.com
Artyom Shalkhakov wrote:
> Hi,
>
> 2009/4/12 Leo Meyerovich <lmey...@gmail.com>:
>
>> InsertDomB / insertValueB are the exception. Nesting them within code
>> returns us to the inverted style we're trying to avoid, so I'm not sure
>> we should endorse it.
>>
>
> Could you give more details on what an "inverted style" is? I don't
> quite get it.
>
>

This is really a pedantic red herring for the original question, but:

Some nestings of insertValueB follow our desired singly-assigned data
flow style, and others don't. The following pseudocode example is in the
spirit of Flapjax:

function makeWidget() {
var widget = DIV();
...
insertValueB(widget, time().apply_b(f, odds, evens));
return widget;
}

However, I can also see somebody also writing it as:

function insertOdds(w) {
insertValueE(w, time_e.filter_e(odds), 'style', 'x');
}
function insertEvens(w) {
insertValueE(w, time_e.filter_e(events), 'style', 'x');
}
insertOdds($('widget'));
insertEvens($('widget'));



The latter gets back to the style of code we're trying to avoid, where
you can't just look at the assignment of some value and be guaranteed
it's not getting reassigned elsewhere. When we say 'inverted', we mean
that the data flow from source (time) to sink (widget.style.x) is
opposite of the control-flow. This happens with callbacks: you need to
check which functions might have called the callback, and which might
have called that one, etc. In the first example, you have the full
definition: f(time(), odds, evens). In the second example, you have to
look around the entire program.


Whether or not insertValue returns the value inserted (or perhaps the
object getting a value inserted), which is your concern, seems somewhat
orthogonal to this issue of nesting calls to insertValue. Getting back
to the email...



>> Again, perhaps there is a clear use case?
>>
>
> I was tinkering with Flapjax-based animation library, the goal being animating
> elements of existing web-pages. (No supplanting of default browser behavior,
> just adding some eye-candy via unobtrusive scripting).
>
> (Basically, all I need is "reactive CSS properties" with proper units and a way
> to easily assign them to elements.)
>
> Since I don't know what kind of API to settle on, I have tried to find
> prior work
> similar to the task at hand. I found "Composing reactive animations" by Conal
> Elliott, which describes an interface very much like I posted.
>
> ATM, using the library is tedious:
>
>

An animation and widget library would make a lot of sense :) We've all
been rolling our own individually so far it seems, and I don't know if
there's enough consensus to make an 'official' one. E.g., how can we
define separate wriggling and stretching animations, and then provide
combinators for sequencing the two or even performing both at the same time?
Code examples are good :)

Hopefully the example at the beginning makes it clear that we want
assignment statements and how they mix with the control flow to be super
obvious. The proposal to mix data flow and assignments seems like a step
backwards (though not a huge one!). E.g., it would suggest the following
is idiomatic Flapjax:

timer_b().times(200).insertValue_b('foo').triple(300).insertValue_b('bar');

Not needing names is often nice... but it can introduce noise when
trying to understand a particular value, as in this example.
Furthermore, rather than seeing assignments on the left, they're nestled
into arbitrary terms! Can you show how you used your function 'left'
that makes code clearer with such a shortform?

I agree that writing multiple 'insertValue' statements isn't ideal.
However, you could use one insertValue statement to bind multiple ones
by passing in an object with fields! E.g., insertValueB({x:timer_b(), y:
timer_b()}, widget, 'style'). Similarly, I think an animation library
can be defined by passing around the property object ( {x:.., y:...}),
where adding an animation creates a new one, with the last composition
being chosen to be inserted. This style might also leave a lot of room
for optimization, just like what happened for inplace DOM updates :)

- Leo


>

> >
>

Artyom Shalkhakov

unread,
Apr 12, 2009, 6:51:54 AM4/12/09
to fla...@googlegroups.com
2009/4/12 Leo Meyerovich <lmey...@gmail.com>:
> This is really a pedantic red herring for the original question ...
> [skipped]

> In the first example, you have the full
> definition: f(time(), odds, evens). In the second example, you have to
> look around the entire program.

Wow. Thanks for clarifiying your terminology.

> An animation and widget library would make a lot of sense :) We've all
> been rolling our own individually so far it seems, and I don't know if
> there's enough consensus to make an 'official' one.

Well, I've looked into CSS3 Transitions and Animation modules, and it
seems to me
that it would be not too hard to implement these proposals using
Flapjax (in fact,
I already wrote a fraction of it). They are very limited in scope, though.

Also, I can volunteer to write an 'official' animation library that
nobody would be
happy with. :)

> E.g., how can we define separate wriggling and stretching animations, and then provide
> combinators for sequencing the two or even performing both at the same time?

Good question. Is anybody willing to answer?

> The proposal to mix data flow and assignments seems like a step
> backwards (though not a huge one!). E.g., it would suggest the following
> is idiomatic Flapjax:
>
> timer_b().times(200).insertValue_b('foo').triple(300).insertValue_b('bar');
>
> Not needing names is often nice... but it can introduce noise when
> trying to understand a particular value, as in this example.

Right. I don't understand what this code means.

> Furthermore, rather than seeing assignments on the left, they're nestled
> into arbitrary terms! Can you show how you used your function 'left'
> that makes code clearer with such a shortform?

Unfortunately, no, because I haven't actually used it yet. I wanted answers
to my questions first.

> I agree that writing multiple 'insertValue' statements isn't ideal.
> However, you could use one insertValue statement to bind multiple ones
> by passing in an object with fields! E.g., insertValueB({x:timer_b(), y:
> timer_b()}, widget, 'style'). Similarly, I think an animation library
> can be defined by passing around the property object ( {x:.., y:...}),
> where adding an animation creates a new one, with the last composition
> being chosen to be inserted. This style might also leave a lot of room
> for optimization, just like what happened for inplace DOM updates :)

This answers my question and yet leaves animation code pure, great!

Thanks a lot.

Cheers,
Artyom Shalkhakov.

Shriram Krishnamurthi

unread,
Apr 14, 2009, 2:27:51 AM4/14/09
to fla...@googlegroups.com
Hi Artyom,

Thanks for posting the code. Leo explained the issue very nicely.

In terms of the inversion issue, you can also read about it in the
tech report that I just mentioned:

http://www.cs.brown.edu/research/pubs/techreports/reports/CS-09-04.html

The description early in section 2 should make Leo's point through a
different example.

-----

We'd love to see your animation library. What to do about wriggling
and stretching? I'd say let's not think about it too much; give it a
try and toss out code; we'd all be happy to try it out and comment!

-----

[Along these lines, there's an nice "reactive widget library" embedded
in one of our applications. We should extract and document that, too.]

Shriram

Artyom Shalkhakov

unread,
Apr 14, 2009, 5:07:06 AM4/14/09
to fla...@googlegroups.com
Hello,

2009/4/14 Shriram Krishnamurthi <s...@cs.brown.edu>:


> Thanks for posting the code.  Leo explained the issue very nicely.
>
> In terms of the inversion issue, you can also read about it in the
> tech report that I just mentioned:
>
> http://www.cs.brown.edu/research/pubs/techreports/reports/CS-09-04.html

A good read, thanks!

> The description early in section 2 should make Leo's point through a
> different example.

I guess you're talking about subsection 2.1, which is shows the structure
of a typical JavaScript program. (Oops, I've missed the bug.)

> We'd love to see your animation library.  What to do about wriggling
> and stretching?  I'd say let's not think about it too much; give it a
> try and toss out code; we'd all be happy to try it out and comment!

Okay, will do, but most of it is contained within the code snippet that I
posted, anyway. I need to ship my work first, so expect a delay.

> [Along these lines, there's an nice "reactive widget library" embedded
> in one of our applications.  We should extract and document that, too.]

I'm looking forward to this.

Cheers,
Artyom Shalkhakov.

Noel Welsh

unread,
Apr 14, 2009, 10:28:58 AM4/14/09
to Flapjax
On Apr 12, 9:23 am, Leo Meyerovich <lmeye...@gmail.com> wrote:

> I agree that writing multiple 'insertValue' statements isn't ideal.
> However, you could use one insertValue statement to bind multiple ones
> by passing in an object with fields! E.g., insertValueB({x:timer_b(), y:
> timer_b()}, widget, 'style').

This is not valid Flapjax, at least in 2.0. In particular you can't
pass an object with fields as the first argument to insertValue(E|B).
Can anyone comment on the idiomatic way to achieve the same effect?
I've been writing lots of curried setter functions to achieve the same
effect. Note that in the new Flapjax you can't see style properties
with insertValue, as you need to dereference two arrays (style, and
the particular property within that style.)

(Yeah, I'm also working on an animation library.)

N.

Shriram Krishnamurthi

unread,
Apr 14, 2009, 12:51:04 PM4/14/09
to fla...@googlegroups.com
Some internal email going on about this. We'll respond soon.

Shriram

Leo Meyerovich

unread,
Apr 14, 2009, 2:59:27 PM4/14/09
to fla...@googlegroups.com
Mornings start later over here :) I just gave it a whirl and modified
the 'where is the mouse' demo:

<html>
<head>
<title>Flapjax Demo: Where is the Mouse?</title>
<link rel="stylesheet" href="/demo.css"/>
</head>
<script type="text/flapjax">
insertValueB({style: {position: 'absolute', left:
mouseLeftB(document), top: mouseTopB(document)}}, 'blah');
</script>
<body>
<p id=blah>The mouse coordinates are
&lt; {! mouseLeftB(document) !}, {! mouseTopB(document) !} &gt;
</p>
</body>
</html>

or

<html>
<head>
<title>Flapjax Demo: Where is the Mouse?</title>
<link rel="stylesheet" href="/demo.css"/>
</head>
<script type="text/javascript">
function go () {
insertValueB({style: {position: 'absolute', left:
mouseLeftB(document), top: mouseTopB(document)}}, 'blah');
}
</script>
<body onload="go()">
<p id=blah>The mouse coordinates are
&lt; {! mouseLeftB(document) !}, {! mouseTopB(document) !} &gt;
</p>
</body>
</html>


Hope that saves some heartache!

- Leo

Leo Meyerovich

unread,
Apr 14, 2009, 8:47:57 PM4/14/09
to fla...@googlegroups.com
Someone noted my email might not have been clear. It was supposed to
demonstrate a couple of things:

1. How to insert multiple properties at the same time. Instead of writing

insertValueB('absolute', 'blah', 'style', 'position')
insertValueB(mouseLeftB(document), 'blah', 'style', 'left')
insertValueB(mouseTopB(document), 'blah', 'style', 'top')

I could specify an object to get merged in:

insertValueB({style: {position: 'absolute', left: mouseLeftB(document),
top: mouseTopB(document)}}, 'blah');

You can actually mix both styles:

insertValueB({position: 'absolute', left: mouseLeftB(document), top:
mouseTopB(document)}, 'blah', 'style');


2. Compiler mode (first example) vs. library mode (second example). In
the library mode, I had to explicitly wait until the document finished
loading before modifying the 'blah' element.

--

It's unclear what should happen if two insertValueB calls conflict.
Always using the first style decreases the chance of this occurring,
though I find using property objects to be clearer. One last bit of
caution relating to the property object form is for deleting properties,
which isn't handled cleanly. Overall, for 'normal' code, the object form
is cleaner, but you should be cognizant of the semantic ambiguities.

- Leo

Artyom Shalkhakov

unread,
Apr 15, 2009, 12:08:57 AM4/15/09
to fla...@googlegroups.com
2009/4/15 Leo Meyerovich <lmey...@gmail.com>:

> It's unclear what should happen if two insertValueB calls conflict.

An exception should be raised, perhaps?

Cheers,
Artyom Shalkhakov.

Noel Welsh

unread,
Apr 16, 2009, 6:38:39 AM4/16/09
to Flapjax
For those following along at home...

On Apr 14, 7:59 pm, Leo Meyerovich <lmeye...@gmail.com> wrote:
> <html>
> <head>
> <title>Flapjax Demo: Where is the Mouse?</title>
> <link rel="stylesheet" href="/demo.css"/>
> </head>
> <script type="text/javascript">
> function go () {
>   insertValueB({style: {position: 'absolute', left:
> mouseLeftB(document), top: mouseTopB(document)}}, 'blah');}
>
> </script>
> <body onload="go()">
> <p id=blah>The mouse coordinates are
> &lt; {! mouseLeftB(document) !}, {! mouseTopB(document) !} &gt;
> </p>
> </body>
> </html>

A valid version is thus:

<html>
<head>
<script type="text/javascript" src="flapjax.js"></script>
<title>Flapjax Demo: Where is the Mouse?</title>
<link rel="stylesheet" href="/demo.css"/>
<script type="text/javascript">
function go () {
insertValueB({style: {position: 'absolute', left:
mouseLeftB(document), top: mouseTopB(document)}}, 'blah');
}
</script>
</head>
<body onload="go()">
<p id="blah">The mouse is here</p>
</body>
</html>

There is some oddness here.

insertValueB works with a hash table as its first argument. The
following example code works:

clicks.mapE( function(){ insertValueB({style: {height: twentyRamp
().startsWith(0)}}, elt)} );

[Don't worry about twentyRamp etc.]

insertValueE does not. This does not work:

clicks.mapE( function(){ insertValueE({style: {height: twentyRamp
()}}, elt) } );

But this does:

clicks.mapE( function(){ insertValueE(twentyRamp(), elt, 'style',
'height') });

So something needs to change, for the sake of consistency.

N.

Arjun Guha

unread,
Apr 16, 2009, 8:33:07 AM4/16/09
to fla...@googlegroups.com
Suppose we were setting two fields in insertValueB, as in Leo's example:

insertValueB({style: {left: mouseLeftB(document), top:
mouseTopB(document)}}, 'blah');

Since behaviors always have values, when either mouseLeftB or
mouseTopB changes, we can recompute the entire style object and insert
it into the DOM.

However, with event streams:

insertValueE({style: {left: mouseLeftE(document), top:
mouseTopE(document)}}, 'blah');

when a mouseLeft event fires, there may not be a corresponding
mouseTop event. So, we can't compute a new value for style. (We'd
have to do some exceedingly clever partial update to just set
style.left but not style.right. We're not that clever and that is not
consistent in general.)

In the examples you gave:

> insertValueB works with a hash table as its first argument. The
> following example code works:

>
>  clicks.mapE( function(){ insertValueB({style: {height: twentyRamp
> ().startsWith(0)}}, elt)} );

Flapjax treats hash tables of constants as constant behaviors and
hashtables with behaviors as reactive objects. The alternative would
involve writing constantB(10), constantB("hello"), etc. That's why
this example works.

However, Flapjax does not implicitly convert objects and constant
values to event streams. So, in this function:

>  clicks.mapE( function(){ insertValueE({style: {height: twentyRamp
> ()}}, elt) } );

the argument is an object, not an event streams. However, here:

>  clicks.mapE( function(){ insertValueE(twentyRamp(), elt, 'style',
> 'height') });

twentyRamp() is an event stream so it works.


Arjun

Reply all
Reply to author
Forward
0 new messages