1

I have an interface which is

public static interface MyClass{
    public boolean doSomething(boolean a, boolean b);
}

I then instantiate a variable

MyClass a = (boolean x, boolean y) -> x && y;

Now my question is that if I want to get the parameters x and y and the return value, how would I go about doing that? The reason I want to get the parameters is because I want to serialize so that I am able to do a ObjectOutputStream.writeObject() with them.

Not sure if my question fully makes sense. I haven't worked with lambda too much so any sort of guidance will be greatly appreciated.

Adding On: OK so MyClass a is instantiated in another class, let's call it ParentClass. So now I have

MyClass a = (x, y) -> x && y;
    ParentClass b = new ParentClass();
    b.setMyClass(a);

Now in the main class that I am working in, I get passed ParentClass b. So I take it and do MyClass c = b.getMyClass; Which if I understand correctly is a reference to (x, y) -> x && y;. Now the question is, how do I get the values of the parameters and return value so that I can serialize it. Also MyClass will not always be (x,y) -> x && y, it could be anything i.e

MyClass a = (x, y) -> x || y;
MyClass a = (x, y) -> x^y;
MyClass a = (x, y) -> true;

I'm not allowed to modify MyClass or ParentClass. Which is why I was trying to get the parameters passed and the return value so that I could serialize those and send them through.

user2989280
  • 117
  • 3
  • 8

3 Answers3

3

I suspect you are misunderstanding how lambda expressions work. Your question implies that you are expecting to create your a object and then serialize it and in the process somehow record the values of x and y. Have I understood you correctly?

If so then this is fundamentally not how lambdas work. They are not an object containing state in the ordinary sense. Rather think of them as a bit of executable code that you can pass around that can be applied to a set of values whenever you want (I suspect I'll be hammered in the comments for that overly simplistic explanation!).

You can serialize lambdas but in that case you are serializing the operation represented by the lambda, not the values passed to it in any given invocation.

If you want implementations of the MyClass interface to be serializable then it needs to extend Serializable. It should look as follows:

@FunctionalInterface
public interface MyClass extends Serializable {
    boolean doSomething(boolean a, boolean b);
}

If you can't modify MyClass then you can still cast a MyClass object to Serializable:

Serializable a = (Serializable & MyClass)(a, b) -> a || b;

Or if you are using the value from a ParentClass:

Serializable a = (Serializable)b.getMyClass();

You should then be able to serialize a.

Just remember when you deserialize that you need to cast back to MyClass so that you can use it. It will look something like:

MyClass b = (Serializable & MyClass)objectInStream.readObject();
b.doSomething(true, false);
sprinter
  • 27,148
  • 6
  • 47
  • 78
  • OK that makes sense...how can I go about serializing a lambda though? I have little to no experience in lambdas, let alone understanding how to serialize it. – user2989280 Nov 13 '15 at 22:54
  • I've looked at that post but don't understand how to implement it in my function. I do `MyClass a = (MyClass & Serializable) b.getMyClass();` but when I go to write it to the outputstream, I get Lambda cannot be cast to java.io.Serializable – user2989280 Nov 13 '15 at 23:04
  • You need to define the `MyClass` interface as extending `Serializable`. – sprinter Nov 13 '15 at 23:05
  • I would, but I'm not allowed to modify `MyClass` or `ParentClass`. Which is why I was trying to get the parameters passed and the return value so that I could serialize those and send them through. I appreciate the help. Thanks. Sorry for being difficult – user2989280 Nov 13 '15 at 23:08
  • 1
    That would have been useful information to have in the original question! – sprinter Nov 13 '15 at 23:10
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/95093/discussion-between-user2989280-and-sprinter). – user2989280 Nov 13 '15 at 23:14
2

In Java, the lambda syntax is, simply, a way to describe the behaviour of a method without giving it a name.

e.g. (Type1 arg1, Type2 arg2, ...) -> <expression> defines a function looking something like this:

public TypeOfExpression anonymousMethod(Type1 arg1, Type2 arg2, ...) {
    ...
    return <expression>;
}

Look on the Java Tutorials for more info on lambdas.

In fact the lambda expression (boolean x, boolean y) -> x && y (when given type MyClass as you define it) is nothing but syntactic sugar for the following:

new MyClass() {
    public boolean doSomething(boolean x, boolean y) {
        return x && y;
    }
}

Hopefully that gives some clarity into what lambdas are representing in Java.

In technical terms, the interface definition you gave defines a 'function type'. In Java, any interface which has only a single method is called 'functional', and can be used, instead of as an interface, as the type of a lambda expression of the same type as the single method in the interface.

This decision was presumably made because if an interface has only one method, all that is needed to specify it is the behaviour of that method, which can be far more concisely written in the lambda notation, as demonstrated above.

So, the lambda expression is nothing but an instance of your interface - in particular, it has no fields, but defines a method behaviour. I think you are assuming instead that it encapsulates a pair of inputs and their output result. If this is what you need, you might be looking for something more like a pair type with a built in operation (like && in this case).

EDIT: on serializability.

It's apparent that you require serialization of an unknown function of MyClass type. If MyClass extends Serializable, you should be able to cast appropriately and serialize. If you're not in control of MyClass, so can't ensure this, the following ad hoc observation may help.

If the method in MyClass is indeed of the type shown here (boolean, boolean) -> boolean, there are a small enough number of cases to consider that you can manually serialize.

The number of 'possible' (total) functions of type A -> B, for finite-sized types A and B is |B|^|A| (size of B to the power size of A). This is because, counting the possible functions, for each input of type A there are |B| possible outputs the function could give.

Also, the size of the pair type (A, B) is |A|*|B|.

In our case, we have (boolean, boolean) -> boolean. But boolean is only of size 2! So (boolean, boolean) is of size 4, and (boolean, boolean) -> boolean is of size 2^4 = 16.

How do we work out which of these 16 functions we have on our hands? Simply enumerate through the possible inputs (only 4 to do). Then we can record the four outputs in variables something like this (where a will be our unknown function.)

boolean ttout = a(true, true);
boolean tfout = a(true, false);
boolean ftout = a(false, true);
boolean ffout = a(false, false);

Then we can merrily serialize these four values. :)

Further, if we are deserializing and obtain the four values (ttout, tfout...) we can reconstruct the function something like this:

a = (boolean x, boolean y) -> {
    if (x) {
        if (y) return ttout;
        else return tfout;
    } else {
        if (y) return ftout;
        else return ffout;
    }
}
Oly
  • 2,329
  • 1
  • 18
  • 23
  • OK, I'm starting to understand the syntax a lot more (been doing a lot of reading online) and your conversion makes a lot of sense too. But my initial problem still remains. I have `MyClass a = (x, y) -> (some return value)`. This is instantiated in another class and I am only given the variable a. How can I serialize that variable? – user2989280 Nov 13 '15 at 23:33
  • If serializing the interface/lambda expression is all you require, it looks like people have suggested good things already. It will be necessary that `MyClass` extends `Serializable`, though: if you are expecting an unknown instance of `MyClass`, you can't assume it'll be serializable if not. – Oly Nov 13 '15 at 23:43
  • If you're not in control of the definition of `MyClass` (so can't ensure it's serializable), one thing that occurs to me is that, if indeed all instances operate on (primitive) boolean inputs, there are actually only four inputs to consider - you could manually serialize any possible binary operation on booleans in as little as four bits! (One for result of input (true, true), one for (true, false).....) – Oly Nov 13 '15 at 23:45
  • Yeah but how will I know which one it was that was originally passed into the variable `a`? It could be any of the four and there could be different return values, depending on what the user inputs. – user2989280 Nov 13 '15 at 23:49
  • 1
    Edit is now done; I explain and demonstrate an ad hoc way to serialize binary operators over primitive booleans. The manner in which you actually serialize the variables I obtain in the example is up to you - a literal four-bit value would be enough, but it might just be easier to group them as four values of a small array or something. – Oly Nov 14 '15 at 00:06
  • We serialize all the possibilities but how do we know which one was originally passed to the function? i.e how do we compare to the original return value? – user2989280 Nov 14 '15 at 01:07
  • 1
    I refer you to the first part of my answer and the other answers on this question. :) it seems there's still a misunderstanding of what a lambda is. It's nothing but a function; in particular, it doesn't retain any information about what inputs it's been called with and what the results were. In fact, we can (and do, often!) have functions which are never called at all, so it makes no sense to ask what argument was 'originally passed to the function': when asking about a function, we care about how it behaves, not how it may or may not have been used in the past. – Oly Nov 16 '15 at 14:11
  • 1
    Of course, my ad hoc example of how to manually serialize arbitrary binary operators on booleans makes several 'pure functional' assumptions: the function is deterministic (its result does not depend on chance, or the time of day, or the weather...) and total (there are no inputs for which its output is undefined, represented in Java probably by either an exception or an infinite loop). For operations on primitive booleans these assumptions seem reasonable. – Oly Nov 16 '15 at 14:17
  • what is type of a? – Sergei Krivonos Sep 25 '17 at 11:53
1

If you want a itself to be serializable, you can write a = (MyClass & Serializable) (boolean x, boolean y) -> x && y.

There is no x or y just from the definition of a, though: those only exist when a is actually invoked.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413