Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Equality should either be the default object identity (for anything mutable), or should encompass the entire public state of the object. If two objects are "equal", calling a particular public method on them should return the same result.

If you're doing anything else that's absolutely insane, how do you even use your equality semantics in a way that makes sense?

If you're trying to model business logic like "these two things represent the same customer", that should absolutely not be equality, just write a comparator or something for the cases where you specifically want that instead of junking up equality and making your objects unusable in any other context

Adbot
ADBOT LOVES YOU

CPColin
Sep 9, 2003

Big ol' smile.
Back at a previous job, somebody decided long ago to make the hashcode of our database entities be the ID. Somebody then correctly noticed the problem of trying to hash an entity that hadn't been persisted into the database yet and, naturally, made hashcode throw a RuntimeException if the ID was zero. Then somebody decided an efficient way to implement equals() was simply to compare the two hashcodes.

So we had RuntimeExceptions, forever lurking.

Volguus
Mar 3, 2009

CPColin posted:

Back at a previous job, somebody decided long ago to make the hashcode of our database entities be the ID. Somebody then correctly noticed the problem of trying to hash an entity that hadn't been persisted into the database yet and, naturally, made hashcode throw a RuntimeException if the ID was zero. Then somebody decided an efficient way to implement equals() was simply to compare the two hashcodes.

So we had RuntimeExceptions, forever lurking.

