Using nested case classes with scodec - scodec

When defining my messages with scodec, I would like to use nested case classes. For example:
case class Foo(x: Int, y: Int)
object Foo {
def baseCodec = uint16 :: uint16
def codec = baseCodec.as[Foo]
}
case class Bar(a: Int, foo: Foo, b: Int)
object Bar {
val baseCodec = uint8 :: Foo.baseCodec :: uint16
val codec = baseCodec.as[Bar]
}
However, when trying to compile this I get the following:
error: Could not prove that shapeless.::[Int,shapeless.::[shapeless.::[Int,shapeless.::[Int,shapeless.HNil]],shapeless.::[Int,shapeless.HNil]]] can be converted to/from Bar.
val codec = baseCodec.as[Bar]
^
Is there a way of doing this? (In my real code, sometimes the nested case class appears at the beginning of the containing class' parameter list, sometimes in the middle and sometimes at the end).

I figured it out. You need to use the Codec, not the HList. This works:
object Bar {
//Foo.codec instead of Foo.baseCodec
val baseCodec = uint8 :: Foo.codec :: uint16
val codec = baseCodec.as[Bar]
}

Related

Understanding a lambda construct that contains dot followed by brackets

This is the function declaration for rememberCoilPainter:
#Composable
fun rememberCoilPainter(
request: Any?,
imageLoader: ImageLoader = CoilPainterDefaults.defaultImageLoader(),
shouldRefetchOnSizeChange: ShouldRefetchOnSizeChange = ShouldRefetchOnSizeChange { _, _ -> false },
requestBuilder: (ImageRequest.Builder.(size: IntSize) -> ImageRequest.Builder)? = null,
fadeIn: Boolean = false,
fadeInDurationMs: Int = LoadPainterDefaults.FadeInTransitionDuration,
#DrawableRes previewPlaceholder: Int = 0,
): LoadPainter<Any> {
}
The line of code I am having difficulty understanding is:
requestBuilder: (ImageRequest.Builder.(size: IntSize) -> ImageRequest.Builder)? = null
A dot appears after Builder followed by (size: IntSize)
This is the first time I've seen this construct in Kotlin and am not sure how to interpret it. This is a lambda. Normally the dot after an object refers to a sub component of a class or a package. But the ( ) after the dot isn't clear.
How do I implement the requestBuilder parameter?
This is a function with receiver type as described here: https://kotlinlang.org/docs/lambdas.html#function-types
Function types can optionally have an additional receiver type, which is specified before a dot in the notation: the type A.(B) -> C represents functions that can be called on a receiver object of A with a parameter of B and return a value of C. Function literals with receiver are often used along with these types.
It could be tricky to understand at first, but this is like you are providing a function/lambda that is a method of ImageRequest.Builder. Or in other words: your lambda receives one additional parameter of type ImageRequest.Builder and it is available in the lambda as this.
You can provide requestBuilder as any other lambda, but note that inside it you will have access to properties and methods of ImageRequest.Builder object that was provided to you.
What you are looking at is a "function literal with receiver". Speaking generically, a type A.(B) -> C represents a function that can be called on a receiver object of A with a parameter of B and return a value of C. Or in your example:
requestBuilder: (ImageRequest.Builder.(size: IntSize) -> ImageRequest.Builder)?
We have a function requestBuilder which can be called on a ImageRequest.Builder with a parameter size: IntSize and returns another ImageRequest.Builder.
Calling this function is just like calling any other function with a lambda as a parameter. The difference: You have access to ImageRequest.Builder as this inside your lambda block.
Hope the following example helps understand lambdas with receiver type:
data class Person(val name: String)
fun getPrefixSafely(
prefixLength: Int,
person: Person?,
getPrefix: Person.(Int) -> String): String
{
if (person?.name?.length ?: 0 < prefixLength) return ""
return person?.getPrefix(prefixLength).orEmpty()
}
// Here is how getPrefixSafely can be called
getPrefixSafely(
prefixLength = 2,
person = Person("name"),
getPrefix = { x -> this.name.take(x) }
)
How do I implement the requestBuilder parameter?
Hope this part of the code snippet answers the above:
getPrefix = { x -> this.name.take(x) }
PS: These lambdas with receiver types are similar to extension functions IMO.

Kotlin Any - Double missmatch

I am trying to pass arrays that can store value of Double, Int, Long or etc.
val input = arrayOf(1.3, 4.5)
val output = arrayOf(3) // Error Kotlin: Type mismatch: inferred type is Array<Int> but Array<Any> was expected
magic(input, output)
fun magic(input: Array<Any>, output: Array<Any>) {
// Do the magic
}
What type of parameters I have to use to do that?
You are probably looking for Number
fun magic(input: Array<Number>, output: Array<Number>) {
// Do the magic
}
val input = arrayOf<Number>(1.3, 4.5)
val output = arrayOf<Number>(3)
magic(input, output)
Based on your requirement, you could utilize the Number class. The documentation on the Kotlin website states that - Number is a "Superclass for all platform classes representing numeric values"
You could modify the magic function as follows -
fun magic(input: Array<Number>, output: Array<Number>) {
// Do the magic
}
Then, invoke the function by constructing the required parameters to the function -
val input = arrayOf<Number>(1.3, 4.5)
val output = arrayOf<Number>(3)
magic(input, output)

Encoding vector length field not adjacent to the vector

I have the following structure I like to encode.
I'm aware that I can encode a vector with vector() if the size field is directly in front of the vector data. But here the field encoding the vector size is not adjacent.
case class Item(
address: Int,
size: Int,
)
case class Header {
// lots of other fields before
numOfItems: Int,
// lots of other fields after
}
case class Outer(
hdr: Header,
items: Vector[]
)
Decoding of Outer is OK:
Header.numOfItems is read from the bit vector and items is created with vectorOfN(provide(hdr.numOfItems, Item.codec))
Encoding of Outer is the problem:
When encoding I would like to have numOfItem be taken from the items.length.
I'm aware that I could set numOfItems with additional code when the items Vector is updated or with something like a "before encoding callback".
The question is if there is a more elegant solution. To me Header.numOfItems is redundant with Outer.items.length, so ideally only the
Encoder should know about numOfItems.
You could try building a Codec using consume() and start without building the Outer object:
case class OuterExpanded(
fieldBefore: Int, // Field before number of items in the binary encoding
fieldAdter: Int, // Field after number of items in the binary encoding
items: Vector[Item] // Encoded items
)
// Single Item codec
def itemC: Codec[Item] = (int32 :: int32).as[Item]
def outerExpandedC: Codec[OuterExpanded] = (
int32 :: // Field before count
int32.consume( c => // Item count
int32 :: // Field after count
vectorOfN(provide(c), itemC)) // 'consume' (use and forget) the count
(_.tail.head.length) // provide the length when encoding
).as[OuterExpanded]
As defined above, you get the following when encoding: outerExpandedC.encode(OuterExpanded(-1, -1, Vector(Item(1,2), Item(3,4)))) returns
Successful(BitVector(224 bits,
0xffffffff00000002fffffffe00000001000000020000000300000004))
^ ^ ^ ^-------^-> First Item
|-1 | |-2
|Vector length inserted between the two header fields
Afterwards, you can xmap() the Codec[OuterExpanded] to pack the other header fields together into their own object. Ie (adding two conversion methods to Outer and OuterExpanded):
def outerC: Codec[Outer] =
outerExpandedC.xmap(_.toOuter,_.expand)
case class OuterExpanded(fieldBefore: Int, fieldAfter: Int, items: Vector[Item]) {
def toOuter = Outer(Hdr(fieldBefore,fieldAfter), items)
}
case class Outer(header: Hdr, items: Vector[Item]) {
def expand = OuterExpanded(header.beforeField1, header.beforeField1, items)
}
This can probably be adapted to more complex cases, though I'm not entirely familar with shapeless' heterogeneous lists – or HList – and there might be nicer ways to get to the length of the vector rather than calling _.tail.head.length in the example above, especially if you end up with more than one field after the number of encoded values.
Also, the Codec scaladoc is a nice place to discover useful operators
Based on the previous answer I came up with something like the code below.
I used the consume trick form above and an AtomicInteger to hold the size of the vector.
import java.util.concurrent.atomic.AtomicInteger
import scala.Vector
import org.scalatest._
import scodec._
import scodec.Attempt._
import scodec.codecs._
import scodec.bits._
object SomeStructure {
case class Item(
address: Int,
size: Int)
def itemC: Codec[Item] = (int32 :: int32).as[Item]
case class Hdr(
beforeField1: Int,
// vectorSize would be here
afterField1: Int)
// vectorSize is an "in" param when encoding and an "out" param when decoding
def hdrC(vectorSize: AtomicInteger): Codec[Hdr] =
(int32 ::
int32.consume(c => {
vectorSize.set(c);
int32
})((i) => vectorSize.get)).as[Hdr]
case class Outer(
hdr: Hdr,
var items: Vector[Item])
def outerC() = {
// when decoding the length is in this atomic integer
// when encoding it is set before
val c = new AtomicInteger(-1)
(hdrC(c) :: lazily(vectorOfN(provide(c.get), itemC)))
.xmapc(identity)((g) => { c.set(g.tail.head.length); g })
}.as[Outer]
}
import SomeStructure._
class SomeStructureSpec extends FlatSpec with Matchers {
val bv = hex"ffffffff00000002ffffffff00000001000000020000000300000004".bits
val v = Vector(Item(1, 2), Item(3, 4))
val bv2 = hex"ffffffff00000003ffffffff000000010000000200000003000000040000000500000006".bits
val v2 = Vector(Item(1, 2), Item(3, 4), Item(5, 6))
val o = Outer(Hdr(-1, -1), v)
"outerC" should "encode" in {
o.items = v
outerC.encode(o) shouldBe Successful(bv)
o.items = v2
outerC.encode(o) shouldBe Successful(bv2)
}
it should "decode" in {
o.items = v
outerC.decode(bv) shouldBe Successful(DecodeResult(o, BitVector.empty))
o.items = v2
outerC.decode(bv2) shouldBe Successful(DecodeResult(o, BitVector.empty))
}
}

Function definition: fun vs val

I'm curious about what is the suggested way to define member functions in Kotlin. Consider these two member functions:
class A {
fun f(x: Int) = 42
val g = fun(x: Int) = 42
}
These appear to accomplish the same thing, but I found subtle differences.
The val based definition, for instance, seems to be more flexible in some scenarios. That is, I could not work out a straight forward way to compose f with other functions, but I could with g. To toy around with these definitions, I used the funKTionale library. I found that this does not compile:
val z = g andThen A::f // f is a member function
But if f were defined as a val pointing to the same function, it would compile just fine. To figure out what was going on I asked IntelliJ to explicitly define the type of ::f and g for me, and it gives me this:
val fref: KFunction1<Int, Int> = ::f
val gref: (Int) -> Int = g
So one is of type KFunction1<Int, Int>, the other is of type (Int) -> Int. It's easy to see that both represent functions of type Int -> Int.
What is the difference between these two types, and in which cases does it matter? I noticed that for top-level functions, I can compose them fine using either definition, but in order to make the aforementioned composition compile, I had to write it like so:
val z = g andThen A::f.partially1(this)
i.e. I had to partially apply it to this first.
Since I don't have to go through this hassle when using vals for functions, is there a reason why I should ever define non-Unit member functions using fun? Is there a difference in performance or semantics that I am missing?
Kotlin is all about Java interoperability and defining a function as a val will produce a completely different result in terms of the interoperability. The following Kotlin class:
class A {
fun f(x: Int) = 42
val g = fun(x: Int) = 42
}
is effectively equivalent to:
public class A {
private final Function1<Integer, Integer> gref = new Function1<Integer, Integer>() {
#Override
public Integer invoke(final Integer integer) {
return 42;
}
};
public int f(final int value) {
return 42;
}
public Function1<Integer, Integer> getG() {
return gref;
}
}
As you can see, the main differences are:
fun f is just a usual method, while val g in fact is a higher-order function that returns another function
val g involves creation of a new class which isn't good if you are targeting Android
val g requires unnecessary boxing and unboxing
val g cannot be easily invoked from java: A().g(42) in Kotlin vs new A().getG().invoke(42) in Java
UPDATE:
Regarding the A::f syntax. The compiler will generate an extra Function2<A, Integer, Integer> class for every A::f occurrence, so the following code results in two extra classes with 7 methods each:
val first = A::f
val second = A::f
Kotlin compiler isn't smart enough at the moment to optimize such kind of things. You can vote for the issue here https://youtrack.jetbrains.com/issue/KT-9831. In case you are interested, here is how each class looks in the bytecode: https://gist.github.com/nsk-mironov/fc13f2075bfa05d8a3c3
Here's some code showing how f and g are different when it comes to usage:
fun main(args: Array<String>) {
val a = A()
exe(a.g) // OK
//exe(a.f) // does not compile
exe { a.f(it) } // OK
}
fun exe(p: (Int) -> Int) {
println(p(0))
}
Where f and g are:
fun f(x: Int) = 42
val g = fun(x: Int) = 42
You can see that g is an object that can be used like a lambda, but f cannot. To use f similarly, you have to wrap it in a lambda.

Define a numerical polymorphic module

I would like to define a module which could support int, int64 and float. For instance,
module Matrix =
struct
type 'a t = 'a array array
(* add point-wise 2 matrices with same dimension *)
let add (m: 'a t) (n: 'a t): 'a t =
...
end
The implementation of add needs the operator plus, which is + for int, +. for float and Int64.add for int64. So I can't write anyone of them, otherwise, the type of Matrix is no more polymorphic.
Could anyone tell me how you work around this problem?
One idea I have at the moment is to make the Matrix a functor:
module type NUM_TYPE =
sig
type t
val add: t -> t -> t
end
module Matrix =
functor (Elt: NUM_TYPE)
struct
type element = Elt.t
type t = element array array
(* add point-wise 2 matrices with same dimension *)
let add (m: t) (n: t): t =
...
end
Then I have to define the following numerical modules:
module MyInt =
(struct
type t = int
let add (a: t) (b: t): t = a + b
end: NUM_TYPE)
module MyFloat = ...
module MyInt64 = ...
module MatInt = Matrix(MyInt)
module MatFloat = Matrix(MyFloat)
module MatInt64 = Matrix(MyInt64)
By this method, I find it is tedious to define MyInt, MyFloat and MyInt64, especially their own add function. Does anyone have any idea to improve this?
You could write each of those in one line like this:
module MatInt = Matrix(struct type t = int let add = (+) end)
I don't think you can do much better in OCaml (have a look at this blog post: https://ocaml.janestreet.com/?q=node/37). This would be a very nice use of typeclasses. If you're ok with using language extensions you can have a look at this project: https://github.com/jaked/deriving.