Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Predicate JavaDoc claims they are lambdas or closures #1495

Open
Chealer opened this issue Aug 24, 2023 · 20 comments
Open

Predicate JavaDoc claims they are lambdas or closures #1495

Chealer opened this issue Aug 24, 2023 · 20 comments

Comments

@Chealer
Copy link

Chealer commented Aug 24, 2023

The Predicate interface's description reads:

A Predicate is a lambda or closure with a boolean result. The method accept should be implemented to indicate the object passed to the method meets the criteria of this Predicate. A Predicate is also known as a Discriminator or Filter.

The first sentence is understandable but incorrect, just like it would be incorrect to claim that a Java String IS a list of letters between double quotes. A String can be instantiated by a list of letters between double quotes, but it represents (is) a sequence of characters. Like other functional interfaces, a class implementing org.eclipse.collections.api.block.predicate.Predicate can indeed be instantiated by lambda expressions or closures, but it doesn't have to, and an object implementing Predicate is neither a lambda expression nor a closure.

I am unsure what exactly an org.eclipse.collections.api.block.predicate.Predicate represents, but this could take example from the JDK Predicate's description:

Represents a predicate (boolean-valued function) of one argument.

By the way

I strongly discourage referring to a predicate as a "Filter". Filters and predicates are highly related concepts, but clearly different.

@mohrezaei
Copy link
Member

The word "lambda" is borrowed from lambda calculus, not from Java's syntactical definition of a "lambda expression".

It also fits the wikipedia definition of a closure fairly well: "Operationally, a closure is a record storing a function[a] together with an environment.["

@Chealer
Copy link
Author

Chealer commented Aug 25, 2023

Thanks @mohrezaei but I do not get your point. Suppose that:
Predicate<Integer> intTester = org.eclipse.collections.impl.block.factory.Predicates.greaterThan(50);

Do you agree that intTester is "a Predicate"?

And if so, are you claiming that intTester is a lambda or a closure?

@mohrezaei
Copy link
Member

mohrezaei commented Aug 25, 2023

Yes, in the general sense of lambda/closure, it is. See the wikipedia articles. lambda/closure has a long history far longer and richer than the meager implementation in Java.

@Chealer
Copy link
Author

Chealer commented Aug 25, 2023

Thanks @mohrezaei

Do you agree that BooleanPredicates.ALWAYS_TRUE is "a Predicate"?

@mohrezaei
Copy link
Member

Sure. It's also an example of a constant function; it's even explicitly mentioned in the lambda calculus article: "Further, ( λ x . y ) represents the constant function x ↦ y, the function that always returns y, no matter the input."

@Chealer
Copy link
Author

Chealer commented Aug 25, 2023

Thanks @mohrezaei

Yes, in the general sense of lambda/closure, it is. See the wikipedia articles. lambda/closure has a long history far longer and richer than the meager implementation in Java.

Are you using "lambda" and "closure" as synonymous terms?

@mohrezaei
Copy link
Member

They are very closely related concepts. They are often mentioned together (e.g. from C++, just to broaden this a bit: "In C++11 and later, a lambda expression—often called a lambda—is a convenient way of defining an anonymous function object (a closure) right at the location where it's invoked or passed as an argument to a function.")

If you're interested in the colloquial usage of the terms, read the first answer here. If you're interested in the historically accurate definition, read the second answer.

@Chealer
Copy link
Author

Chealer commented Aug 25, 2023

Thanks @mohrezaei , that question is interesting, and there are definitely multiple senses for these terms.

Is BooleanPredicates.ALWAYS_TRUE a "closure" (according to the way you personally define that term)?

@mohrezaei
Copy link
Member

