Skip to content

Instantly share code, notes, and snippets.

@ileasile
Last active April 19, 2024 09:17
Show Gist options
  • Save ileasile/1016cf09608df8f9b7f4cfe2d64625f6 to your computer and use it in GitHub Desktop.
Save ileasile/1016cf09608df8f9b7f4cfe2d64625f6 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@ileasile
Copy link
Author

The API I currently suggest is

fun animateIterator(delayMs: Long, iterator: Iterator<Any>)
fun animateSequence(delayMs: Long, sequence: Sequence<Any>)
fun animateIterable(delayMs: Long, iterable: Iterable<Any>)
fun animate(framesCount: Int, delayMs: Long, frameFactory: (id: Int) -> Any)

Probably these should be overloads of a same function?

fun animate(delayMs: Long, iterator: Iterator<Any>)
fun animate(delayMs: Long, sequence: Sequence<Any>)
fun animate(delayMs: Long, iterable: Iterable<Any>)
fun animate(framesCount: Int, delayMs: Long, frameFactory: (id: Int) -> Any)

Probably the name itself should be different?

@belovrv
Copy link

belovrv commented Apr 14, 2024

I thought we had a convention to name such kind of functions with CAPITAL letters

@cmelchior
Copy link

cmelchior commented Apr 15, 2024

My comments:

  • I am not a big fan of using animateX. It feels unnecessary when the type is also in the argument.
  • Would it make more sense to use Duration instead of Long for the delay. That way we encode it more directly in the type, plus make it easier to define delays at different granularities like seconds.
  • frameFactory argument naming looks off. Shouldn't id be index or frameIndex?

So something like:

fun animate(delay: Duration, iterator: Iterator<Any>)
fun animate(delay: Duration, sequence: Sequence<Any>)
fun animate(delay: Duration, iterable: Iterable<Any>)
fun animate(framesCount: Int, delay: Duration, frameFactory: (index: Int) -> Any)

// or if these are capitalized pr. Romans comment

fun ANIMATE(delay: Duration, iterator: Iterator<Any>)
fun ANIMATE(delay: Duration, sequence: Sequence<Any>)
fun ANIMATE(delay: Duration, iterable: Iterable<Any>)
fun ANIMATE(framesCount: Int, delay: Duration, frameFactory: (index: Int) -> Any)

@ark-1
Copy link

ark-1 commented Apr 15, 2024

another idea:

fun <T> animate(delayMs: Long, iterable: Iterable<T>, frameFactory: (element: T) -> Any) {
    animateSequence(delayMs, sequence {
        iterable.forEach { element ->
            yield(frameFactory(element))
        }
    })
}

animate(delayMs = 50, 1..50) { it }
animate(delayMs = 50, mySnapshots) { snapshotPlot(it) }

@devcrocod
Copy link

I agree with some points from Christian:

  • add functions with Duration to existing ones
  • the name for the variable frameFactory looks strange for me

Also, we are reserving quite common name animate

@Jolanrensen
Copy link

Probably put the thing you want to animate at the first place. You maybe could even provide a default duration of 1 second or something.
Makes more sense to have ANIMATE(what, how) instead of ANIMATE(how, what). The lambda overload being the notable exception of course. The rest looks good to me!

One thing that comes to mind is making an extension function to animate an iterable... But a part of me doesn't like the idea of having TOP_LEVEL() extension functions, so it's probably fine as it is.

@nikolay-egorov
Copy link

To add more convinience, I'd say we might add some defaults for this parameters framesCount: Int, delayMs: Long

Maybe we could also add a default way of animating things with the help of our libraries / integrations.
Couple of them comes to mind:
fun animate(framesCount: Int, delayMs: Long, frameFactory: Plot.(index: Int) -> {Plot})
fun animate(framesCount: Int, delayMs: Long, frameFactory: (index: Int) -> {BufferedImage})

@ileasile
Copy link
Author

ileasile commented Apr 17, 2024

Second version of the API, more consistent with what we have

import kotlin.time.Duration

class Frame(
    val delayBefore: Duration,
    val content: Any,
)

fun ANIMATE(frames: Iterator<Frame>)
fun ANIMATE(sequence: Sequence<Frame>)
fun ANIMATE(iterable: Iterable<Frame>)
fun ANIMATE(firstFrame: Frame, nextFrame: (Frame) -> Frame?)
fun ANIMATE(nextFrame: () -> Frame?)
fun ANIMATE(delay: Duration, iterator: Iterator<Any>)
fun ANIMATE(delay: Duration, sequence: Sequence<Any>)
fun ANIMATE(delay: Duration, seedValue: Any?, nextValue: (Any) -> Any?)
fun ANIMATE(delay: Duration, nextValue: () -> Any?)
fun ANIMATE(delay: Duration, iterable: Iterable<Any>)
fun ANIMATE(framesCount: Int, delay: Duration, frameByIndex: (index: Int) -> Any)

@ark-1
Copy link

ark-1 commented Apr 17, 2024

fun ANIMATE(delay: Duration, seedValue: Any?, nextValue: (Any) -> Any?)

I suggest to add a type parameter here:

fun <T : Any> ANIMATE(delay: Duration, seedValue: T?, nextValue: (T) -> T?)

This way the user won't need to write it as Long and such.

An extension of that idea would to be to make Frame parameterized:

class Frame<out T : Any>(
    val delayBefore: Duration,
    val content: T,
)

This way me may have this:

fun <T : Any> ANIMATE(firstFrame: Frame<T>, nextFrame: (Frame<T>) -> Frame<T>?)

And Frame<*> in all other overloads. But this may be a bit over-engineered.

@ileasile
Copy link
Author

Thanks! Parametrized version is below. It indeed makes some lambdas easier to write

import kotlin.time.Duration

class Frame<T>(
    val delayBefore: Duration,
    val content: T,
)

fun <T> ANIMATE(frames: Iterator<Frame<T>>)
fun <T> ANIMATE(sequence: Sequence<Frame<T>>)
fun <T> ANIMATE(iterable: Iterable<Frame<T>>)
fun <T> ANIMATE(firstFrame: Frame<T>, nextFrame: (Frame<T>) -> Frame<T>?)
fun <T> ANIMATE(nextFrame: () -> Frame<T>?)
fun <T> ANIMATE(delay: Duration, iterator: Iterator<T>)
fun <T> ANIMATE(delay: Duration, sequence: Sequence<T>)
fun <T: Any> ANIMATE(delay: Duration, nextValue: () -> T?)
fun <T: Any> ANIMATE(delay: Duration, seedValue: T?, nextValue: (T) -> T?)
fun <T> ANIMATE(delay: Duration, iterable: Iterable<T>)
fun <T> ANIMATE(framesCount: Int, delay: Duration, frameByIndex: (index: Int) -> T)

@nikolay-egorov
Copy link

Can one of them with functional parameters be with inline modifier? Since they only serve delegating role, it may redice them without warmup

@ark-1
Copy link

ark-1 commented Apr 19, 2024

We don't actually need type parameters in any of the overloads except (firstFrame,nextFrame) and (seedValue,nextValue). They will just cause unnecessary inference problems with unclear errors, if user types something wrong or too complex, and they provide no actual benefit. We can just use Frame<*>, Any? and Any.

Also, I suggest declaring Frame as class Frame<out T>(...).

@nikolay-egorov
Copy link

nikolay-egorov commented Apr 19, 2024

True, agree with the above. * and Any? looks right as a broadest spectre

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment