Win a copy of Testing JavaScript Applications this week in the HTML Pages with CSS and JavaScript forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Bear Bibeault
  • Ron McLeod
  • Jeanne Boyarsky
  • Paul Clapham
Sheriffs:
  • Tim Cooke
  • Liutauras Vilda
  • Junilu Lacar
Saloon Keepers:
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • fred rosenberger
  • salvin francis
Bartenders:
  • Piet Souris
  • Frits Walraven
  • Carey Brown

Question about method reference, program behaviour in this particular case.

 
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello,
I tried really hard to understand logic behind this program, but couldn't figure it out. I would be really really grateful if You could help me.
For starters, I'm familiar with lambda/method references and method/behaviour parametrization, but in this case, I don't understand flow of the program, when method reference is used. (it's example for  learning ,from book).

In this program we simulate behaviour of a cell (like Microsoft Excell cell). It's a Publisher, Subsciber concept. In case, to be clear what it does I'll give an  example :

We implementing the behavior of "C3=C1+C2" ? Class ArithmeticCell is capable of storing two sides of an arithmetic operation (left and right).
ArithmeticCell has two variables : int left, and int right.  So that we could assign e.g SimpleCell C1 to int left, and SimpleCell C2 to int right.




Source code:




 
Marshal
Posts: 69847
278
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Your line 4is equivalent to taking an object of whichever functional interface you require there and getting it to execute the instruction c3.setLeft(c1);

Adding discussion to our λs forum.
 
Campbell Ritchie
Marshal
Posts: 69847
278
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Why does your setLeft() method do something other than setting the left cell? Why are you doing arithmetic in the same method?
 
Bartender
Posts: 4006
156
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think Campbells answer is a tad too simple, for me that is.

I, like OP, had to stare more than an hour to understand why this:

worked.

If you look at the method 'SimpleCell.subscribe', you see that the parameter is of type 'Subscriber<? super Integer>'. ArithmeticCell exends SimpleCell, that does not implement any Subscriber<?>. So the question is: how come Java recognizes in 'c1.subscribe(c3::setLeft)', 'c3::setLeft' as a Subscriber<Integer>? As usual: the first three repliers are in for a free yearsubscription to this site!

I found the generics confusing in the interfaces, so I adapted the code based on these interfaces:

A nice exercise, recommended!
 
Sheriff
Posts: 15801
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Try substituting c3::setLeft with n -> c3.setLeft(n) and see if it works, because I think that's basically what happens.

That is,

Edit: Sorry, I've been playing around with Kotlin the last few days so that syntax has bled over to my Java. I had initially posted c1.subscribe({n -> c3.setLeft(n)}); but it should have been without the {}.

Edit: if you're wondering how the lambda becomes an anonymous new Subscriber(), it's because the subscribe() method takes a Subscriber as its argument, so that's the type that Java will bind the lambda to. If you want to experiment, you can probably do something like this:

 
Junilu Lacar
Sheriff
Posts: 15801
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Here's how that flows:
1. c1 adds c3::setLeft as a Subscriber
2. The following anonymous object gets added to c1's subscribers:

3. When you call c1.onNext(10), it updates its own value to 10 (line 21) and then notifies all its subscribers (line 22)
4. The anonymous Subscriber's onNext() is called with 10 and so c3.setLeft(10) is invoked.
5. If c3 has subscribers, the same process continues until there are no more subscribers to notify, except c3 notifies its subscribers with onNext(10 + right).
6. After that, flow returns to the anonymous Subscriber's onNext() method which then finishes. The anonymous Subscriber is where the whole recursive notification chain ends because it only has a call to setLeft() and no subsequent call to onNext() like a regularly instantiated SimpleCell or ArithmeticCell object does.
 
Junilu Lacar
Sheriff
Posts: 15801
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:Why does your setLeft() method do something other than setting the left cell? Why are you doing arithmetic in the same method?


I take it you're referring to line 12:

Line 12 is necessary because if c3 is a subscriber of c1 and c4 is a subscriber of c3, when c1 changes then it has to notify c3 which in turn has to notify c4 of the its (c3's) change. The recursion ends when the subscriber chain ends.

Although I don't know if it's a proper recursion since it's really just a chain. The one thing you do have to watch for is accidentally creating a circular chain. If that happens, then you'd actually enter into an infinite indirect recursive loop so you have to track some kind of "visited" state if you want to guard against that kind of thing from happening.
 
Jonas Ramanauskas
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank You everyone for help! What I would do without you .
Really really big thanks to Junilu Lacar!

Campbell Ritchie wrote:Why does your setLeft() method do something other than setting the left cell? Why are you doing arithmetic in the same method?


It's small snippet of example code, to show what is publisher, subscriber. As I understood concept from that example, I could go on, but didn't want to. Because to understand concept is one thing, and I want to understand as much code implementation nuances as I can.

When I was learning lambdas/method references it was with functional interfaces(I now that here Publisher/Subscriber are functional too) like Consumer, Function and etc. Where it was like something like that : behaviour.accept(value), and for example in list.stream.map(Person::getName), or passing behaviour to parametrized methods, everything was pretty clear for me.
And in this case

Is clear too, because we add a3  object as a subscriber.  And when example was altered to a1.subscribe(a3::setLeft) , it became unclear to me, what the hell is hapening.
Thanks to Junilu Lacar now the flow is clear to me if ofcourse I understand it corectly:


Now if I am not mistaken somewhere, it's how it works. Seems kinda easy now, just needed good guidance. And thanks to you I got that .
Ofcourse now I have to play with it a little bit more, so that I "digest" this thing. Because it's a little bit complex, we create ArithmeticCell, then we subscribe it's method reference, not a concrete object like
a1.subscribe(c3) and etc. But now as this flow of the program is clear I think it will not be hard t settle everything in .  








 
Junilu Lacar
Sheriff
Posts: 15801
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Glad it helped. It takes a while to wrap your head around the syntax. I still get confused sometimes, too. There was one thread fairly recently in particular that still boggles my mind. Stephan has a really good handle on those things though as I'm sure a few others, too.

The main thing to remember is that lambdas and method references are "typeless" until you associate them to a functional interface. The same expression can take on different forms, depending on where you pass them or assign them. I think of them as "shape shifters" that take on the form of whatever it is they get attached to by the compiler. Here's a totally contrived example (you can also run it here: https://repl.it/@jlacar/ShapeShiftingLambdas)
 
Junilu Lacar
Sheriff
Posts: 15801
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just an aside, I've been studying Kotlin lately and I really like how lambdas work in that language. Here's a function I wrote to calculate quadratic roots (input guaranteed to have real roots, no imaginary roots):

Line 2 defines a lambda that encapsulates the quadratic equation formula. It is then used on line 3. And printing the result is easy, too:

And I'm just scratching the surface--there's so much more to this language to learn. And you can use everything in the standard Java library, too.
 
Jonas Ramanauskas
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank You very much! Great examples to strengthen understanding of functional programming.
 
Hot dog! An advertiser loves us THIS much:
Thread Boost feature
https://coderanch.com/t/674455/Thread-Boost-feature
    Bookmark Topic Watch Topic
  • New Topic