Serialize a function to JSON

Is there a way to serialize a function to JSON?

I try to do

Json.encodeToString(fun(i:Int): Int = i * 2)

I get “Class () is not registered for polymorphic serialization in the scope of ‘Function1’.
Mark the base class as ‘sealed’ or register the serializer explicitly”.

Marking the class as sealed does not work in my case as I don’t want to make this class abstract. In any case, this should have nothing to do with where the code is run from.

No, this is not possible. Function is a compiled bytecode, there is no simple way to represent it as text or even as bytes. You would have to use some bytecode manipulation util, but even then I don’t know if this is that easy to deserialize it back to a working function.

3 Likes

Java lambda is serializable-ish. All captured arguments must be serializable though. Maybe the same trick can be done in kotlin. A serializable lambda which is stored as a field in a class and can be normally deserialized. A binary which is result of serialization can be converted to string with Base64 and sent by JSON.

That being said I think whatever your problem is, sending a serialized lambda is the last solution you want to use. Consider sending an id to a lambda which is executed on a cloud or a separate microservice.

2 Likes

Please note this doesn’t serialize the code of the lambda. It serializes arguments and a “reference” to the lambda located already in the classpath. To use this we have to serialize and deserialize using exactly the same code base. It could be fine for some use scenarios and useless for others.

1 Like

Good point. So sending by JSON isn’t an option, unless you send a codebase too :rofl: .

Um actually (:laughing:), you can load classes over the network with the Java standard URLClassLoader. IIRC there’s Java Trial tutorial for it that is essentially a serialized lambda with a “ComputeTask” interface. They do cover some security tooling you have to jump through but I’ll forever be suspicious of any “feature” of arbitrary code execution… over the network! :grimacing:

Just in case someone new to programming reads this: Do not do that.

1 Like

I need a solution where the user can write a math expression, but I found another solution, that will also be safer.

That being said, I think it would be useful to somehow be able to serialize a complete object, there should be a way to simply take what’s in memory and convert to a string (readable or not). That’s especially useful for those who don’t use databases.

Another more generic option is to store/transfer a function as a pure string and use Kotlin Script Engine to compile and execute it.

Converting a chunk of bytes to a string is easy. Converting a string back to a chunk of bytes is also easy. The hard part is knowing what that chunk of bytes means at the other end. Is it an object of type Foo, or of type Bar, or an array of Bazs? What if the code on the other side has no idea what a Foo, Bar, or Baz is?

Isn’t that just to store the object type as part of the bytes? I thought that was how it is already.

Only if the relevant class(es) are also defined on the target system. Otherwise, the rest of the bytes won’t make any sense.

If the target is the same system (e.g. you’re storing the lambda’s state on disk so it can later be reloaded by the same running program, or another invocation of it), then of course there’s no problem. But in other cases, you could run into all sorts of trouble if they’re not all available, or the versions differ significantly.

(Back in the early days of Java and CORBA, I remember talk of using Java to write intellligent ‘agents’ — programs which could send themselves to a remote system and then carry on running there, moving from system to system in order to find the right services, and then returning to the original system with the results. It was all very exciting, but I never quite saw the point… Things have gone very quiet since then, so I’m guessing that the prospects didn’t pan out. Serialising only the state, and not the behaviour, is much more straightforward.)

Yeah, of course the types need to be available on the target system. It would be really useful to be able to serialize an object, and then load the object again later, for example from a database. Is there any way to do this currently?

This is exactly what serialization frameworks do. Of course, we can’t serialize just any object, it has to meet some requirements provided by the framework.

Going back to lambdas: technically speaking, there is no such thing as lambda. Lambdas are simply classes, only represented differently in the code. That means two things. First: yes, in many cases they can be serialized, then deserialized and even executed. Second, underneath lambda could be many much different things. We don’t really serialize/deserialize “the lambda”, but the class it represens and this class could be Function0, it could be Function2<Int, Int, Int>, it could be Runnable, Callable, Supplier or MyCustomClass. This is what you really serialize and if you want to be able to execute it after deserialization, then you have to think in terms of working with types mentioned above, not in terms of “lambdas”.

So the real question here is: what do you mean by “lambda”? Depending on your specific case, there could be many different answers.

edit:
Also, please be aware lambdas don’t have stable/reliable type names in the code. If you store such lambda in the DB, then to make sure you can load it back, you not only has to use the same application, but also in exactly the same version. If you save, then rebuild the application and load, then it may crash.

edit2:
I just realized you never mentioned “lambdas” - in your first post you asked about “functions” and provided an example of Function1. If this is your case and you store Function0, Function1 and similar objects across your application, then yes, it is potentially possible to serialize, deserialize and execute them. Although that depends on the specific implementation. Some could be serialized, others couldn’t.

To be more precise: a lambda is a syntactic structure, but not a semantic one. A lambda is simply a convenient way of defining an anonymous function (which is itself implemented, as you say, as a method of an anonymous class implementing the relevant interface).

So there’s no such thing as a lambda in the compiler output, though there clearly is in the code!

1 Like