Skip to content

Conversation

@TheDrawingCoder-Gamer
Copy link

Attempt to make IArray work

I personally think after some testing it will end up being impossible for IArray to work and that when possible, ArraySeq should be preferred.

Right now, all tests pass except stack safe traverse, but stack safe traverse fails because of a cast error, and that leads be to believe that the instance will end up being unsound in a lot of cases where it needs to cast between Array[X <: AnyVal] and Array[X <: AnyRef]

@TheDrawingCoder-Gamer TheDrawingCoder-Gamer marked this pull request as draft November 12, 2025 16:08
@TheDrawingCoder-Gamer
Copy link
Author

copy pasted segments of discussion from discord, maybe someone else could make this work:

if casting a Array[Any] to an Array[Int] at runtime causes issues its not really surprising that doing the same on IArray would cause issues too
ArraySeq takes special care to keep track of the runtime implementation

the issue is that IArray is an opaque type with no extra bits, so we really are just working with a raw array
my hack was to summon a ClassTag[Any].asInstanceOf[T] but that obviously doesn't work with primitives
however, it seems you can call getClass.getComponentType, but no clue if that would work on JS or native
would be no help for fmap, or any similar thing as I need to know the exact type of the return
not exact, but exact enough to get a ClassTag

ArraySeq gets around that by making its output always boxed, and it can keep track of that safely
like all things IArray, it seems its relegated to only very specific, performance centered use cases

@johnynek
Copy link
Contributor

I think we could possibly solve some of these issues with a function like:

  def extractClassTag[A](arr: Array[A]): ClassTag[_] = {
    val componentClass = arr.getClass.getComponentType
    ClassTag(componentClass)
  }

and also using Class#isAssignableFrom, Class#isPrimitive and Class#isArray, I think we could solve many of the issues.

I think we need to get away from making the fake class tag from Any in every case.

Copy link
Contributor

@johnynek johnynek left a comment

Choose a reason for hiding this comment

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

Another thing we could do is break this up.

There are definitely sound typeclasses you can implement:

Hash[IArray[A]], Show[IArray[A]], Order[IArray[A]] Eq[IArray[A]] Foldable[IArray[A]]

I think all of those can be implemented without any casts or any funny business. We could add those first.

The ones that need to create IArray[A] parametrically may not be sound, and they may have to go into alleycats or something if we can't find a way to make them reliable.


def empty[A]: IArray[A] = {
implicit val fakeClassTag: ClassTag[A] = summonFakeTag[A]
IArray.empty[A]
Copy link
Contributor

Choose a reason for hiding this comment

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

IArray is defined as covariant:
https://github.com/scala/scala3/blob/b8afeea3de732d0cfccaa372e38af1bc02f7eb31/library/src/scala/IArray.scala#L8

So, I think we can return empty[Nothing] here and it will type check without any casts.

IArray.empty[A]
}

def combineK[A](x: IArray[A], y: IArray[A]): IArray[A] = {
Copy link
Contributor

Choose a reason for hiding this comment

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

So, something like:

val cx = getClassTag(x)
val cy = getClassTag(y)
if (cx.runtimeClass.isAssignableFrom(cy)) {
  // cy <:< cx
  implicit val ctA: ClassTag[A] = cx.asInstanceOf[ClassTag[A]
  x.appendAll(y)
}
else if (/* check the opposite */ {
 
}
else {
  // neither may be subclasses because one could be a primitive Int and the other a boxed Int, for example.
  // just do boxing here
  implicit val fakeClassTag: ClassTag[A] = ClassTag.Object.asInstanceOf[ClassTag[A]]
  x.appendedAll(y)
}

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