Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@HopeBaron
Copy link
Member

This PR is to:

  • Implement indexing for cache items in kord
  • Reflection-free implementation
  • Introduce a obverver-like relationship on discards instead of descriptions

@HopeBaron HopeBaron changed the title cache rewrite? [Needs folder restructure] cache rewrite Apr 6, 2023
@lukellmann
Copy link
Member

lukellmann commented Apr 14, 2023

could you provide some examples how you think this all should be used (maybe also compared to the old cache api)? that way it will be easier to review because i would know what i'm looking at and what the intention was.

@HopeBaron
Copy link
Member Author

@lukellmann
https://gist.github.com/HopeBaron/8417dbbbfa814be381b8c8498f4ba534
Above is a full example
output:

{SnowflakeSetIndex(snowflakes=[1, 123])=MemberData(guildId=1, userId=123)}
{SnowflakeSetIndex(snowflakes=[123])=UserData(userId=123)}
{}
{}

@@ -0,0 +1,5 @@
package dev.kord.cache.api.observables

interface Index: Comparable<Index> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this index do? why is it comparable? would something like Identifier / Id / Key be a better name?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it may be composed of mutliple craitera thus I thought Index was a good name.

/**
* A cache that associates a [Value] with an [Index].
*/
public interface EntryCache<Value : Any> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it be generic over the index too? if i understand this right EntryCache is a specialized Map and Index is like a key for a Value

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the Entrycache doesn't have to be a map
you can implement a cache using a set data structure so it didn't make sense to provide an Index specially that "Indexing" is techincally optional and we don't really care about the key

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah but EntryCache could still have a generic for the concrete Index type (the Index interface wouldn't even be needed then)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've rewritten a possibly better implementation?

* Returns the [Relation] object for this cache, which contains information about any other
* caches that are observing this one.
*/
public suspend fun getRelations(): Relation<Value>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what would this be used for? Relation just has discard and to, both can be done from EntryCache too

/**
* Returns a defensive copy of the cache entries as a [Map] of [Index] to [Value].
*/
public suspend fun asMap(): Map<Index, Value>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so it gives a copied snapshot? what would we use this for?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should give a non-mutable type; I think returning the underlaying type is moer optimal than to copy the whole cache over.

Comment on lines 5 to 8
/**
* Removes any cached value [T] that satisfies the given [transform] function.
* @param transform A function that takes a value of type [T] and returns a boolean.
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is now in the wrong place, should be above removeIf

Comment on lines 15 to 18
public suspend fun firstOrNull(transform: (T) -> Boolean): T?


public suspend fun removeIf(transform: (T) -> Boolean)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public suspend fun firstOrNull(transform: (T) -> Boolean): T?
public suspend fun removeIf(transform: (T) -> Boolean)
public suspend fun firstOrNull(predicate: (T) -> Boolean): T?
public suspend fun removeIf(predicate: (T) -> Boolean)

i think predicate is a better name and also commonly used in e.g. stdlib

*
* @param T the type of the first entity in the relation.
*/
public interface Relation<T: Any> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this need to be a public interface now? it's no longer exposed by the other public interfaces so it could now just be an implementation detail

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be provided to customize the deletion process.
I've already added it to the implementation
What do you suggest we do with this one?

Copy link
Member

@lukellmann lukellmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think it would be a good idea to try using this rewrite in a new branch of the kord repo (using maven local for cache builds). that way we'll see whether some operations we require are still missing and how this new api would by used

/**
* Returns the value associated with the given [key] in the cache, or null if no such entry exists.
*/
suspend fun get(key: Key): Value?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
suspend fun get(key: Key): Value?
suspend operator fun get(key: Key): Value?

/**
* A cache for a map of entries where each [Value] is associated with a unique [Key].
* */
interface DataCache<Key : Any, Value : Any> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could Cache be a better name? it seems obvious that it caches data

/**
* Returns a [Map] containing all entries in the cache.
*/
suspend fun getAll(): Map<Key, Value>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, i'm not sure if we really need this

/**
* A cache for a map of entries where each [Value] is associated with a unique [Key].
* */
interface DataCache<Key : Any, Value : Any> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a function that's still missing is something that can return multiple values, i suggest a signature like:

fun filter(predicate: (Value) -> Boolean): Flow<Value>

* @param key The key to associate the [value] with.
* @param value The value to be cached.
*/
public suspend fun put(key: Key, value: Value)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public suspend fun put(key: Key, value: Value)
public suspend operator fun set(key: Key, value: Value)

@lukellmann
Copy link
Member

what i just realized is a problem with Cache.filter and Cache.firstOrNull: these will always have O(n) complexity because all objects have to be accessed to be filtered.

@HopeBaron
Copy link
Member Author

Yeah but the implementation doesn't specify a Key no more
if you are looking for something you can identify you can easily add that sort of data to your key.
Create a key out of it, and get it.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants