Coder Social home page Coder Social logo

Todo sample, keeping count about s HOT 3 OPEN

adamhaile avatar adamhaile commented on June 13, 2024
Todo sample, keeping count

from s.

Comments (3)

adamhaile avatar adamhaile commented on June 13, 2024

So just flip the signs of 1 and -1 and it's all good, right? 😆

The data() mixin attaches to the change event too, so in your code above, it comes down to which gets fired first.

The view layer isn't really where you'd want to do such a calculation anyway. For instance, if a completed todo is removed, you'll want to decrement the count. And if we load todos from localStorage, we need to redo the whole count, etc. I think I'd rather do it in the model layer.

Incidentally, I played around with schemes to make the SArray() methods have more optimal change behavior. In the end, I just paralleled the standard array methods for two reasons:

  1. simplicity of use. If you know how to use the standard Array methods, you pretty much know how to use the SArray ones.

  2. applicability. The function doesn't just have to be reversible, it also has to be commutative and expensive enough to matter. In this case, I'm guessing SArray.reduce() would take you well beyond 10k todos before taking longer than a 60hz frame refresh, maybe even 100k.

... but it's still an interesting problem.

Off the top of my head:

  1. I'd make the completed signal a sum signal, which is a variant of a data signal which, instead of a new value, takes a function to transform the old value to the new. So completed(x => x + 1) instead of completed(S.sample(completed) + 1). This isn't part of core S, but can be implemented in a few lines of code. Let me know if you're curious how to do so.

  2. I'd use mapS() to create a computation for each todo which incremented completed() when appropriate and used S.cleanup() to schedule the corresponding decrement. Essentially, the computation creates a side-effect by incrementing completed, which it needs to clean up when it re-runs.

So something like (untested):

const count = S.sum(0),
    inc = () => count(c => c + 1),
    dec = () => count(c => c - 1);
...
todos.mapS(todo => todo.done() && (inc(), S.cleanup(dec)));

from s.

naasking avatar naasking commented on June 13, 2024

I'm absolutely interested in exploring various options. I'm still learning about this whole field of client-side reactivity, vdom, JSX, etc., so please bear with me!

An explicitly commutative variant of reduce which accepts a TAcc merge(TAcc acc, TItem original, TItem current) might solve this problem. So a completed count could be defined as:

todos.creduce(
  (acc, x) => acc + (x.done() ? 1 : 0),
  0,
  (acc, o, x) => acc - (o.done() ? 1 : 0) + (x.done() ? 1 : 0))`.

Or you could overload the regular reduce based on the extra argument for merge. I got this idea from the Concurrent Revisions work at Microsoft which uses similar merge functions to ensure incremental and deterministic concurrent execution.

The only problem is that you'd need to store the original value of any changed signal while a reaction/recomputation is underway, just in case they're needed for a creduce merge. Upside being, you can now support commutative and incremental reduction on an opt-in basis.

I had also considered special sum() and count() methods, but I think creduce() is a more general solution, ie. sum(f) = creduce((acc,x) => acc+f(x), 0, (acc,o,x) => acc-f(o)+f(x)), count(f) = creduce((acc,x) => acc+(f(x) ? 1 : 0), 0, (acc,o,x) => acc - f(o) + f(x)).

I started exploring this question based on a thread where I was discussing various options like MobX and such, and the incremental reduce/completed count issue with S.js came up. So I'm not sure I'd do it this way either, but it ought to be possible and simple to do so.

P.S. Your link to index.d.ts on the S-Array repository should be a link to index.ts.
P.P.S. Alternately, you could define a global map that maps typeof x to merge functions for that type, but I'm not sure this would work given JS's dynamic types and heterogeneous collections.
P.P.P.S. As another possibility, you can define creduce to always return some known commutative type, creduce(f : TItem->Number, seed, merge:Number->Number->Number). So all reduction happens via merge after mapping to a known commutative type, like Number. So counting completed tasks would then simply be todos.creduce(x => x.done() ? 1 : 0, 0, (acc, o, x) => acc - o + x).

from s.

adamhaile avatar adamhaile commented on June 13, 2024

Yeah, I was puzzling over how a more general utility could be constructed. My thought was a little like your last form but with three functions: one to extract a value from the item, one to add it to the accumulator, one to subtract.

creduce<T, I, A>(f : T => I, add : (A, I) => A, sub: (A, I) => A, seed : A)

todos.creduce(x => x.done() ? 1 : 0, (acc, x) => acc + x, (acc, x) => acc - x, 0)

I think it'd need three functions, not just two, because it'd have to deal with the case where a value left the collection, not just updated.

from s.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.