ALWAYS_TRUE is a "closed" expression (as in, it doesn't require any more context from its environment). In that sense, it's the simplest possible "closure" of a lambda expression -- one with a empty environment. (simply put, "yes", the same way an empty set is still a set, even if it's axiomatically so).

@Chealer
Copy link
Author

Chealer commented Aug 26, 2023

Thank you @mohrezaei I think the confusion is much clearer now.

So, I do agree that BooleanPredicates.ALWAYS_TRUE can be represented by a "closed" lambda expression. So it would be correct to describe "a Predicate" as something which can be represented by "a lambda". There is undeniably a relationship between the concepts of lambda expressions and predicates.

The problem is the current description claims:

A Predicate IS a lambda or closure [...].

To give a perhaps clearer analogy, while many would agree that the string "10" is ten, that is technically incorrect. Even though the sequence of the digit 1 followed by the digit 0 can represent ten, that is only a representation, which is only valid in the Indo-Arabic numeral system. In different systems, "10" could represent two, or even sixteen.

One way to convince oneself would be to imagine that the Indo-Arabic system and Arabic numerals would disappear. Would the number 10―the concept itself―disappear? No; ten is not "10", and it could still be represented as "X". And even before Roman numerals, the quantity ten existed.

To go back to our topic, while BooleanPredicates.ALWAYS_TRUE can be instantiated using a lambda expression, it is not one. To clarify, I am not against referring to lambda expressions in Predicate's description, as long as it's done properly. It would surely even help to add such an example. As for closures, the story is different, given how misunderstood and ambiguous the term is. I recommend avoiding that term, but here too, providing an example of instantiation through an anonymous function would be good.

@mohrezaei
Copy link
Member

To me, it doesn't matter how it was instantiated. What matters is how it behaves.

Does it take a parameter and return a result? Yub, it sure is a lambda.
Can it hold an environment it interacts with? Definitely, so it's a closure.

If you want it in formal terms, any instance of a single function Java interface is a lambda or closure.

I'm not sure what to make of your string example. It seems to hold the same sort of confusion about what something is (its true essence) and what it looks like (the characters somebody typed in). If there was a programming language where the literal "10" (with quotes and all), behaved like this:

(== true (== "17" (+ "10" "7")))

would it not be ten? A Java string "10" doesn't do that. it's not ten. In the hypothetical language above, it behaves like ten; it is therefore ten. BTW, it's not about numerals. It's about the operations defined on the integer ring Z (or if you want to get super technical, the finite group represented by two's complement modular math).

In case it's still not clear: what Java labels as a lambda expression is just syntax. I don't care about syntax.

@Chealer
Copy link
Author

Chealer commented Aug 27, 2023

Hi @mohrezaei

To me, it doesn't matter how it was instantiated. What matters is how it behaves.

That's exactly my point.

Does it take a parameter and return a result? Yub, it sure is a lambda. Can it hold an environment it interacts with? Definitely, so it's a closure.

If you want it in formal terms, any instance of a single function Java interface is a lambda or closure.

Ah, sorry, I had misunderstood, but thank you, this is an excellent characterization of this confusion, which is rather semantic.

There is lots of jargon used in IT, but properly speaking, a "lambda" in an expression. A function (just like a class) is not an expression.

As for "closure", the term is much more ambiguous. If we take the BooleanPredicates.ALWAYS_TRUE as example, it does not satisfy the definitions from the Stack Overflow answers you referred to, for example. And even if it does satisfy some jargon's definition, we should avoid it as the term has no standard definition in EC's context. Using an ambiguous term which entails such complexity unqualified would be more confusing than helpful.

I'm not sure what to make of your string example. It seems to hold the same sort of confusion about what something is (its true essence) and what it looks like (the characters somebody typed in). If there was a programming language where the literal "10" (with quotes and all), behaved like this:

(== true (== "17" (+ "10" "7")))

would it not be ten? A Java string "10" doesn't do that. it's not ten. In the hypothetical language above, it behaves like ten; it is therefore ten. BTW, it's not about numerals. It's about the operations defined on the integer ring Z (or if you want to get super technical, the finite group represented by two's complement modular math).

Just to clarify, the analogy was with a mathematical concept, not with Java.

In case it's still not clear: what Java labels as a lambda expression is just syntax. I don't care about syntax.

Technically, a lambda expression is an expression. For example:

( λ x . x )

In the Java world, a lambda expression remains an expression, albeit one complying with a different syntax. For example, the following is a lambda expression which would correspond to the identify function in Java terminology:

(x) -> x

A (Java) lambda expression which could represent BooleanPredicates.ALWAYS_TRUE would be:

(x) -> true

@mohrezaei
Copy link
Member

but properly speaking, a "lambda" in an expression.

Source? It seems rather contradictory on its face. A "lambda expression" is an expression. Why would people go around using "lambda expression", "lambda term" (which is also an expression) and "lambda calculus" (which is not an expression), if lambda simply meant "lambda expression"???

I don't know how long you've been coding and how many languages you've been exposed to, but using the word "lambda" to refer to functions that can be passed around as arguments to other functions is a very typical usage of that word 1,2,3. Is it really that far a stretch to refer to the thing a lambda expression creates as a lambda?

The purpose of the original sentence in the documentation is to give context. That assumes some shared notions. Clearly, "lambda" and "closure" are not part of your programming notions. I'm reasonably sure I didn't write that sentence, but it succinctly expresses the role a Predicate plays in the bigger scheme, for people who're used to those words.

@BrijeshPatra
Copy link

Hello @Chealer I successfully improved the documentation of the Predicate class and made the changes please review my Pull request once. Hope I will hear back from you soon. PR: #1497
Thank you

@Chealer
Copy link
Author

Chealer commented Sep 8, 2023

but properly speaking, a "lambda" in an expression.

Source?

The English Wiktionary?

It seems rather contradictory on its face. A "lambda expression" is an expression.

Right, that is my point: What current documentation means by "a lambda" (a lambda expression) is an expression.

Why would people go around using "lambda expression", "lambda term" (which is also an expression) and "lambda calculus" (which is not an expression), if lambda simply meant "lambda expression"???

There are very few people who know of multiple "lambda calculuses". Using "a lambda" meaning "a lambda calculus" would be cryptic. Obviously, nobody is saying that "lambda" simply means "lambda expression". I was assuming that "a lambda" meant a lambda expression since the noun "lambda" has no other common sense in the domain... but if you think that's incorrect, by all means tell us what you think it meant!

I don't know how long you've been coding and how many languages you've been exposed to

Neither do I ;-)

, but using the word "lambda" to refer to functions that can be passed around as arguments to other functions is a very typical usage of that word 1,2,3.

The Devil is in the details; if you take for example the last reference, it doesn't actually refer to functions by the term "lambda" (it only discusses "lambda expressions" and "lambda functions").

Is it really that far a stretch to refer to the thing a lambda expression creates as a lambda?

Well, if my mother had asked me 20 years ago to "fix her Internet", I would not have alerted ICANN that the Internet was broken before making sure that her desktop still had a shortcut to launch Internet Explorer. That is not to say that calling a browser or a browser installation "an Internet" is necessarily acceptable.

As indicated right from the start, the sentence is (at least for me) understandable, but that doesn't mean it's acceptable. Context matters, and the official description of a core class of a foundational library should warrant minimal exactitude.

The purpose of the original sentence in the documentation is to give context. That assumes some shared notions. Clearly, "lambda" and "closure" are not part of your programming notions. I'm reasonably sure I didn't write that sentence, but it succinctly expresses the role a Predicate plays in the bigger scheme, for people who're used to those words.

I'm afraid what's clearer is that reading or communication are not part of your strengths. As I already wrote, I am not against keeping the word "lambda" in the description. As long as it's used properly, it might even help if it doesn't mislead readers.

@Chealer
Copy link
Author

Chealer commented Sep 8, 2023

Hello @Chealer I successfully improved the documentation of the Predicate class and made the changes please review my Pull request once. Hope I will hear back from you soon. PR: #1497 Thank you

Thank you @BrijeshPatra
Your proposal solved the issue(s) reported here and even goes beyond, and I hope my remarks will be useful. In case you would like to go even further, the reason why I consulted this documentation is that I wondered how EC's Predicate differed from the JDK's Predicate.

@mohrezaei
Copy link
Member

if you take for example the last reference, it doesn't actually refer to functions by the term "lambda" (it only discusses "lambda expressions" and "lambda functions").

Ok, let's start there. Let's agree that there are two things: "lambda expression" and "lambda function". The wiktionary you referenced lists them as such.

what's clearer is that reading or communication are not part of your strengths.

Funny you should say that, because it's obvious you didn't see the clear usage of lambda-as-function-not-expressin in the first two links. Just so this point is a bit more clear, here are 3 more such references:

Lambda comes from the Lambda Calculus and refers to anonymous functions in programming.

"Lambdas" are a shortened name for anonymous functions

lambda is a function

What current documentation means by "a lambda" (a lambda expression) is an expression.

Incorrect. What the documentation currently means by lambda is a "lambda function". The defining feature of Predicate is the accept function, which has nothing to do with the particular syntax (expression) that was used to define it.

The wiktionary you referenced also includes "lambda function" as a derived term for lambda, and interestingly, that page refers to a "closure" as its hyponym. A reader seeing "a lambda or closure" deducing that the first term in that phrase refers to a lambda-expression instead of a lambda-function clearly has never read the wiktionary.

That is not to say that calling a browser or a browser installation "an Internet" is necessarily acceptable.

Seriously? You're equating calling a "lambda function" a "lambda" the same as calling a "browser" the "internet"?
Your communication skills are so super that you couldn't possibly be caught in a hyperbolic straw man argument.

@Chealer
Copy link
Author

Chealer commented Sep 9, 2023

Hi @mohrezaei ,

what's clearer is that reading or communication are not part of your strengths.

Funny you should say that, because it's obvious you didn't see the clear usage of lambda-as-function-not-expressin in the first two links. Just so this point is a bit more clear, here are 3 more such references:

Lambda comes from the Lambda Calculus and refers to anonymous functions in programming.

"Lambdas" are a shortened name for anonymous functions

lambda is a function

Reading ability doesn't require a reader to accept everything he reads from random sources on the Internets. For example, to take your first reference, it's a confused piece whose author doesn't even understand what a code block is (and sorry if you were hoping to get it fixed, but it's so outdated it's still unaware of "Java lambda expressions").

What current documentation means by "a lambda" (a lambda expression) is an expression.

Incorrect. What the documentation currently means by lambda is a "lambda function". The defining feature of Predicate is the accept function, which has nothing to do with the particular syntax (expression) that was used to define it.

The wiktionary you referenced also includes "lambda function" as a derived term for lambda, and interestingly, that page refers to a "closure" as its hyponym. A reader seeing "a lambda or closure" deducing that the first term in that phrase refers to a lambda-expression instead of a lambda-function clearly has never read the wiktionary.

And that will be the case of 100% of EC users. Not only is Wiktionary indeed unreliable, but it's also huge. Even if you only meant the English Wiktionary, it's already got millions of entries.

Nevertheless, you are basically right. Technically, Java has no first-class functions, but one could argue that an object like one implementing Predicate is a function. The least incorrect way to read the description is to interpret "a lambda" as a functional object instantiated using a (Java) lambda expression, which we could call an anonymous function (or colloquially, a "lambda function" indeed).

That is not to say that calling a browser or a browser installation "an Internet" is necessarily acceptable.

Seriously? You're equating calling a "lambda function" a "lambda" the same as calling a "browser" the "internet"? Your communication skills are so super that you couldn't possibly be caught in a hyperbolic straw man argument.

No, what I provided was just an analogy to distinguish understandability from correctness, clarity and acceptability. My point is that even if a description is understandable by us experts, it can be misleading and inappropriate in a given context.

When my mother told me about her problems with "the Internet" 20 years ago, her voice tone indicated she wasn't sure about the word choice, and I could quickly validate my understanding if I wasn't sure how to interpret. Unfortunately, EC readers will have have much more difficulty determining if the author of Predicate's description knew what it was talking about, even more to find who that was, and it would take them even longer to validate their understanding, admitting that contributor remains alive and willing to reply.

My point was that as I wrote, context matters, and the JavaDoc of a core class of a foundational library with potential to be used by hundreds of thousands of developers should warrant minimal exactitude. In that context, calling a functional object a "lambda" just because it can serve as a callback is not merely unclear/incorrect―it's unacceptable.

@motlin
Copy link
Contributor

motlin commented Sep 9, 2023

I feel like the conversation may be most productive if we focus here:

the reason why I consulted this documentation is that I wondered how EC's Predicate differed from the JDK's Predicate

We could answer this in our Javadoc and clarify why our Predicate exists. Off the cuff:

  1. There's basically no difference between them, except ours is Serializable.
  2. Ours existed first. If the JDK one existed at the time, we likely would have never created ours. We retrofitted our Predicate to extend the JDK Predicate for maximum compatibility.

Ours is not deprecated and we don't plan on getting rid of it. Keeping it doesn't seem to create a lot of problems, and getting rid of it may break code for some long-time users.

@Chealer
Copy link
Author

Chealer commented Sep 11, 2023

Thank you very much @motlin

That makes sense. I believe every element of your reply is interesting and worth documenting, so I recommend that the Javadoc provide at least those elements. However, it should be evaluated whether Predicate's Javadoc should document that directly or indirectly, since presumably, the same reasons also apply to Predicate2/BiPredicate. Perhaps the reasons can be indicated in Predicate's Javadoc and Predicate2 can mention that the reasons are explained in Predicate's.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants