Java - passing a method to a class

snotnose

Ars Tribunus Militum
2,660
Subscriptor
I have 2 classes. Foo is a bunch of inter-related text fields, and Bar implements those fields and does all the error checking. I don't want the user leaving a text field when it has invalid data.

There are a bunch of checks between Bars that Foo understands and Bar knows nothing about. As Bar is getting the keystroke events it needs to do the verification. So how does Foo tell Bar how to validate the field?
Code:
class Foo {
    Foo() {
        Bar bar = new Bar(validateRoutine);
    } 
    boolean validateRoutine(Blatz b) {
        return isvalid(b);
    }
}

class Bar {
    JTextField textField;
    boolean goNoGo;
    Bar(boolean validate) {
        goNogo = validate;
        textField = new JTextField();
        addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent event) {
                char key = event.getKeyChar();
                Blatz b = new Blatz(key);
                if(goNoGo(b)) {
                    // w00t!
                } else {
                    // BTW, how do I flash textField.background() red for
                    // half a second or so?
                }
            }
        });
    }
}

I've googled it but, too be honest, my Java isn't yet good enough for me to understand what they're talking about and the examples seem, quite frankly, stupid and meaningless.
 

ShuggyCoUk

Ars Tribunus Angusticlavius
9,808
Subscriptor++
first off you question sounds like "how do I do first class functions in java" historically that answer was "make a class with one method, it's shit suck it" things are better now though. But really your question looks a bit funny in terms of code.

I have 2 classes. Foo is a bunch of inter-related text fields, and Bar implements those fields and does all the error checking.

There's some issue here. Foo most definitely isn't a bunch of interrelated text fields. it's a bunch of Bars (one in this example but I presume you have more in reality?
Foo has no swing related stuff in it but Bar does, that's generally a bad sign.

That said I can't extrapolate that issue from the sample there so I'll leavwe it hanging and if you want any more context just ask.

Here's the answer I think to what you want.

You're using boolean in a place where what you want/meant is actually a Predicate<Blatz> (in c# this would be a Func<Blatz,bool>. I may be wrong on the specific validation type needed for swing1.


I typed this quick from memory/quick google of Predicate<T>, in theory the compiler should transform you validateRoutine reference for you but ages since I used java in anger
Code:
class Foo {
    Foo() {
        Bar bar = new Bar(validateRoutine);
    } 
    boolean validateRoutine(Blatz b) {
        return isvalid(b);
    }
}

class Bar {
    JTextField textField;
    BooleanSupplier goNoGo;
    Bar(BooleanSupplier validate) {
        goNogo = validate;
        textField = new JTextField();
        addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent event) {
                char key = event.getKeyChar();
                Blatz b = new Blatz(key);
                if(goNoGo.test(b)) {
                    // w00t!
                } else {
                    // BTW, how do I flash textField.background() red for
                    // half a second or so?
                }
            }
        });
    }
}
1. There's no structural typing for this in many languages, including java so two things named Bob and Rob whose type signature are identical are not the same thing and cannot be substituted for one another)
 

snotnose

Ars Tribunus Militum
2,660
Subscriptor
Foo has no swing related stuff in it but Bar does, that's generally a bad sign.

I'm new to this OO stuff, but the idea was Foo does the heavy lifting, and Bar makes things pretty. I started out with Foo doing everything, then thought "hmmm, objects?", and made Bar. But I have the fundamental problem that the routine verifying the data has no idea what valid data is.

If y'all say so I'm more than willing to put all the GUI code back into Foo and be done with it. I just thought breaking up my data and my GUI as what I was supposed to do.

Other options I've found are a Functional Interface, but I hate adding 3 line files to my project. I also found Predicate<T>, that's where the "I don't grok Java well enough yet" came from. I have no clue how to use it and the examples are useless.
 

ShuggyCoUk

Ars Tribunus Angusticlavius
9,808
Subscriptor++
Looking at your Example Blatz appears to add no value. Just pass a char around (or the Character wrapper whatever that is in java - I hate those wrappers)

Having Bar take a function from char to boolean is no problem1, and very solid design regardless of "OO" (you demand the very minimum of the user of Bar). I'm not saying it's the right wy to do a UI BTW. the predictae you pass in (or lambda, it compiles to the same thing) needs to know it's operating inside the main UI loop so it have a bunch of implied rules and behaviours (being fast, not modifying anythign else it shouldn't, not blocking etc) but in many cases that is clear and reasonable from context.

1. Apart from those shitty wrappers and the like for things. Really I wouldn't learn OO in java these days, there's much better languages for it, including c# but also TypeScript or Python might work for you and are also cross platform (no clue on the widget libraries in python though, sorry)
 

ShuggyCoUk

Ars Tribunus Angusticlavius
9,808
Subscriptor++
being precise:

You want Bar to be passed a function to call, but not use it on construction, only on the callbacks from the GUI widget.

That function must end up being an actual method somewhere (it's Java, everything is a method) but a lambda might be fine in the source. Bar cares not that this function comes from Foo, just that it behave nice on a gui callback.
 

etr

Ars Scholae Palatinae
695
passing a method to a class

You cannot do this directly, but you can wrap a method in an class, instantiate it, and then pass the object.

One way to do this would be with an internal class. Something like this might do the trick (apologies, I'm rusty):

Code:
class Foo {
   class BarValidator extends/implements Validator {
      boolean validate(Blatz b) {
         return isValid(b);
      }
   }
    Foo() {
        Bar bar = new Bar(new BarValidator());
    } 
}

class Bar {
    JTextField textField;
    BooleanSupplier goNoGo;
    Bar(Validator validator) {
        goNogo = validator;
        textField = new JTextField();
        addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent event) {
                char key = event.getKeyChar();
                Blatz b = new Blatz(key);
                if(goNoGo.valiate(b)) {
                    // w00t!
                } else {
                    // BTW, how do I flash textField.background() red for
                    // half a second or so?
                }
            }
        });
    }
}

Some points to bring up:
(1) You would need to implement or re-use a supertype (parent class or interface) for Validator
(2) This was actually a common trick with Java UI classes years ago
(3) This may not be the best approach to your specific problem, just one worth being aware of

I'm operating from memory here, but if you can still find the "Thinking in Java" material, I found that very helpful for learning back in the day. That said, I've never been a long term Java coder, and my use pre-dated key features like generics. YMMV
 

ShuggyCoUk

Ars Tribunus Angusticlavius
9,808
Subscriptor++
Education/mentoring by forum is hard. I really just want to chat you through it.

Providing the validation function as a first class function (i.e. something you can put in a variable) is just fine, Java just makes it a bit harder (and seem way harder because lots of old docs/examples required even more complex and limited hoops)

OO is (grossly) overused in parts, and was horribly faddish about 20 years ago. Some bits do make sense, but often actually because they can provide a pretty low cost abstraction (especially when backed by a JIT) for late bound implementation choices thanks to vtables as the last resort being okay - especially with caches and branch prediction
 
  • Like
Reactions: Lt_Storm

snotnose

Ars Tribunus Militum
2,660
Subscriptor
Yeah, that was the explanations I couldn't grok. They say "Use lambdas" and proceed to use println() to print stuff in an array. I couldn't figure out where the "pass a function pointer" part happened.

Not to mention they do it in the middle of a stream. Which, OK, I've done some streams. But I wouldn't call myself good at them, much less figure out which part is a stream and which part is passing a function pointer.

I'm still curious about how to do it in Java but as I've solved my original problem it's on a back burner..
 

koala

Ars Tribunus Angusticlavius
7,498
Java:
$ cat Sample.java
class Sample {

  public static int foo(java.util.function.Function<Integer,Integer> f, int value) {
    return f.apply(value);
  }

  public static class OtherFunction implements java.util.function.Function<Integer,Integer> {
    public Integer apply(Integer i) {
      return i * 3;
    }
  }
 
  public static void main(String[] args) {
    java.util.function.Function<Integer,Integer> x = (n) -> n*2;
    System.out.println(foo(x, 2));
    System.out.println(foo(new OtherFunction(), 3));
  }
}
$ javac Sample.java
$ /usr/lib/jvm/jre-22/bin/java Sample
4
9

java.util.function.Function is an interface that defines a single abstract method. (All the functions in java.util.function are.) This single method takes one argument and returns an argument.

Therefore, lambdas can be "casted" to Function if their signature matches. The lambda in the first line of the main function takes and returns an Integer so it can be "casted" to Function<Integer,Integer>.

Then you can pass instances of Function around as if they were function pointers. OtherFunction is really basically just its apply function.

Functions such as foo can take Function arguments. The "ugliness" is that you must call the apply method.
 

Lt_Storm

Ars Praefectus
15,959
Subscriptor++
Education/mentoring by forum is hard. I really just want to chat you through it.

Providing the validation function as a first class function (i.e. something you can put in a variable) is just fine, Java just makes it a bit harder (and seem way harder because lots of old docs/examples required even more complex and limited hoops)

OO is (grossly) overused in parts, and was horribly faddish about 20 years ago. Some bits do make sense, but often actually because they can provide a pretty low cost abstraction (especially when backed by a JIT) for late bound implementation choices thanks to vtables as the last resort being okay - especially with caches and branch prediction
that and it's hardly the best example of OOP in existence. Early versions were crude and written without bells and whistles least some fool developer do something foolish, and the language still suffers from those decisions. Honestly, a language like Smalltalk or Ruby is probably a better example of the form. Both those support first class functions noticably better than does Java even today.
Java:
$ cat Sample.java
class Sample {

  public static int foo(java.util.function.Function<Integer,Integer> f, int value) {
    return f.apply(value);
  }

  public static class OtherFunction implements java.util.function.Function<Integer,Integer> {
    public Integer apply(Integer i) {
      return i * 3;
    }
  }
 
  public static void main(String[] args) {
    java.util.function.Function<Integer,Integer> x = (n) -> n*2;
    System.out.println(foo(x, 2));
    System.out.println(foo(new OtherFunction(), 3));
  }
}
$ javac Sample.java
$ /usr/lib/jvm/jre-22/bin/java Sample
4
9

java.util.function.Function is an interface that defines a single abstract method. (All the functions in java.util.function are.) This single method takes one argument and returns an argument.

Therefore, lambdas can be "casted" to Function if their signature matches. The lambda in the first line of the main function takes and returns an Integer so it can be "casted" to Function<Integer,Integer>.

Then you can pass instances of Function around as if they were function pointers. OtherFunction is really basically just its apply function.

Functions such as foo can take Function arguments. The "ugliness" is that you must call the apply method.
And, these days, you can do similar things with other single function interfaces such as Predicate.
 

Lt_Storm

Ars Praefectus
15,959
Subscriptor++
Not to mention they do it in the middle of a stream. Which, OK, I've done some streams. But I wouldn't call myself good at them, much less figure out which part is a stream and which part is passing a function pointer.
Streams are just Java's implementation of an internal iterator ala Ruby's Enumable. Meaning that, rather than write a loop, you pass some sort of single function object / interface (this is Java, such things always have to be a bit over complicated), and then it execute it on every item in the collection to sort, map, group be, etc

What do you mean? I admit I haven't paid much attention to java.util.function, but I thought it was fairly feature-complete since day one of it existing?
This is Java, functions can't just be functions. Instead, they have to be something that implements a particular interface, be that java.util.Function, or Predicate. And, of course, Function<T, Boolean> is a different thing than a Predicate<T>, because it's Java and type compatibility is a mess.

Edit: or to put this another way, first class functions work better when the first version of the language includes them rather than adding them piecemeal one kludge at a time. But, first class functions are a sharp edge and this is an object oriented language, nobody needs good support for that functional BS. (Never mind how the first object printed language had support for first class functions, because who, upon being inspired by Lisp, wouldn't).
 
Last edited: