Is there a way to compare lambdas? - java

Say I have a List of object which were defined using lambda expressions (closures). Is there a way to inspect them so they can be compared?
The code I am most interested in is
List<Strategy> strategies = getStrategies();
Strategy a = (Strategy) this::a;
if (strategies.contains(a)) { // ...
The full code is
import java.util.Arrays;
import java.util.List;
public class ClosureEqualsMain {
interface Strategy {
void invoke(/*args*/);
default boolean equals(Object o) { // doesn't compile
return Closures.equals(this, o);
}
}
public void a() { }
public void b() { }
public void c() { }
public List<Strategy> getStrategies() {
return Arrays.asList(this::a, this::b, this::c);
}
private void testStrategies() {
List<Strategy> strategies = getStrategies();
System.out.println(strategies);
Strategy a = (Strategy) this::a;
// prints false
System.out.println("strategies.contains(this::a) is " + strategies.contains(a));
}
public static void main(String... ignored) {
new ClosureEqualsMain().testStrategies();
}
enum Closures {;
public static <Closure> boolean equals(Closure c1, Closure c2) {
// This doesn't compare the contents
// like others immutables e.g. String
return c1.equals(c2);
}
public static <Closure> int hashCode(Closure c) {
return // a hashCode which can detect duplicates for a Set<Strategy>
}
public static <Closure> String asString(Closure c) {
return // something better than Object.toString();
}
}
public String toString() {
return "my-ClosureEqualsMain";
}
}
It would appear the only solution is to define each lambda as a field and only use those fields. If you want to print out the method called, you are better off using Method. Is there a better way with lambda expressions?
Also, is it possible to print a lambda and get something human readable? If you print this::a instead of
ClosureEqualsMain$$Lambda$1/821270929#3f99bd52
get something like
ClosureEqualsMain.a()
or even use this.toString and the method.
my-ClosureEqualsMain.a();

This question could be interpreted relative to the specification or the implementation. Obviously, implementations could change, but you might be willing to rewrite your code when that happens, so I'll answer at both.
It also depends on what you want to do. Are you looking to optimize, or are you looking for ironclad guarantees that two instances are (or are not) the same function? (If the latter, you're going to find yourself at odds with computational physics, in that even problems as simple as asking whether two functions compute the same thing are undecidable.)
From a specification perspective, the language spec promises only that the result of evaluating (not invoking) a lambda expression is an instance of a class implementing the target functional interface. It makes no promises about the identity, or degree of aliasing, of the result. This is by design, to give implementations maximal flexibility to offer better performance (this is how lambdas can be faster than inner classes; we're not tied to the "must create unique instance" constraint that inner classes are.)
So basically, the spec doesn't give you much, except obviously that two lambdas that are reference-equal (==) are going to compute the same function.
From an implementation perspective, you can conclude a little more. There is (currently, may change) a 1:1 relationship between the synthetic classes that implement lambdas, and the capture sites in the program. So two separate bits of code that capture "x -> x + 1" may well be mapped to different classes. But if you evaluate the same lambda at the same capture site, and that lambda is non-capturing, you get the same instance, which can be compared with reference equality.
If your lambdas are serializable, they'll give up their state more easily, in exchange for sacrificing some performance and security (no free lunch.)
One area where it might be practical to tweak the definition of equality is with method references because this would enable them to be used as listeners and be properly unregistered. This is under consideration.
I think what you're trying to get to is: if two lambdas are converted to the same functional interface, are represented by the same behavior function, and have identical captured args, they're the same
Unfortunately, this is both hard to do (for non-serializable lambdas, you can't get at all the components of that) and not enough (because two separately compiled files could convert the same lambda to the same functional interface type, and you wouldn't be able to tell.)
The EG discussed whether to expose enough information to be able to make these judgments, as well as discussing whether lambdas should implement more selective equals/hashCode or more descriptive toString. The conclusion was that we were not willing to pay anything in performance cost to make this information available to the caller (bad tradeoff, punishing 99.99% of users for something that benefits .01%).
A definitive conclusion on toString was not reached but left open to be revisited in the future. However, there were some good arguments made on both sides on this issue; this is not a slam-dunk.

To compare labmdas I usually let the interface extend Serializable and then compare the serialized bytes. Not very nice but works for the most cases.

I don't see a possibility, to get those informations from the closure itself.
The closures doesn't provide state.
But you can use Java-Reflection, if you want to inspect and compare the methods.
Of course that is not a very beautiful solution, because of the performance and the exceptions, which are to catch. But this way you get those meta-informations.

Related

List of lambda suppliers, and equality [duplicate]

Say I have a List of object which were defined using lambda expressions (closures). Is there a way to inspect them so they can be compared?
The code I am most interested in is
List<Strategy> strategies = getStrategies();
Strategy a = (Strategy) this::a;
if (strategies.contains(a)) { // ...
The full code is
import java.util.Arrays;
import java.util.List;
public class ClosureEqualsMain {
interface Strategy {
void invoke(/*args*/);
default boolean equals(Object o) { // doesn't compile
return Closures.equals(this, o);
}
}
public void a() { }
public void b() { }
public void c() { }
public List<Strategy> getStrategies() {
return Arrays.asList(this::a, this::b, this::c);
}
private void testStrategies() {
List<Strategy> strategies = getStrategies();
System.out.println(strategies);
Strategy a = (Strategy) this::a;
// prints false
System.out.println("strategies.contains(this::a) is " + strategies.contains(a));
}
public static void main(String... ignored) {
new ClosureEqualsMain().testStrategies();
}
enum Closures {;
public static <Closure> boolean equals(Closure c1, Closure c2) {
// This doesn't compare the contents
// like others immutables e.g. String
return c1.equals(c2);
}
public static <Closure> int hashCode(Closure c) {
return // a hashCode which can detect duplicates for a Set<Strategy>
}
public static <Closure> String asString(Closure c) {
return // something better than Object.toString();
}
}
public String toString() {
return "my-ClosureEqualsMain";
}
}
It would appear the only solution is to define each lambda as a field and only use those fields. If you want to print out the method called, you are better off using Method. Is there a better way with lambda expressions?
Also, is it possible to print a lambda and get something human readable? If you print this::a instead of
ClosureEqualsMain$$Lambda$1/821270929#3f99bd52
get something like
ClosureEqualsMain.a()
or even use this.toString and the method.
my-ClosureEqualsMain.a();
This question could be interpreted relative to the specification or the implementation. Obviously, implementations could change, but you might be willing to rewrite your code when that happens, so I'll answer at both.
It also depends on what you want to do. Are you looking to optimize, or are you looking for ironclad guarantees that two instances are (or are not) the same function? (If the latter, you're going to find yourself at odds with computational physics, in that even problems as simple as asking whether two functions compute the same thing are undecidable.)
From a specification perspective, the language spec promises only that the result of evaluating (not invoking) a lambda expression is an instance of a class implementing the target functional interface. It makes no promises about the identity, or degree of aliasing, of the result. This is by design, to give implementations maximal flexibility to offer better performance (this is how lambdas can be faster than inner classes; we're not tied to the "must create unique instance" constraint that inner classes are.)
So basically, the spec doesn't give you much, except obviously that two lambdas that are reference-equal (==) are going to compute the same function.
From an implementation perspective, you can conclude a little more. There is (currently, may change) a 1:1 relationship between the synthetic classes that implement lambdas, and the capture sites in the program. So two separate bits of code that capture "x -> x + 1" may well be mapped to different classes. But if you evaluate the same lambda at the same capture site, and that lambda is non-capturing, you get the same instance, which can be compared with reference equality.
If your lambdas are serializable, they'll give up their state more easily, in exchange for sacrificing some performance and security (no free lunch.)
One area where it might be practical to tweak the definition of equality is with method references because this would enable them to be used as listeners and be properly unregistered. This is under consideration.
I think what you're trying to get to is: if two lambdas are converted to the same functional interface, are represented by the same behavior function, and have identical captured args, they're the same
Unfortunately, this is both hard to do (for non-serializable lambdas, you can't get at all the components of that) and not enough (because two separately compiled files could convert the same lambda to the same functional interface type, and you wouldn't be able to tell.)
The EG discussed whether to expose enough information to be able to make these judgments, as well as discussing whether lambdas should implement more selective equals/hashCode or more descriptive toString. The conclusion was that we were not willing to pay anything in performance cost to make this information available to the caller (bad tradeoff, punishing 99.99% of users for something that benefits .01%).
A definitive conclusion on toString was not reached but left open to be revisited in the future. However, there were some good arguments made on both sides on this issue; this is not a slam-dunk.
To compare labmdas I usually let the interface extend Serializable and then compare the serialized bytes. Not very nice but works for the most cases.
I don't see a possibility, to get those informations from the closure itself.
The closures doesn't provide state.
But you can use Java-Reflection, if you want to inspect and compare the methods.
Of course that is not a very beautiful solution, because of the performance and the exceptions, which are to catch. But this way you get those meta-informations.

Method references to static methods or static methods which return lambdas

While developing I always have to rewrite the same lambda expression over and over again which is quite redundant and most of the cases the code formatting policy imposed by my company does not help. So I moved these common lambdas to a utility class as static methods and use them as method references. The best example I have is the Throwing merger used in conjunction with java.util.stream.Collectors.toMap(Function, Function, BinaryOperator, Supplier).
Always having to write (a,b) -> {throw new IllegalArgumentException("Some message");}; just because I want to use a custom map implementation is a lot of hassle.
//First Form
public static <E> E throwingMerger(E k1, E k2) {
throw new IllegalArgumentException("Duplicate key " + k1 + " not allowed!");
}
//Given a list of Car objects with proper getters
Map<String,Car> numberPlateToCar=cars.stream()//
.collect(toMap(Car::getNumberPlate,identity(),StreamUtils::throwingMerger,LinkedHasMap::new))
//Second Form
public static <E> BinaryOperator<E> throwingMerger() {
return (k1, k2) -> {
throw new IllegalArgumentException("Duplicate key " + k1 + " not allowed!");
};
}
Map<String,Car> numberPlateToCar=cars.stream()//
.collect(toMap(Car::getNumberPlate,identity(),StreamUtils.throwingMerger(),LinkedHasMap::new))
My questions are the following:
Which of the above is the correct approach and why?
Does either one of them offer a performance advantage or compromises performance?
Neither variant is more correct than the other.
Further, there is no significant performance difference, as the relevant bytecode is even identical. In either case, there will be a method holding a throw statement in your class and an instance of a runtime generated class which will invoke that method.
Note that you can find both patterns within the JDK itself.
Function.identity() and Map.Entry.comparingByKey() are examples of factory methods containing a lambda expression
Double::sum, Objects::isNull, or Objects::nonNull are examples of method references to target methods solely existing for the purpose of being referenced that way
Generally, if there are also use cases for invoking the methods directly, it’s preferable to provide them as API methods, which may also be referenced by method references, e.g. Integer::compare, Objects::requireNonNull, or Math::max.
On the other hand, providing a factory method makes the method reference an implementation detail that you can change when there is a reason to do so. E.g., did you know that Comparator.naturalOrder() is not implemented as T::compareTo? Most of the time, you don’t need to know.
Of course, factory methods taking additional parameters can’t be replaced by method references at all; sometimes, you want the parameterless methods of a class to be symmetric to those taking parameters.
There is only a tiny difference in memory consumption. Given the current implementation, every occurrence of, e.g. Objects::isNull, will cause the creation of a runtime class and an instance, which will then be reused for the particular code location. In contrast, the implementation within Function.identity() makes only one code location, hence, one runtime class and instance. See also this answer.
But it must be emphasized that this is specific to a particular implementation, as the strategy is implemented by the JRE, further, we’re talking about a finite, rather small number of code locations and hence, objects.
By the way, these approaches are not contradicting. You could even have both:
// for calling directly
public static <E> E alwaysThrow(E k1, E k2) {
// by the way, k1 is not the key, see https://stackoverflow.com/a/45210944/2711488
throw new IllegalArgumentException("Duplicate key " + k1 + " not allowed!");
}
// when needing a shared BinaryOperator
public static <E> BinaryOperator<E> throwingMerger() {
return ContainingClass::alwaysThrow;
}
Note that there’s another point to consider; the factory method always returns a materialized instance of a particular interface, i.e. BinaryOperator. For methods that need to be bound to different interfaces, depending on the context, you need method references at these places anyway. That’s why you can write
DoubleBinaryOperator sum1 = Double::sum;
BinaryOperator<Double> sum2 = Double::sum;
BiFunction<Integer,Integer,Double> sum3 = Double::sum;
which would not be possible if there was only a factory method returning a DoubleBinaryOperator.
EDIT: Ignore my remarks about avoiding unnecessary allocations, see Holgers answer as to why.
There won't be a noticable performance difference between the two - the first variant is avoiding unnecessary allocations though. I would prefer the method reference as the function does not capture any value and thus does not need a lambda in this context. Compared to creating the IllegalArgumentException, which has to fill its stacktrace before being thrown(which is quite expensive), the performance difference is totally negligible.
Remember: this is more about readability and communicating what your code does than about performance. If you ever hit a performance wall because of this kind of code lambdas and streams just aren't the way to go as they are a pretty elaborate abstraction with many indirections.

Check whether method is overwritten in Java

I'd like to implement a method that compares two Objects of my interface Task. Since there will only be a strict partial ordering on Task, partialCompareTo should return null if and only if the two objects are incomparable.
If you are confused by the concept of a strict partial ordering, check this out:
https://en.wikipedia.org/wiki/Partially_ordered_set
Motivation: Some tasks will have the constraint that they have to be done before or after another task. This is then used to topological sort the tasks, i.e. arrange them in a way that all constraints are met.
It should have the following property, for any instances of Task a and b:
if a.partialCompareTo(b) != null then sgn(a.partialCompareTo(b)) = -sgn(b.partialCompareTo(a))
if a.partialCompareTo(b) = null then b.partialCompareTo(a) = null
Note: I can't use the interface Comparable of the standard library since there will be no total ordering on Task: compareTo in Comparable returns int, so there is no way for an adequate result if two objects are incomparable. In particular there will be implementations of Task, where instances of that implementations are never comparable to each other (but might be comparable to instances of other subclasses of Task, which override partialCompareTo).
The idea is to use the partialCompareTo method of the argument if it overrides the method specified in the class Task.
The following approach is actually more of a joke than an actual attempt, since every time two not comparable objects are compared we get an StackOverflowError (which is caught, but anyway this is not feasible):
public class Task implements TopologicalComparable<Task> {
/*
* other code
*/
#Override
public Integer partialCompareTo(Task other) {
Integer result;
try {
result = - other.partialCompareTo(this);
} catch (StackOverflowError | NullPointerException e) {
return null;
}
return null;
}
}
The following implementation is clearly better, but it has the downside, that one always has to override the helper method overridesDefaultPartialCompareTo:
public class Task implements TopologicalComparable<Task> {
/*
* other code
*/
#Override
public Integer partialCompareTo(Task other) {
if (other.overridesDefaultPCompareTo()) {
Integer revComp = other.overridesDefaultPartialCompareTo(this);
if (revComp != null) {
return - revComp;
}
}
return null;
}
public default boolean overridesDefaultPartialCompareTo() {
return false;
}
}
Is there a way to ask, whether the method is overwritten in code?
Or is there an alternative approach to solve my problem?
when you compare things you should using something with a comparable interface as recommended by duffymo. To go into detail, you should be keeping your items in an ArrayList then overwriting the compare method. I am not sure why you have pCompare, but I am going to assume you do not understand inheritance and polymorphism. Instead of changing the name of your compare you should be using extends, here are documents about Inheritance please read them. It looks like your syntax is good, but your understanding of how java code is written is not good. So how should you do this?
Lets start with the first thing I think is wrong (feel free to correct me guys if this is incorrect) you are not using an interface correctly. An interface is good for declaring global variables, helping you implement design patterns, and ect. Most people say it is a contract of behavior. In plain English use an interface to help you get past Multiple Inheritance. I have no idea why you are using one and what you plan to do with it, but I have never added a method to an interface that is implemented.
The next thing is you renaming your pCompareTo I have never done that and I have helped make some pretty large programs. I really don't think it is good programming. It should be in a class. The class that uses it is fine, though not always, and I am having a hard time thinking of how it can be explained so you might have to do some research.
When you get rid of the interface, put compareTo() in the correct place (do not change it to pCompareTo() that is bad programming) you override it like you did, and specify what goes into it. Pay attention this is important Usually when you override a compare to you have the compareTo Method you have it return -1 if the object coming in is smaller than what it is being compared to, 1 if it is larger or 0 if it is the same size. In the case where you just want to check if it is equal then you can simply check if they are equal like for string you do
string1.equals(string2)
and it will return 1 if true or 0 if false.
#Override
public default Integer pCompareTo(Task other) {
Integer result;
try {
result = - other.pCompareTo(this);
} catch (StackOverflowError | NullPointerException e) {
return null;
}
return null;
}
Ok this is horribly wrong man, just horribly wrong. Your method is pCompareTo() right? You are calling it inside itself (that is called recursion and I would not recommend you using that right now). I do not know what you are comparing (also a you don't need a try catch here but can if you want to, a try catch is like a trap you set in your code that goes off if that particular area did not work correctly), but if they were integers you would do something like
#Override
public int compareTo(Integer other){
if (this < other) {
return 1;
}
if (this > other) {
return -1;
}
return 0;
Please see override explanation. It is just to much for me to explain how it works to you in this already long post. Good luck, and my advice syntax in programming is not very important. Knowing how to program properly is much more important.
The revision is slightly better, and makes more sense. Thank you for that. Now to start off you need to understand that you are comparing objects. If you would like to write a compareTo() method you need to think about 'what am I comparing'. In order for you to write your method you need to explain to us what you are comparing, in your mind you might be comparing elements in a set. But in the programming world you are comparing ints, strings, or w/e you make them out of. So I ask you, what are you comparing? You should make a class of w/e you are comparing, say
class POsetElement{...
//make some sort of set element object
}
In this class you would want to implement comparable like so,
class POsetElement implements comparable{...
//make some sort of set element object...
//then make w/e other methods you need...
//now use compareTo() override
#override
compareTo(){
//make your custom method
}
}
Notice how I put the compareTo() method INSIDE the POsetElement class. Java is OOP. That means object oriented programming. You need to custom build objects. You need to make your own world,create your own objects. There is not way that I can explain all of this to you. Please put in some effort and learn more java programming. Also you need to understand I would say that these are some very basic things and once again I will reiterate that you need to read a bit on java basics. Good luck.

Why there is no BooleanConsumer in Java 8?

I'm afraid that this is somewhat a silly question.
Is there anybody can tell me why there is no BooleanConsumer opposite to BooleanSupplier?
Is there any reason other than "because simply there isn't"?
Should I create my own one? Or am I missing something else?
public interface BooleanConsumer {
void accept(boolean value);
default BooleanConsumer andThen(final BooleanConsumer after) {
return v -> {
accept(v);
after.accept(v);
}
}
}
Update
Where to use? I'm writing a library that uses much of consumers and suppliers. I successfully wrote a line with LongConsumer and I encountered a situation that expecting a consumer accepting a boolean value which is from a method result. Say Files.deleteIfExist?
IntConsumer and LongConsumer are needed to avoid the overhead autoboxing every value. It is much more efficent to be working on raw primitives.
However, for Boolean and Byte every possible object is cached so there is little reason to avoid using Consumer<Boolean> or Consumer<Byte>
As other answers indicate there is no great reason to avoid Consumer<Boolean>, but then there's no great reason to avoid Supplier<Boolean> either, so a different explanation is required for this.
A similar question is why can't you switch on a boolean value. The answer is that there's no need because you could always use if or if else.
A BooleanConsumer would really be nothing more than an if else construct because the accept() method for a BooleanConsumer could always be written in this form:
if (v) {
// Do something
} else {
// Do something else
}
If you needed to pass such code around as data, you could just pass a pair of Runnables representing "do something" and "do something else". In many cases, you would only need one of the Runnables because one of the two blocks above would be empty.
In the same way, there is no need for a BooleanPredicate because it would be nothing more than a pair of BooleanSuppliers and there is no need for a a BooleanFunction<R> because it would be nothing more than a pair of Supplier<R>s.
In contrast to this, it is not possible to break a BooleanSupplier into two simpler objects.
You can write your own BooleanConsumer, but in order to make it really useful, you would need to write your own BooleanStream, too. There is an IntStream, LongStream, and DoubleStream, but no "BooleanStream" (or "ShortStream", "FloatStream" etc). It seems that these primitives were judged not to be important enough.
You can always use Boolean objects instead of boolean primitives, and a Boolean Consumer to consume the values. Example code:
public class Main {
public static void main(String[] args) {
Consumer<Boolean> myConsumer = b -> System.out.println("b = " + b);
Stream.of("aa", "bb", "cc")
.map(Main::myBooleanFunction)
.forEach(myConsumer);
}
static boolean myBooleanFunction(String s) {
return s.startsWith("b");
}
}
myBooleanFunction returns a boolean, but using it in a map creates a stream of Booleans (because we are in the generic, non-primitive Stream. Again, we have mapToInt, mapToLong, mapToDouble to create an IntStream etc, but no mapToBoolean).
If you don't need stream support, you can still write and use a "BooleanConsumer" in order to provide a type for some behavior, put I would prefer to see a functional interface with a more specific and descriptive name.

set/get methods in C++

Java programmers and API seems to favor explicit set/get methods.
however I got the impression C++ community frowns upon such practice.
If it is so,is there a particular reason (besides more lines of code) why this is so?
on the other hand, why does Java community choose to use methods rather than direct access?
Thank you
A well designed class should ideally not have too many gets and sets. In my opinion, too many gets and sets are basically an indication of the fact that someone else (and potentially many of them) need my data to achieve their purpose. In that case, why does that data belong to me in the first place? This violates the basic principle of encapsulation (data + operations in one logical unit).
So, while there is no technical restriction and (in fact abundance of) 'set' and 'get' methods, I would say that you should pause and reinspect your design if you want too many of those 'get' and 'set' in your class interface used by too many other entities in your system.
There are occasions when getters/setters are appropriate but an abundance of getters/setters typically indicate that your design fails to achieve any higher level of abstraction.
Typically it's better (in regards to encapsulation) to exhibit higher level operations for your objects that does not make the implementation obvious to the user.
Some other possible reasons why it's not as common in C++ as in Java:
The Standard Library does not use it.
Bjarne Stroustrup expresses his dislike towards it (last paragraph):
I particularly dislike classes with a
lot of get and set functions. That is
often an indication that it shouldn't
have been a class in the first place.
It's just a data structure. And if it
really is a data structure, make it a
data structure.
The usual argument against get/set methods is that if you have both and they're just trivial return x; and x = y; then you haven't actually encapsulated anything at all; you may as well just make the member public which saves a whole lot of boilerplate code.
Obviously there are cases where they still make sense; if you need to do something special in them, or you need to use inheritance or, particularly, interfaces.
There is the advantage that if you implement getters/setters you can change their implementation later without having to alter code that uses them. I suppose the frowning on it you refer to is kind of a YAGNI thing that if there's no expectation of ever altering the functions that way, then there's little benefit to having them. In many cases you can just deal with the case of altering the implementation later anyway.
I wasn't aware that the C++ community frowned on them any more or less than the Java community; my impression is that they're rather less common in languages like Python, for example.
I think the reason the C++ community frowns on getters and setters is that C++ offers far better alternatives. For example:
template <class T>
class DefaultPredicate
{
public:
static bool CheckSetter (T value)
{
return true;
}
static void CheckGetter (T value)
{
}
};
template <class T, class Predicate = DefaultPredicate <T>>
class Property
{
public:
operator T ()
{
Predicate::CheckGetter (m_storage);
return m_storage;
}
Property <T, Predicate> &operator = (T rhs)
{
if (Predicate::CheckSetter (rhs))
{
m_storage = rhs;
}
return *this;
}
private:
T m_storage;
};
which can then be used like this:
class Test
{
public:
Property <int> TestData;
Property <int> MoreTestData;
};
int main ()
{
Test
test;
test.TestData = 42;
test.MoreTestData = 24;
int value = test.TestData;
bool check = test.TestData == test.MoreTestData;
}
Notice that I added a predicate parameter to the property class. With this, we can get creative, for example, a property to hold an integer colour channel value:
class NoErrorHandler
{
public:
static void SignalError (const char *const error)
{
}
};
class LogError
{
public:
static void SignalError (const char *const error)
{
std::cout << error << std::endl;
}
};
class Exception
{
public:
Exception (const char *const message) :
m_message (message)
{
}
operator const char *const ()
{
return m_message;
}
private:
const char
*const m_message;
};
class ThrowError
{
public:
static void SignalError (const char *const error)
{
throw new Exception (error);
}
};
template <class ErrorHandler = NoErrorHandler>
class RGBValuePredicate : public DefaultPredicate <int>
{
public:
static bool CheckSetter (int rhs)
{
bool
setter_ok = true;
if (rhs < 0 || rhs > 255)
{
ErrorHandler::SignalError ("RGB value out of range.");
setter_ok = false;
}
return setter_ok;
}
};
and it can be used like this:
class Test
{
public:
Property <int, RGBValuePredicate <> > RGBValue1;
Property <int, RGBValuePredicate <LogError> > RGBValue2;
Property <int, RGBValuePredicate <ThrowError> > RGBValue3;
};
int main ()
{
Test
test;
try
{
test.RGBValue1 = 4;
test.RGBValue2 = 5;
test.RGBValue3 = 6;
test.RGBValue1 = 400;
test.RGBValue2 = 500;
test.RGBValue3 = -6;
}
catch (Exception *error)
{
std::cout << "Exception: " << *error << std::endl;
}
}
Notice that I made the handling of bad values a template parameter as well.
Using this as a starting point, it can be extended in many different ways.
For example, allow the storage of the property to be different to the public type of the value - so the RGBValue above could use an unsigned char for storage but an int interface.
Another example is to change the predicate so that it can alter the setter value. In the RGBValue above this could be used to clamp values to the range 0 to 255 rather than generate an error.
Properties as a general language concept technically predate C++, e.g. in Smalltalk, but they weren't ever part of the standard. Getters and setters were a concept used in C++ when it was used for development of UI's, but truth be told, it's an expensive proposition to develop UI's in what is effectively a systems language. The general problem with getters and setters in C++ was that, since they weren't a standard, everybody had a different standard.
And in systems languages, where efficiency concerns are high, then it's just easier to make the variable itself public, although there's a lot of literature that frowns mightily on that practice. Often, you simply see richer exchanges of information between C++ object instances than simple items.
You'll probably get a lot of viewpoints in response to this question, but in general, C++ was meant to be C that did objects, making OOP accessable to developers that didn't know objects. It was hard enough to get virtuals and templates into the language, and I think that it's been kind of stagnant for a while.
Java differs because in the beginning, with what Java brought in areas like garbage collection, it was easier to promote the philosophy of robust encapsulation, i.e. external entities should keep their grubby little paws off of internal elements of a class.
I admit this is pretty much opinion - at this time I use C++ for highly optimized stuff like 3D graphics pipelines - I already have to manage all my object memory, so I'd take a dim view of fundamentally useless code that just serves to wrap storage access up in additional functions - that said, the basic performance capabilies of runtimes like the MSFT .net ILM make that a position that can be difficult to defend at times
Purely my 2c
There's nothing unusual about having explicit set/get methods in C++. I've seen it in plenty of C++, it can be very useful to not allow direct access to data members.
Check out this question for an explanation of why Java tends to prefer them and the reasons for C++ are the same. In short: it allows you to change the way data members are accessed without forcing client code (code that uses your code) to recompile. It also allows you to enforce a specific policy for how to access data and what to do when that data is accessed.
By mandating the use of set/get methods, one can implement useful side-effects in the getter/setter (for example, when the argument to get/set is an object).
I am surprised nobody has mentioned Java introspection and beans yet.
Using get.../set... naming convention combined with introspection allows all sorts of clever trickery with utility classes.
I personally feel that the "public" keyword should have been enough to trigger the bean magic but I am not Ray Gosling.
My take on this is that in C++ is a rather pointless exercise. You are adding at least six lines of code to test and maintain which perform no purpose and will for the most part be ignored by the compiler. It doesnt really protect your class from misuse and abuse unless you add a lot more coding.
I don't think the C++ community frowned on using getters and setters. They are almost always a good idea.
It has to do with the basics of object oriented programming - hiding the internals of an object from its users. The users of an object should not need to know (nor should they care) about the internals of an object.
It also gives you control over what is done whenever a user of your object tries to read/write to it. In effect, you expose an interface to the object's users. They have to use that interface and you control what happens when methods in that interface are called - the getters and setters would be part of the interface.
It just makes things easier when debugging. A typical scenario is when your object lands up in a weird state and you're debugging to find out how it got there. All you do is set breakpoints in your getters and setters and assuming all else is fine, you're able to see how your object gets to the weird state. If your object's users are all directly accessing its members, figuring out when your object's state changes becomes a lot harder (though not impossible)
I would argue that C++ needs getters/setters more than Java.
In Java, if you start with naked field access, and later you changed your mind, you want getter/setter instead, it is extremely easy to find all the usages of the field, and refactor them into getter/setter.
in C++, this is not that easy. The language is too complex, IDEs simply can't reliably do that.
so In C++, you better get it right the first time. In Java, you can be more adventurous.
There were gets/sets long before java. There are many reasons to use them, especially, if you have to recalculate sth. wenn a value changes. So the first big advantage is, that you can watch to value changes. But imho its bad to ALWAYS implement get and set-often a get is enough. Another point is, that class changes will directly affect your customers. You cant change member names without forcing to refactor the clients code with public members. Lets say, you have an object with a lenght and you change this member name...uh. With a getter, you just change you side of the code and the client can sleep well. Adding gets/Sets for members that should be hidden is of course nonsense.

Categories