Reputation: 3
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
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