Salad Tea
Salad Tea

Reputation: 3

In Kotlin, is there any way to define method for a aliased type?

Say I have a aliased type:

typealias Bitmap5x5 = Int

Is there any way to define method for this type, as if it's a real object? Like some constructor, methods? I have GB level amount of data, so I don't have enough RAM to box them in real objects. (I tried, turns out to be horrible)

I'd have some methods which can be use like this:

var bitmap1 = Bitmap5x5(1) // a white one
var bitmap2 = Bitmap5x5(0) // a black one
bitmap1.drawVerticalLine(0, 3) // draw a black line a on column 3
bitmap2.drawHorizontalLine(1, 2)

Currently I have a static helper class Bitmap5x5Helper to group some methods like this, but kind of ugly:

var bitmap1 = Bitmap5x5Helper.makeBitmap(1)
var bitmap2 = Bitmap5x5Helper.makeBitmap(0)
bitmap1 = Bitmap5x5Helper.drawVerticalLine(bitmap1, 0, 3)
bitmap2 = Bitmap5x5Helper.drawHorizontalLine(bitmap2, 1, 2)

If it is impossible to handle integer like this, is there any way to just define static method for it? So at least directly, without the "Helper"

bitmap1 = Bitmap5x5.drawVerticalLine(bitmap1, 0, 3)

Upvotes: 0

Views: 50

Answers (1)

Sweeper
Sweeper

Reputation: 274035

You are looking for a value class. Bitmap5x5 can be written like this:

@JvmInline // if on JVM
value class Bitmap5x5(val value: Int) {
    fun drawVerticalLine(arg1: Int, arg2: Int): Bitmap5x5 { // I'm not sure what the parameters represent
        val newValue = value + arg1 + arg2 // imagine complicated calculations going on here
        return Bitmap5x5(newValue)
    }

    // fun drawHorizontalLine(...): Bitmap5x5 { ... }
}

Usage:

var bitmap1 = Bitmap5x5(1)
bitmap1 = bitmap1.drawVerticalLine(0, 3)

Note that you still have to write bitmap1 twice to reassign bitmap1. This is unfortunately not possible to avoid while also satisfying the requirement of not boxing the integer. This wouldn't have been a problem though if drawVerticalLine doesn't mutate the thing on which it is called, and instead mutates some external state, like draws something on the screen or something like that.

Note that although it may seem like Bitmap5x5(1) "boxes" an integer, no boxing actually occurs here. Boxing only occurs for value classes when it is necessary - for example, when you convert it to Any:

println(bitmap1) // boxing occurs here, otherwise an Int would be printed, which is not correct

For reference, here is the JVM bytecode that the three lines of code above generates:

   0: iconst_1
   1: invokestatic  #12                 // Method Bitmap5x5."constructor-impl":(I)I
   4: istore_0
   5: iload_0
   6: iconst_0
   7: iconst_3
   8: invokestatic  #16                 // Method Bitmap5x5."drawVerticalLine-SupUMkI":(III)I
  11: istore_0
  12: iload_0
  13: invokestatic  #20                 // Method Bitmap5x5."box-impl":(I)LBitmap5x5;
  16: astore_1
  17: getstatic     #26                 // Field java/lang/System.out:Ljava/io/PrintStream;
  20: aload_1
  21: invokevirtual #32                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
  24: return

Notice that box-impl is only called before calling System.out.println, and that constructor-impl returns an int (descriptor is (I)I). constructor-impl would have contained the code in the init block of the value class, but in this case, it's just an identity function.

Upvotes: 4

Related Questions