Haha. I mean, yes, one can get stupid with this of course. It is important to correctly implement hashcode and equals (it's not rocket science, really, and this example is how to not do it). With that being said, if the ID is the only discriminator, the only problem that may arise is when trying to use the object in a Set or as a key in a Map. If you absolutely need to use 2 unsaved objects in a set (maybe some big import operation) then you should find some other discriminator, something that for that particular operation makes the objects unique. Unless that's all you do with the objects all the time: handle tons of them unpersisted in a Set or a Map, then by all means, use all the properties you have. Lombok baby all the way, it's not like it matters.

205b
Mar 25, 2007

Volguus posted:

Haha. I mean, yes, one can get stupid with this of course. It is important to correctly implement hashcode and equals (it's not rocket science, really, and this example is how to not do it). With that being said, if the ID is the only discriminator, the only problem that may arise is when trying to use the object in a Set or as a key in a Map. If you absolutely need to use 2 unsaved objects in a set (maybe some big import operation) then you should find some other discriminator, something that for that particular operation makes the objects unique. Unless that's all you do with the objects all the time: handle tons of them unpersisted in a Set or a Map, then by all means, use all the properties you have. Lombok baby all the way, it's not like it matters.

You can't use different hash/equality semantics with the same class in different contexts, though - everything has to use the same equals and hashCode methods. if you settle on any non-default hash/equality semantics that don't encompass all observable instance state, it's probably going to hamstring you or produce unintuitive behavior at some point in the future.

When you do need to compare instances based on specific properties (e.g. ID), it's easy and more clear to do that explicitly: entityA.equals(entityB) becomes entityA.getId().equals(entityB.getId()), and a Set<Entity> becomes a Map<Id, Entity>.

e: the map-keyed-by-ID approach also makes it a bit harder to accidentally mutate the contents of a hash table

205b fucked around with this message at 02:38 on Sep 9, 2019

Volguus
Mar 3, 2009

205b posted:

You can't use different hash/equality semantics with the same class in different contexts, though - everything has to use the same equals and hashCode methods. if you settle on any non-default hash/equality semantics that don't encompass all observable instance state, it's probably going to hamstring you or produce unintuitive behavior at some point in the future.

When you do need to compare instances based on specific properties (e.g. ID), it's easy and more clear to do that explicitly: entityA.equals(entityB) becomes entityA.getId().equals(entityB.getId()), and a Set<Entity> becomes a Map<Id, Entity>.

e: the map-keyed-by-ID approach also makes it a bit harder to accidentally mutate the contents of a hash table

What kind of unintuitive behaviour do you envision? I can envision a ton of very unintuitive behaviour when you do encompass all observable state: I change the name of a person, now it's suddenly no longer the same person? That is, and you know it, everyone knows it, false. It should replace the object with the same ID in the Set, it should be found by key in the Map because it is the same Person after all.
To use different hash/equality semantics in different contexts with the same class one could go the inheritance route. I've never done it since I've never needed it, but it one could have a CSVPerson extends Person, where, all state is present in the hash/equals for that particular operation, at that particular point in time. Sure, one can go stupid and abuse the poo poo out of it and make a mess, but hey, let's not pretend that anything has really stopped those people.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
If your thing is mutable you shouldn't be overriding equals/hashcode at all, because object identity is more important.

If you have two immutable objects that are mostly the same but the Name field is different then yes they absolutely should not compare equal, seriously what the gently caress?

If you need specialized comparisons in some special context then write a comparator that compares things that way, don't junk up your general equality semantics.

Everything you've described is an unmaintainable shitpile and I hope you don't really consider it to be best practice.

Volguus
Mar 3, 2009

Jabor posted:

If your thing is mutable you shouldn't be overriding equals/hashcode at all, because object identity is more important.

If you have two immutable objects that are mostly the same but the Name field is different then yes they absolutely should not compare equal, seriously what the gently caress?

If you need specialized comparisons in some special context then write a comparator that compares things that way, don't junk up your general equality semantics.

Everything you've described is an unmaintainable shitpile and I hope you don't really consider it to be best practice.

That's insane. :wtc:

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Volguus posted:

That's insane. :wtc:

Do you want to be more specific about which parts you disagree with?

If you're a novice looking for more information on how to handle equality semantics correctly, I'd recommend reading through Effective Java, which contains a wealth of information and best practices sourced from decades of real-world experience in large software projects.

e: actually, even if you're not a novice, reading Effective Java is probably still worthwhile. I just reread the section on equals/hashcode as a refresher.

Jabor fucked around with this message at 05:37 on Sep 9, 2019

RandomBlue
Dec 30, 2012

hay guys!


Biscuit Hider

Jabor posted:

If your thing is mutable you shouldn't be overriding equals/hashcode at all, because object identity is more important.

If you have two immutable objects that are mostly the same but the Name field is different then yes they absolutely should not compare equal, seriously what the gently caress?

If you need specialized comparisons in some special context then write a comparator that compares things that way, don't junk up your general equality semantics.

Everything you've described is an unmaintainable shitpile and I hope you don't really consider it to be best practice.

Agreed.

Volguus
Mar 3, 2009
Certainly, darling. One piece of advice though: speaking in absolutes, making blanket statements does not do you any favours.

Jabor posted:

If your thing is mutable you shouldn't be overriding equals/hashcode at all, because object identity is more important.
Let me guess: you jumped from "do not mutate your Map's key" to "don't override equals/hash on mutable objects" in some amazing leap of ... something? Better than Houdini. What the actual gently caress? Because not overriding hash/equals somehow magically prevents one from using said object as a key of a map? Or in a set? There are many things to consider when deciding if an object should receive a hash/equals and what exactly those should be and how should those behave. Mutability is not one of them.
One requirement (don't mutate) does not imply the other (do not provide hash/equals). This would be insane, it doesn't solve anything.

Jabor posted:

If you have two immutable objects that are mostly the same but the Name field is different then yes they absolutely should not compare equal, seriously what the gently caress?
Seriously, what in the actual gently caress? How can you come and say, without knowing of anything about the business logic, that if two objects have a different name field therefore they must be not equal? They may, then again they may not. In the example provided even, two Person objects most likely refer to real people. I don't know if you are aware, but humans change their names thought their lifetimes, some multiple times. They change their address, colour of their hair, even their sex. And yet, they are still the same person. Conversely, the opposite is true: if you have two person objects which have the same name, live at the same address, have the same hair colour and the same sex, it does not mean they are the same human being, it does not mean they are the same entity. Designing a system that is not able to handle this just puts you in a world of hurt, sooner or later.
Now, you can come and say, for a particular operation, for a particular business requirement, two person objects with fields X, Y and Z equal they shall be considered equal. The advantages outweigh the risks. That is fine. But you cannot come and make it a true statement for all operations, for all systems that handle people. That's just insane.

Jabor posted:

If you need specialized comparisons in some special context then write a comparator that compares things that way, don't junk up your general equality semantics.
Certainly. Don't compare the universe all the time. Do it when it makes sense. Use correct, proper keys for your objects and data structures, ones are are appropriate for the business logic, for whatever it is you're trying to solve.

Jabor posted:

Everything you've described is an unmaintainable shitpile and I hope you don't really consider it to be best practice.
It certainly may be. It is also light years ahead of whatever junk you're making/maintaining with blanket rules and sweeping statements. I certainly hope you do not behave like that in the real world and you do actually think before you write code. Going all "we work, don't think" is not way to go through life.

Sagacity
May 2, 2003
Hopefully my epitaph will be funnier than my custom title.

Volguus posted:

How can you come and say, without knowing of anything about the business logic, that if two objects have a different name field therefore they must be not equal? They may, then again they may not.
You can argue all you want, but equals/hashCode is not designed to handle object identity in the 'real world' sense. If an object is referring to the same person in the real world, but they have different hair color properties, equals/hashCode should reflect that.

Your point of view already falls apart if you have two sections of your application that treat equality differently. How would you implement equals/hashCode in that case?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Volguus posted:

Certainly, darling. One piece of advice though: speaking in absolutes, making blanket statements does not do you any favours.

Let me guess: you jumped from "do not mutate your Map's key" to "don't override equals/hash on mutable objects" in some amazing leap of ... something? Better than Houdini. What the actual gently caress? Because not overriding hash/equals somehow magically prevents one from using said object as a key of a map? Or in a set? There are many things to consider when deciding if an object should receive a hash/equals and what exactly those should be and how should those behave. Mutability is not one of them.
One requirement (don't mutate) does not imply the other (do not provide hash/equals). This would be insane, it doesn't solve anything.

Seriously, what in the actual gently caress? How can you come and say, without knowing of anything about the business logic, that if two objects have a different name field therefore they must be not equal? They may, then again they may not. In the example provided even, two Person objects most likely refer to real people. I don't know if you are aware, but humans change their names thought their lifetimes, some multiple times. They change their address, colour of their hair, even their sex. And yet, they are still the same person. Conversely, the opposite is true: if you have two person objects which have the same name, live at the same address, have the same hair colour and the same sex, it does not mean they are the same human being, it does not mean they are the same entity. Designing a system that is not able to handle this just puts you in a world of hurt, sooner or later.
Now, you can come and say, for a particular operation, for a particular business requirement, two person objects with fields X, Y and Z equal they shall be considered equal. The advantages outweigh the risks. That is fine. But you cannot come and make it a true statement for all operations, for all systems that handle people. That's just insane.

Certainly. Don't compare the universe all the time. Do it when it makes sense. Use correct, proper keys for your objects and data structures, ones are are appropriate for the business logic, for whatever it is you're trying to solve.

It certainly may be. It is also light years ahead of whatever junk you're making/maintaining with blanket rules and sweeping statements. I certainly hope you do not behave like that in the real world and you do actually think before you write code. Going all "we work, don't think" is not way to go through life.

This post is really funny, because you're the one who's been advocating encoding special business logic in your class's equals and hashcode methods, and I've just been saying "putting business logic in your equals method is dumb and unmaintainable, don't do that".

If it's an immutable value object, override equals and hashcode to define whether they're completely identical and interchangable. If it's not an immutable value object, stick with the default identity-based implementation, and write a separate Comparator to use in cases where you need to express a different kind of equivalence relation.

(Pro tip: You can use mutable objects as map keys just fine as long as you leave them with the default identity-based equals and hashcode!)

Volguus
Mar 3, 2009

Jabor posted:

This post is really funny, because you're the one who's been advocating encoding special business logic in your class's equals and hashcode methods, and I've just been saying "putting business logic in your equals method is dumb and unmaintainable, don't do that".
Where the gently caress did I say that? The business logic dictates what fields participate in the hash/equals not ... put business logic in the hash/equals. Jesus. What the flying gently caress, you're putting words in my mouth now?

Jabor posted:

If it's an immutable value object, override equals and hashcode to define whether they're completely identical and interchangable. If it's not an immutable value object, stick with the default identity-based implementation, and write a separate Comparator to use in cases where you need to express a different kind of equivalence relation.
You know you can have a mutable object with the only fields that provide its identity be immutable, right? It doesn't have to be an all or nothing. Actually, reading your posts, it does have to be all or nothing for you. It's all black or white in your universe.

Jabor posted:

(Pro tip: You can use mutable objects as map keys just fine as long as you leave them with the default identity-based equals and hashcode!)
Even pro-er tip: you can do that, but the results may not be what you want since the default identity based equals and hashcode may not reflect the correct identity of your objects.

Sagacity posted:

You can argue all you want, but equals/hashCode is not designed to handle object identity in the 'real world' sense. If an object is referring to the same person in the real world, but they have different hair color properties, equals/hashCode should reflect that.
equals/hasCode have to be designed to handle object identity in business sense. Which may or may not mimic the real world. If in your application the hair colour is the key differentiatior of people, the yes, equals/hashCode should reflect that and it should be made immutable. Otherwise, no.

Sagacity posted:

Your point of view already falls apart if you have two sections of your application that treat equality differently. How would you implement equals/hashCode in that case?

Like we established before, with a separate comparator.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Volguus posted:

Where the gently caress did I say that? The business logic dictates what fields participate in the hash/equals not ... put business logic in the hash/equals. Jesus. What the flying gently caress, you're putting words in my mouth now?

Either business concerns are dictating what you put in your equals method (hence, there is business logic in your equals method), or they do not, and your equals method is determined entirely by technical stuff. There's not actually any middle ground here?

quote:

You know you can have a mutable object with the only fields that provide its identity be immutable, right? It doesn't have to be an all or nothing. Actually, reading your posts, it does have to be all or nothing for you. It's all black or white in your universe.

Have you read Effective Java yet? It's honestly a bargain in terms of what you'll get out of it. Heck, you could even use your OReilly free trial and just read it for free. (Or perhaps your workplace already has a subscription you can use). You might think that you don't need it or it wouldn't be helpful if you're already an experienced programmer, but it's actually quite the opposite - it's most useful to someone who has some familiarity with the language and wants to know more about modern best practices.

The short version is that in the situation you describe, you're already making a terrible mistake.

quote:

Even pro-er tip: you can do that, but the results may not be what you want since the default identity based equals and hashcode may not reflect the correct identity of your objects.

It reflects object identity, which is almost certainly what you want in most cases, and far more importantly is consistent and predictable instead of being whatever arbitrary equivalence relation someone wanted at some point.

quote:

equals/hasCode have to be designed to handle object identity in business sense. Which may or may not mimic the real world. If in your application the hair colour is the key differentiatior of people, the yes, equals/hashCode should reflect that and it should be made immutable. Otherwise, no.


Like we established before, with a separate comparator.

How do you decide which semantics get the privileged position of being the equality semantics, and which are merely equivalence relations defined in comparators? Do you end up with multiple similar classes that do it totally differently, based on what use case they were originally written for (which may not even be a use case that your application handles any more)?

Overall, what you're describing is unmaintainable horseshit. It seems like it would break down as soon as you had more than about 5 developers, it would be a complete joke at 500.

Hekk
Oct 12, 2012

'smeper fi

I got all excited when I saw fifteen unread posts in the Java questions thread. I should have known it'd be nerds flexing their epeens.

Volguus
Mar 3, 2009

Jabor posted:

Either business concerns are dictating what you put in your equals method (hence, there is business logic in your equals method), or they do not, and your equals method is determined entirely by technical stuff. There's not actually any middle ground here?
Can you please rephrase that sentence? I honestly have no idea where you're getting at. The business logic dictates the business keys, the fields that go in equals/hash. There no any other criteria in here.

Jabor posted:

Have you read Effective Java yet? It's honestly a bargain in terms of what you'll get out of it. Heck, you could even use your OReilly free trial and just read it for free. (Or perhaps your workplace already has a subscription you can use). You might think that you don't need it or it wouldn't be helpful if you're already an experienced programmer, but it's actually quite the opposite - it's most useful to someone who has some familiarity with the language and wants to know more about modern best practices.

The short version is that in the situation you describe, you're already making a terrible mistake.
I have, quite a few years ago. It must have been the 2nd edition. Since you're so adamant that the book vindicates your point, i went and bought the 3rd edition. I am looking through it right now. Chapter 3 you say qualifies? Let's see, lets quote:

Page 38

quote:

So when is it appropriate to override equals? It is when a class has a notion of
logical equality that differs from mere object identity and a superclass has not
already overridden equals. This is generally the case for value classes.
A value
class is simply a class that represents a value, such as Integer or String. A
programmer who compares references to value objects using the equals method
expects to find out whether they are logically equivalent, not whether they refer to
the same object. Not only is overriding the equals method necessary to satisfy
programmer expectations, it enables instances to serve as map keys or set
elements with predictable, desirable behavior.
One kind of value class that does not require the equals method to be overrid-
den is a class that uses instance control (Item 1) to ensure that at most one object
exists with each value. Enum types (Item 34) fall into this category. For these
classes, logical equality is the same as object identity, so Object’s equals method
functions as a logical equals method

Hmm, "has a notion of logical equality that differs from mere object identity". Strange. Don't you think a Person entity, a domain object qualifies? I'd say it does. It certainly, unmistakably does. But lets go on .

So we go through all the rules for writing a proper equals method, which is all fine and dandy and we reach page 47

quote:

ITEM 10: OBEY THE GENERAL CONTRACT WHEN OVERRIDING EQUALS (page) 47

For each “significant” field in the class, check if that field of the argument matches the corresponding field of this object.

Hmm, "significant". That's strange. Who determines what is "significant"? What fields make the business keys? The tooth faerie? The business logic? Nah, surely it cannot be the business logic, after all you've all been singing praises to the tooth faerie so far.

The rest of the chapter goes on about hashCode (same remark, strangely, about those pesky "significant" fields, unbelievable), toString and clone. Nowhere did I see any of your claims, namely:

Jabor posted:

If your thing is mutable you shouldn't be overriding equals/hashcode at all, because object identity is more important.
and

Jabor posted:

If you have two immutable objects that are mostly the same but the Name field is different then yes they absolutely should not compare equal, seriously what the gently caress?
But hey, I'm here, I have the book open, I'm waiting for you to point the page number with the quote where the book sustains your point.

Jabor posted:

It reflects object identity, which is almost certainly what you want in most cases, and far more importantly is consistent and predictable instead of being whatever arbitrary equivalence relation someone wanted at some point.

How do you decide which semantics get the privileged position of being the equality semantics, and which are merely equivalence relations defined in comparators? Do you end up with multiple similar classes that do it totally differently, based on what use case they were originally written for (which may not even be a use case that your application handles any more)?

Overall, what you're describing is unmaintainable horseshit. It seems like it would break down as soon as you had more than about 5 developers, it would be a complete joke at 500.

Hahaha, this is getting hilarious.

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

A Person object isn't a person though, it's a representation - and two representations with different data are probably not considered identical. If someone changes their name, arguably an object with the old name isn't valid, isn't interchangeable with an updated object, and will cause problems if you pick one over the other (say if you throw them both in a Set)

It's possible you'd have some business logic where this isn't an issue, but what people are saying is that's an unusual situation, and it could create issues as development continues and those objects start to get used in other places. Wouldn't it be better to just create comparators for any business logic and leave the usual language semantics alone?

Volguus
Mar 3, 2009

baka kaba posted:

A Person object isn't a person though, it's a representation - and two representations with different data are probably not considered identical. If someone changes their name, arguably an object with the old name isn't valid, isn't interchangeable with an updated object, and will cause problems if you pick one over the other (say if you throw them both in a Set)

It's possible you'd have some business logic where this isn't an issue, but what people are saying is that's an unusual situation, and it could create issues as development continues and those objects start to get used in other places. Wouldn't it be better to just create comparators for any business logic and leave the usual language semantics alone?

A person object is a representation of most likely a real person, isn't it? That would have a Name, an Address, a work position. Surely you don't assign a printer to be a Person. right?

And my argument is that it's a logical, usually, desirable situation, where only the "significant" fields of a person are considered not the identity and not all of them. You (and others) are saying how this can lead to issues when used in other places: which ones? How? Shouldn't the business keys be the same throughout the entire application? Why would you change the semantics of a Person?
And let's just assume that you really really really want to change the semantics of a person, for a particular situation, for a particular operation: The book itself provides examples like I have before (me: CSVPerson extends Person, them: ColorPoint extends Point) although it makes a very good point to prefer composition over inheritance and have the Person object as opposed to be a person object. Yes, that is certainly the more desirable approach. Any way you slice it, you have the problem solved.

Now, if you come and say: 99% of the use cases of the Person object throughout the system are these special kinds of operations where it would have to be various things therefore defining any business keys is a waste of time, I would understand. But even there, the implementation of equals in hashCode only matters if you're using the object in data structures that ask for them (namely a Key in a Map or an element in a Set). Now, if you do not override equals/hash why in the universe would you put those objects in a Set? What kind of logic would lead one to do that? Put them in a List, you're done, it's simple, it's more efficient, don't sweat it. If you don't care if they're equal, then you don't. There is no point in arguing over anything.

Sagacity
May 2, 2003
Hopefully my epitaph will be funnier than my custom title.
You seem to think that "significant fields" mean "fields that I think are significant for the identity of the person".

The author of the book is simply saying you should ignore things like calculated fields. This seems to be where your fundamental misunderstanding comes from.

It's unfortunate, because your phrasing seem to suggest you assume you are on the right side of this argument.

Volguus
Mar 3, 2009

Sagacity posted:

You seem to think that "significant fields" mean "fields that I think are significant for the identity of the person".

The author of the book is simply saying you should ignore things like calculated fields. This seems to be where your fundamental misunderstanding comes from.

It's unfortunate, because your phrasing seem to suggest you assume you are on the right side of this argument.

I know that "significant fields" means "fields that I think are significant for the identity of the person" and that I am on the right side of the argument. The book's author does not say "you should ignore things like calculated fields". The only thing the author says about calculated fields is (page 47):

quote:

You need not compare derived fields,
which can be calculated from “significant fields,” but doing so may improve
the performance of the equals method. If a derived field amounts to a summa-
ry description of the entire object, comparing this field will save you the ex-
pense of comparing the actual data if the comparison fails.

Where in the book does your statement even remotely looks to be valid and supported by the author?

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Volguus posted:

A person object is a representation of most likely a real person, isn't it? That would have a Name, an Address, a work position. Surely you don't assign a printer to be a Person. right?

The objects might represent the same, unique thing (person or printer or whatever) but that doesn't mean those representations themselves are identical, and that often matters when you're creating and manipulating these objects. They're an abstraction. Should two objects containing different data be considered identical? I mean sure, maybe there's a situation where you'd want that, but the general understanding is that if two things say different things then they're two different representations

Like if you have two Persons with different names that are meant to represent the same person... well, why are the names different? Is that correct, are they both valid? Should the logic behind this be hidden away in the class's equals method, the discrepancy (and the potential for it occurring) invisible to the rest of the system unless you know it's happening? Or should it be handled explicitly as part of the business logic that decides two disagreeing data objects can be considered identical in certain, specific cases?

I'm not saying it has to be one way or the other, but one way keeps it closer to standard, expected behaviour which reduces the potential for weird gotcha side effects rippling out. "btw don't use Sets" is definitely something that could catch people out down the line

Sagacity
May 2, 2003
Hopefully my epitaph will be funnier than my custom title.

baka kaba posted:

one way keeps it closer to standard, expected behaviour which reduces the potential for weird gotcha side effects rippling out. "btw don't use Sets" is definitely something that could catch people out down the line
Exactly this.

I'm sure people caught out by this during a production outage are very open to pedantic discussions about why it *is* in fact better and they (and most existing libraries) were doing it wrong

Imazul
Sep 3, 2006

This was actually a lot more bearable than most of you made it out to be.
All of this from a mention of project Lombok.

I love Lombok, saves so much time automating pojos and logging. It also makes collaborators angry when you start using val everywhere you don't care about knowing types.

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.
I'm not wild about val / var. I shy away from it in C# code too, that feels like something that should stay in javascript and interpreted languages.

Having strong types is good and knowing those types makes your code more readable. Don't make me guess based on your bad variable names. (Are we going to return to Hungarian Notation?)

RandomBlue
Dec 30, 2012

hay guys!


Biscuit Hider

Zaphod42 posted:

I'm not wild about val / var. I shy away from it in C# code too, that feels like something that should stay in javascript and interpreted languages.

Having strong types is good and knowing those types makes your code more readable. Don't make me guess based on your bad variable names. (Are we going to return to Hungarian Notation?)

var in c# is still strongly typed.

e: It takes on a type when the variable is initialized. It's implicitly typed: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/var

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

RandomBlue posted:

var in c# is still strongly typed.

e: It takes on a type when the variable is initialized. It's implicitly typed: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/var

I know, its all compiler-time, not run-time. But still, readability.

Lombok in Java does the same thing.

The MUMPSorceress
Jan 6, 2012


^SHTPSTS

Gary’s Answer

Volguus posted:

A person object is a representation of most likely a real person, isn't it? That would have a Name, an Address, a work position. Surely you don't assign a printer to be a Person. right?

And my argument is that it's a logical, usually, desirable situation, where only the "significant" fields of a person are considered not the identity and not all of them. You (and others) are saying how this can lead to issues when used in other places: which ones? How? Shouldn't the business keys be the same throughout the entire application? Why would you change the semantics of a Person?
And let's just assume that you really really really want to change the semantics of a person, for a particular situation, for a particular operation: The book itself provides examples like I have before (me: CSVPerson extends Person, them: ColorPoint extends Point) although it makes a very good point to prefer composition over inheritance and have the Person object as opposed to be a person object. Yes, that is certainly the more desirable approach. Any way you slice it, you have the problem solved.

Now, if you come and say: 99% of the use cases of the Person object throughout the system are these special kinds of operations where it would have to be various things therefore defining any business keys is a waste of time, I would understand. But even there, the implementation of equals in hashCode only matters if you're using the object in data structures that ask for them (namely a Key in a Map or an element in a Set). Now, if you do not override equals/hash why in the universe would you put those objects in a Set? What kind of logic would lead one to do that? Put them in a List, you're done, it's simple, it's more efficient, don't sweat it. If you don't care if they're equal, then you don't. There is no point in arguing over anything.

I don't care about this dumb argument but I have actually worked in an application that expanded a database literally named "person" to also include workstations, faxes, and bots because they were too lazy to implement a general purpose access control system and instead made anything that needed managed permissions people.

Never underestimate the poo poo lazy enterprise programmers on crunch timelines will do

Sagacity
May 2, 2003
Hopefully my epitaph will be funnier than my custom title.
All characters in Tony Hawk Pro Skater derive from a class called Bruce because originally the code was written for a game starring Bruce Willis as the protagonist. Nobody ever bothered to rename the class.

Janitor Prime
Jan 22, 2004

PC LOAD LETTER

What da fuck does that mean

Fun Shoe

Zaphod42 posted:

I know, its all compiler-time, not run-time. But still, readability.

Lombok in Java does the same thing.

I limit it's use for when I'm in the same function and I just told you the type on the RHS of the =. Never as the assignment of a method call that returns something, that's just killing your readability as you said.

Hughlander
May 11, 2005

Sagacity posted:

All characters in Tony Hawk Pro Skater derive from a class called Bruce because originally the code was written for a game starring Bruce Willis as the protagonist. Nobody ever bothered to rename the class.

Shadow of Mordor players have an open and close method since the base game object (Called CLTObject inherits from CLTDoor...)

hooah
Feb 6, 2006
WTF?
So anyhow, thanks to some help from the course's Slack group, I got it sorted out. I have to exclude Recipe from equals and hashCode to avoid circular references.

Soricidus
Oct 21, 2010
freedom-hating statist shill

Zaphod42 posted:

I'm not wild about val / var. I shy away from it in C# code too, that feels like something that should stay in javascript and interpreted languages.

Having strong types is good and knowing those types makes your code more readable. Don't make me guess based on your bad variable names. (Are we going to return to Hungarian Notation?)

Actually they’re good and cool and everyone should use them whenever possible. They don’t take anything away, they just make it less cluttered. The type is still there and if you aren’t sure what it is then you can just ask your ide and it’ll tell you, no guessing required.

Verbose types everywhere make code harder to read, not easier, and are the reason so many people started using dynamically typed languages to begin with.

smackfu
Jun 7, 2004

You know you have a good java code base when you have auto generated boiler plate Javadoc comments for all your auto generated getters and setters.

I like Lombok.

rujasu
Dec 19, 2013

Soricidus posted:

Verbose types everywhere make code harder to read, not easier, and are the reason so many people started using dynamically typed languages to begin with.

Well that's obviously pretty subjective, and I don't agree at all (code is more readable to me with explicit typing). You may have a point about more people preferring dynamic typing, but I'd argue that, first, JavaScript is popular for reasons that have nothing to do with the language itself (e.g. being the literal only option for client-side scripting on the web), and second, there's a reason TypeScript was invented.

carry on then
Jul 10, 2010

by VideoGames

(and can't post for 10 years!)

rujasu posted:

Well that's obviously pretty subjective, and I don't agree at all (code is more readable to me with explicit typing). You may have a point about more people preferring dynamic typing, but I'd argue that, first, JavaScript is popular for reasons that have nothing to do with the language itself (e.g. being the literal only option for client-side scripting on the web), and second, there's a reason TypeScript was invented.

Yeah, but TypeScript doesn't force declaration of type for variables if they're assigned right away, just like Kotlin, Swift, C#, and now Java.

rujasu
Dec 19, 2013

carry on then posted:

Yeah, but TypeScript doesn't force declaration of type for variables if they're assigned right away, just like Kotlin, Swift, C#, and now Java.

Well, TypeScript doesn't force declaration of type at all, since it's compatible with plain old JavaScript.

Personally, I'd like to keep that sort of sloppiness out of Java, but sadly I realize that's not the current trend.

CPColin
Sep 9, 2003

Big ol' smile.
*bursts into thread*

Kotlin!

(Seriously, if Lombok is being a pain, try out Kotlin.)

carry on then
Jul 10, 2010

by VideoGames

(and can't post for 10 years!)

rujasu posted:

Well, TypeScript doesn't force declaration of type at all, since it's compatible with plain old JavaScript.

Personally, I'd like to keep that sort of sloppiness out of Java, but sadly I realize that's not the current trend.

It's not sloppiness, it's brevity. Please stop holding this language back in 2000.

rujasu
Dec 19, 2013

carry on then posted:

It's not sloppiness, it's brevity. Please stop holding this language back in 2000.

Like I said, I know what the trend is, so I'm certainly not going to stop it. That said, newer isn't always better.

Adbot
ADBOT LOVES YOU

Soricidus
Oct 21, 2010
freedom-hating statist shill
*stares at screen*

var usersByUsername = new HashMap<String, User>();

*frowns, sweat beading on forehead as he struggles in vain to guess what type this variable might have*

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply