Java Callbacks?
- KVRist
- 393 posts since 12 Apr, 2020
Struggling here with really wanting to have C or JavaScript like callbacks where you can pass in a function pointer to a function vs defining an interface just to do a single use callback.
I did a bunch of google searches on the subject and they all say "build an interface"...I'd be happy to if it made sense but this really adds a lot of uneccessary code and passing around objects to do the callback. When you could simply pass a a function pointer. So I think there must be a better way...
... it seems like bitwig has callbacks right? They don't make you create implement an interface to get a callback from an observer. What is the programming pattern for that? How can I learn more about this wizardry
addValueObserver(), addIsPlayingObserver()...addHasContentObserver()... these all take some sort of specialized class as a parameter... IndexedBooleanValueObserver for example... Any ideas what the contents of that object type is? how it works? and why i can just pass a function into it? I love it because its so simple to use!
I did a bunch of google searches on the subject and they all say "build an interface"...I'd be happy to if it made sense but this really adds a lot of uneccessary code and passing around objects to do the callback. When you could simply pass a a function pointer. So I think there must be a better way...
... it seems like bitwig has callbacks right? They don't make you create implement an interface to get a callback from an observer. What is the programming pattern for that? How can I learn more about this wizardry
addValueObserver(), addIsPlayingObserver()...addHasContentObserver()... these all take some sort of specialized class as a parameter... IndexedBooleanValueObserver for example... Any ideas what the contents of that object type is? how it works? and why i can just pass a function into it? I love it because its so simple to use!
----------------------------------------------------------------------
/CTRL → http://slashctrl.io
Music & mixes → http://soundcloud.com/kirkwoodwest
/CTRL → http://slashctrl.io
Music & mixes → http://soundcloud.com/kirkwoodwest
-
- KVRist
- 316 posts since 18 Sep, 2020
My answer may not be the most accurate (I develop in Scala, not Java) but it's the quickest 
Snippet from Bitwig-generated project template:
If I'm reading this right, this is passing `onMidi0` function to `setMidiCallback` (as an anonymous class implementing a single-method ShortMidiDataReceivedCallback interface). I didn't try compiling that and cannot tell if that is correct (does it magically know how to turn three Ints into a ShortMidiMessage?), but it is demonstrating the capability to a) pass functions via anonymous lambdas and b) implement single-method interfaces inline as a function.
Scala definitely has those capabilities, I'm assuming modern Java is similar. Here is the Scala version:
(explicitly converting 3 Int arguments to ShortMidiMessage, no magic)
Snippet from Bitwig-generated project template:
Code: Select all
host.getMidiInPort(0).setMidiCallback((ShortMidiMessageReceivedCallback)msg -> onMidi0(msg));
...
private void onMidi0(ShortMidiMessage msg)
...
void setMidiCallback(ShortMidiDataReceivedCallback callback);
...
public interface ShortMidiDataReceivedCallback extends Callback
{
void midiReceived(int statusByte, int data1, int data2);
}
Scala definitely has those capabilities, I'm assuming modern Java is similar. Here is the Scala version:
Code: Select all
host.getMidiInPort(0).setMidiCallback((s: Int, d1: Int, d2: Int) => onMidi0(new ShortMidiMessage(s, d1, d2)))
...
private def onMidi0(msg: ShortMidiMessage): Unit
-
- KVRist
- 316 posts since 18 Sep, 2020
- KVRist
- Topic Starter
- 393 posts since 12 Apr, 2020
Totally in line with the conversation... thanks minortom! Probably gonna take me a bit to grok this, so I can implement them into my extension.
After a couple days of working through the examples in the drivenbymoss framework and experimenting them... I've been able to pass in the function reference... but now after all the previous googling and now reading this and I understand how that actually works! I get how to pass in the function reference to one of the bitwig callbacks clearly now and how the lambda really works.
My questions is, how do i implement one of these myself? is it all there? in https://www.javacodemonk.com/single-abs ... a-44f22fc3 ... or am I missing something.
like in JavaScript I would have something like this..
A couple things confusing to me in the example from javacodemunk... is that Runnable seems to be something that you would only use for multi-threading. where as I want my callbacks to block the thread and process, possibly even return some values... Specifically I also don't see in the examples is where the callback function stored and actually gets executed. Also some of the language typing <T> in all these places in the javacodemunk example is very new to me, but i'm sure i'll get that too in the next couple days.
I will google, read and sleep on this some more. maybe come back with a more specific example or an answer to my worries. Thanks again minortom! 
After a couple days of working through the examples in the drivenbymoss framework and experimenting them... I've been able to pass in the function reference... but now after all the previous googling and now reading this and I understand how that actually works! I get how to pass in the function reference to one of the bitwig callbacks clearly now and how the lambda really works.
My questions is, how do i implement one of these myself? is it all there? in https://www.javacodemonk.com/single-abs ... a-44f22fc3 ... or am I missing something.
like in JavaScript I would have something like this..
Code: Select all
function setCallback(callback) {
this.callback = callback;
}
function doCallback() {
this.callback();
}Code: Select all
public<T> Future<T> invoke(Callable<T> runnable) {
return executor.submit(runnable);
}----------------------------------------------------------------------
/CTRL → http://slashctrl.io
Music & mixes → http://soundcloud.com/kirkwoodwest
/CTRL → http://slashctrl.io
Music & mixes → http://soundcloud.com/kirkwoodwest
- KVRAF
- 4888 posts since 13 May, 2004
Simply create an interface with only 1 method and tag it with @FunctionalInterface., e.g.Kirkwood West wrote: Mon Oct 05, 2020 5:52 pm Totally in line with the conversation... thanks minortom! Probably gonna take me a bit to grok this, so I can implement them into my extension.
After a couple days of working through the examples in the drivenbymoss framework and experimenting them... I've been able to pass in the function reference... but now after all the previous googling and now reading this and I understand how that actually works! I get how to pass in the function reference to one of the bitwig callbacks clearly now and how the lambda really works.
My questions is, how do i implement one of these myself? is it all there? in https://www.javacodemonk.com/single-abs ... a-44f22fc3 ... or am I missing something.
like in JavaScript I would have something like this..
Code: Select all
function setCallback(callback) { this.callback = callback; } function doCallback() { this.callback(); }
Code: Select all
@FunctionalInterface
interface MyCallback
{
void dontCallMeIwillCallYou(event);
}
Code: Select all
void setMyCallback (MyCallback callback)
Code: Select all
anInstanceOfAFunkyClass.setMyCallback (event -> doSomething());
Code: Select all
anInstanceOfAFunkyClass.setMyCallback (new MyCallback ()
{
@Override
public void dontCallMeIwillCallYou(event)
{
doSomething());
}
});
- KVRist
- Topic Starter
- 393 posts since 12 Apr, 2020
Thanks for the funky code Moss! So Stoked! <3 will get after it!
will be certainly interesting when I get to this. I want to try building a display in that graphics window that you covered in your multi-threading tutorial. Will see... its on the wish list. You think its worth sending a feature request for this?
bruh... I plan to blow the planet up! infinite loops for life!moss wrote: Tue Oct 06, 2020 8:41 am Stay away from everything multi-threading!!! Until you absolutely know what you are doing.
will be certainly interesting when I get to this. I want to try building a display in that graphics window that you covered in your multi-threading tutorial. Will see... its on the wish list. You think its worth sending a feature request for this?
----------------------------------------------------------------------
/CTRL → http://slashctrl.io
Music & mixes → http://soundcloud.com/kirkwoodwest
/CTRL → http://slashctrl.io
Music & mixes → http://soundcloud.com/kirkwoodwest
-
- KVRist
- 45 posts since 12 Jan, 2018 from Cambridge, MA
Technically, the Bitwig API is uses thread-purposed classes, because....it is threaded internally. addValueObserver callbacks are not guaranteed to be called in order relative to each other for disparate *Values. A trick I've had to use a lot to get a semblance of synchronous API is using the threaded classes Atomic*, which guarantee that all sets happen before all gets iirc.
Just for a small example of why there must be at least a surface level understanding of threading is this little bug I had: if you booted one of my scripts, all the pads in a column lit up the exact same way. This was because I used both track.clipLauncherSlotBank().getItemAt(i).position().addValueObserver. and track.clipLauncherSlotBank().addPlaybackStateObserver. The bug was called because even though the first value observer might have been called, the playbackStateObserver would always use the position from the initial Value as the position (0), and since I was filtering events based off it, all the pads (in a column) would follow the state of the very first pad.
Just for a small example of why there must be at least a surface level understanding of threading is this little bug I had: if you booted one of my scripts, all the pads in a column lit up the exact same way. This was because I used both track.clipLauncherSlotBank().getItemAt(i).position().addValueObserver. and track.clipLauncherSlotBank().addPlaybackStateObserver. The bug was called because even though the first value observer might have been called, the playbackStateObserver would always use the position from the initial Value as the position (0), and since I was filtering events based off it, all the pads (in a column) would follow the state of the very first pad.
- KVRist
- Topic Starter
- 393 posts since 12 Apr, 2020
was experimenting this morning... failed. ended up with just passing the class into another class. what would be the data type for the event?moss wrote: Tue Oct 06, 2020 8:41 amCode: Select all
@FunctionalInterface interface MyCallback { void dontCallMeIwillCallYou(event); }
----------------------------------------------------------------------
/CTRL → http://slashctrl.io
Music & mixes → http://soundcloud.com/kirkwoodwest
/CTRL → http://slashctrl.io
Music & mixes → http://soundcloud.com/kirkwoodwest
- KVRAF
- 4888 posts since 13 May, 2004
Ah, sorry that happens when do not use an IDEKirkwood West wrote: Fri Oct 09, 2020 5:23 pmwas experimenting this morning... failed. ended up with just passing the class into another class. what would be the data type for the event?moss wrote: Tue Oct 06, 2020 8:41 amCode: Select all
@FunctionalInterface interface MyCallback { void dontCallMeIwillCallYou(event); }
You can give it any type you need, you could also have multiple parameters or none at all.
