Skip to content

Entry generic#752

Open
hannesa2 wants to merge 9 commits intomasterfrom
EntryGeneric
Open

Entry generic#752
hannesa2 wants to merge 9 commits intomasterfrom
EntryGeneric

Conversation

@hannesa2
Copy link
Copy Markdown
Collaborator

@hannesa2 hannesa2 commented Mar 29, 2026

Before with Float

image

now with optional Double
image

@hannesa2 hannesa2 added the breaking-change Breaking change label Mar 29, 2026
@hannesa2 hannesa2 force-pushed the EntryGeneric branch 4 times, most recently from 05d340d to c8e8daf Compare March 30, 2026 04:38
to be able to use it as Float or Double
Use BaseEntry<Float> instead of FloatEntry
The problem is invariant generics. BarDataSet is DataSet<BarEntryFloat>, so entries expects MutableList<BarEntryFloat>. Even though BarEntryDouble : BarEntryFloat, MutableList<BarEntryDouble> is not a MutableList<BarEntryFloat> because MutableList is invariant (it's both a producer and consumer).

MutableList<T> is invariant in T because it both reads (get() → T) and writes (add(T)). Even though BarEntryDouble : BarEntryFloat, the compiler must reject the assignment to prevent this kind of unsound write:

val list: MutableList<BarEntryFloat> = values  // if allowed...
list.add(BarEntryFloat(1f, 2f))                // would corrupt the original BarEntryDouble list!

The @Suppress("UNCHECKED_CAST") cast is safe here because:
* JVM erases generics at runtime — both are just MutableList on the heap
* BarDataSet only reads entries from the list as BarEntryFloat, and BarEntryDouble IS a BarEntryFloat
* Nothing writes a plain BarEntryFloat back into the list through BarDataSet
The problem is invariant generics. LineDataSet is LineDataSet<EntryFloat>, so entries expects MutableList<EntryFloat>. Even though EntryDouble : EntryFloat, MutableList<EntryDouble> is not a MutableList<EntryFloat> because MutableList is invariant (it's both a producer and consumer).

MutableList<T> is invariant in T because it both reads (get() → T) and writes (add(T)). Even though EntryDouble : EntryFloat, the compiler must reject the assignment to prevent this kind of unsound write:

val list: MutableList<EntryFloat> = values  // if allowed...
list.add(EntryFloat(1f, 2f))                // would corrupt the original EntryDouble list!

The @Suppress("UNCHECKED_CAST") cast is safe here because:
* JVM erases generics at runtime — both are just MutableList on the heap
* LineDataSet only reads entries from the list as EntryFloat, and EntryDouble IS a EntryFloat
* Nothing writes a plain EntryFloat back into the list through DataSet
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking-change Breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant