Make animation subscriptions safer?

When reading through the topics in this discourse I came across an issue and had an idea.
The post in question was this:

Not using a subscription defined in a module is an easy mistake to make as a consumer. And apart from animations not working then, this can often cause issues with the base functionality of a “component” (for example a drop down not expanding because it is waiting for animation events).

Now, since I like functional languages for the guarantees they provide, and since I recently started learning Idris I thought; can’t we make this safer somehow?

Two ideas I came up with on the spot:

  • Change TEA so that view functions can guarantee subscriptions. This… is probably not the best idea and not going to happen, but I am still mentioning it as a possibility.

  • Have an Animation subscription fire a subscribed event immediately which sets some state in the Animation describing it as successfully subscribed to. This would then allow module authors to check wether animations for their element were correctly enabled, and fall back to animationless behaviour otherwise. I don’t know how this would work for checking wether the subscription was accidentally removed though.

These are just ideas that I am curious to get feedback on. I would like for Elm to be as safe and convenient as possible, without programmers having to be aware of edge cases and preconditions :slight_smile:

The fundamental problem here is how do you handle updating the current time.

It’s not entirely clear in the post, but it sounds like you are looking at mdgriffith/elm-style-animation. I will also consider my own library, mgold/elm-animation. I actually recommend mdgriffith’s library for most cases since it handles animating styles rather than Float values, but let’s get back to updating the current time.

In elm-style-animation, you

  • Subscribe to an opaque animation message (but it’s just the current time) by passing a library function a list of all your animations,
  • Update every animation on every frame to contain the current time, and
  • Render and interrupt without passing the current time.

You shouldn’t be dynamically (i.e. at runtime) adding or removing the animation subscription, or animations passed to generate it, because it will automatically stop sending events if no animations are running. The brittleness of this model instead comes from adding a new animation to the model, since you also have to add it to the update and subscription functions for it to work.

The other issue with this approach is that you compute and allocate new animation records on every frame. I would imagine that this has performance implications, but apparently it hasn’t been a problem. The APIs for render and interrupt are simplified.

In elm-animation, you

  • Subscribe constantly to the time delta provided by AnimationFrame,
  • Update the current time in the model by adding the delta, and
  • Render and interrupt by passing the current time.

This setup eliminates the brittle subscribe and update functions, and requires only a constant change (vs. the number of animations) to the model each frame. The APIs for render and interrupt require an extra parameter, the current time.

In elm-animation, you can query for the value of an animation at any time because it’s computed as a mathematical easing function. In elm-style-animation, as I understand it, there are simulations involving springs that require updates each frame. The physics simulation requires the “new frame, new animation” approach to work well. So I take it that’s why it’s done that way.

I think the problem being discussed/addressed has more to do with the issue that if you add animation support via something like elm-style-animation but fail to include the necessary subscription, the code will all compile but the animations won’t work and it might not be obvious why they don’t work. Elm’s type system will catch lots of things and you have to explicitly drop most connection points on the floor to break them, but it won’t detect an omitted subscription.


1 Like

Why is that subscription necessary? Because animations need to have the current time. So studying two approaches for subscribing to and updating based on the current time really is the issue at hand. I offered an alternative approach, already implemented, that eliminates the need to hook up each animation in both subscriptions and update, and then explained why it’s not suitable for elm-style-animation. I think it’s much more fruitful to look at choices in library design than it is to speculate on language features.