aspose file tools*
The moose likes Java in General and the fly likes is this technique an antipattern? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Java in General
Bookmark "is this technique an antipattern?" Watch "is this technique an antipattern?" New topic
Author

is this technique an antipattern?

Tudor Raneti
Ranch Hand

Joined: Nov 29, 2009
Posts: 145
I happened to stumble upon a solution and wonder if it's an OOP antipattern and whether it has any performance improvement over RTTI

I got a Sums class that is extended by SumsDated. Sums has a relevant sum field.

Then because they are POJOs used with Hibernate, I need to separate another subclass of Sums by name (UnitsSumsDated) to map them and use them with HQL.

However, instead of extending SumsDated into NrsSums and UnitsSums, I discovered I can do this:

create an interface


and do this

instead of


because in my code I can go like this:


with emphasis on these bits:



Instead of extending the SumsDated class twice just to have two or more different HQL mappings, and this way I implement OCP and some kind of extreme ISP
Stephan van Hulst
Bartender

Joined: Sep 20, 2010
Posts: 3611
    
  14

So how would the code be any different if you extended SumsDated instead of extending Sums and implementing Dated? The result would be exactly the same, since you don't have to cast upwards. The compiler automatically understands that a UnitsSumsDated is a Sums and it's also a Dated.
Tudor Raneti
Ranch Hand

Joined: Nov 29, 2009
Posts: 145
Well, I don't have the time to go deeper and see how the compiler handles RTTI exactly, and what happens in byte code, and when it happens.
If I would extend SumsDated, it would be all RTTI (dynamic) at work.
This way, I handle the casts myself (there's no compile time casts occuring in Java AFAIK though compile time checks are made), but being specific should yield a slight performance boost if JIT cooperates?
There's no need for dynamic polymorphism need in this case too, compiler should be able to tie things together somehow...

This quote Java Language Specification:
http://stackoverflow.com/questions/840322/how-does-the-java-cast-operator-work

Also some relevant articles:
http://en.wikipedia.org/wiki/Just-in-time_compilation
http://en.wikipedia.org/wiki/Java_compiler

Someone confirm with some experiment if you please? Thanks

P.S. Does it violate OCP? Since every time I add a new behaviour, I also have to add it to the module, it's more of extending the module, not modifying what already is.
Stephan van Hulst
Bartender

Joined: Sep 20, 2010
Posts: 3611
    
  14

Even *if* this works, the boost in performance would be so incredibly marginal that you would never notice any difference.

You're casting upwards by the way. So you're not being specific, quite the opposite. You're making the type more vague. Polymorphism is handled through jump tables, so regardless of the type of the object, after the compiler has performed type checking, the JVM will just perform a virtual method call on the object, which should be equally fast regardless of the type of the reference.

You're performing premature nano optimizations, which half of the time won't work out as you hoped. The best thing to do is write clear code that makes conceptual sense. People will spend more time trying to understand, maintain and debug a program that's written with all sorts of small tricks, than the program will save on running time using these tricks. As I don't know the requirements of your project, and I don't know what your classes are supposed to model conceptually, I can't tell you which of the two ways makes more sense for your project.

I hope this helps.
Tudor Raneti
Ranch Hand

Joined: Nov 29, 2009
Posts: 145
Even *if* this works

I wouldn't have posted this if it didn't

the boost in performance would be so incredibly marginal that you would never notice any difference.

Yes, though there's no improvement at all, because I upcast (which is safe - no explicit cast needed), RTTI only checks if the cast is correct, then the call follows those jump tables you referred to I think and calls the downmost override.
If there was a downcast, again, RTTI only checks if the cast is correct then the call is done on the downmost override.

If there was an improvement though, take that marginal boost in ms and multiply it by 1000, then, consider that it exist in a multiuser environment, with many other such tasks.
It is a micro optimisation, true, but...
You're performing premature nano optimizations, which half of the time won't work out as you hoped.

...I'm exploring a concept. If I was micro optimising, I would separate the static variables in my caches into two, to avoid read contention

after the compiler has performed type checking

I thought I was using the explicit cast as in C++, which I didn't (it doesn't exist actually in Java, RTTI always intervenes and then the downmost overriden behaviour is imposed). Check out this:


In C++, the classic cast "(Shape)" does not perform RTTI. It simply tells the compiler to treat the object as the new type. In Java, which does perform the type check, this cast is often called a "type-safe downcast."

from Thinking in Java 4th Edition

As a consequence of Liskov Substitution principle application in Java polymorphism, upcasting limits the behaviours that of a subtype in number, though it shouldn't be meant to restrict the client from using the supertype's behaviours since only methods are polymorphic, not fields, so there's no danger.
Casting won't call the supertype's behaviour if it has been overriden, or, in other words RTTI always runs detecting and calling the downmost override.

So, why this should work:
1. Objects in inheritance (is-a) can be regarded when built conceptually (and probably physically) by analogy to sheets of an onion (or a lot within another lot), so, if I'm casting to the supertype Sum explicitly, doing RTTI is useless logically because I'm refering explicitly to the Sum instance within the instance that extended Sum. That is, I explicitly said (though I have no operator to say it in Java) I want the Sum class instance, not the downmost subtype of it within that instance. If the compiler would ignore my explicit cast then it's doing RTTI, which it does in Java. The cast only helps me identify the object at compile time to call the right method.
2. Types and subtypes are supposed to be designed in respect to Liskov substitution principle, so explicitly casting to a supertype should be fine, but isn't available...

For the validity of this idea I mention: http://en.wikipedia.org/wiki/Method_overriding
Where C# allows for instance method hiding, then casting to the supertype and obtaining its behaviour.

In short, this only allows me to write like in the example above. RTTI happens anyway and thus no improvement in performance exists. Extending a common class instead of casting doesn't change the overall logic because I'm using the objects for something else not telling them to do something, so there's no difference but in style

Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Tudor Raneti wrote:
This way, I handle the casts myself (there's no compile time casts occuring in Java AFAIK though compile time checks are made), but being specific should yield a slight performance boost if JIT cooperates?


How do you figure?
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Tudor Raneti wrote:
If there was an improvement though, take that marginal boost in ms and multiply it by 1000,


But what else are you doing? Are these operations a significant portion of how your app spends its time? If there's any boost due to whatever casting trick you're employing here, it will be in the sub-microsecond range. A single I/O operation will probably overshadow the cost of thousands or even millions of these operations, with or without your micro-optimization.

A 100% performance improvement on something that your app spends 1% of its time on is not helpful, especially if it comes at the cost of clarity and ease of maintenance.
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7639
    
  19

Tudor Raneti wrote:In short, this only allows me to write like in the example above. RTTI happens anyway and thus no improvement in performance exists. Extending a common class instead of casting doesn't change the overall logic because I'm using the objects for something else not telling them to do something, so there's no difference but in style

Fraid I still don't see the point. Quite apart from what Stephan (and Knuth) have said, you've had to spend a long time to describe a technique which appears (a) trickier, and (b) more brittle than existing ones, with only one goal: saving a few nanoseconds. Even if you're right and its a few thousand, it still sounds like micro-optimization to me.

But maybe it's just me being thick.

Winston


Isn't it funny how there's always time and money enough to do it WRONG?
Articles by Winston can be found here
dennis deems
Ranch Hand

Joined: Mar 12, 2011
Posts: 808
Tudor Raneti wrote:RTTI ... HQL ... ISP ... JIT

Please spell out words instead of using abbreviations like this. There may be readers of the forum who are not familiar with them.
Tudor Raneti
Ranch Hand

Joined: Nov 29, 2009
Posts: 145
Dennis Deems wrote:
Tudor Raneti wrote:RTTI ... HQL ... ISP ... JIT

Please spell out words instead of using abbreviations like this. There may be readers of the forum who are not familiar with them.

RTTI
http://en.wikipedia.org/wiki/Run-time_type_information
HQL
http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.htm
OCP
http://en.wikipedia.org/wiki/Open/closed_principle
ISP
http://en.wikipedia.org/wiki/Interface_segregation_principle
JIT
http://en.wikipedia.org/wiki/Just-in-time_compilation



If I was using inheritance w/o interfaces in this, and there would be many attributes such as Dated but that wouldn't be always common among all the beans that share one main attribute in my application, that is Timelined in my case for example, then I would have lots of redundant functionality around and I would have to use reflection or annotations to ascertain which bean has something and which does not when fetching data in a generic way from all of them.

Otherwise there's no real difference if I inherit only in my code now... nor do I see how it's more or less brittle since whenever I add a new functionality I still have to extend the logic below.

Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7639
    
  19

Tudor Raneti wrote:If I was using inheritance w/o interfaces in this, and there would be many attributes such as Dated but that wouldn't be always common among all the beans that share one main attribute in my application...

Erm...but isn't that the whole point of subclassing?

...then I would have lots of redundant functionality around...

That, I strongly suspect, depends on how good your design is.

...and I would have to use reflection or annotations to ascertain which bean has something and which does not when fetching data in a generic way from all of them...

Really? Personally, I don't regard instanceof as 'reflection'; although I may get nasty looks from the purists. Alternatively, there are a few design patterns (Chain of Responsibility?) that you could use instead.

Your design logic seems to me the equivalent of banging a whole bunch of "similar" items into a single database table or file record, which I thought went out with magnetic tape drives.

...nor do I see how it's more or less brittle since whenever I add a new functionality I still have to extend the logic below...

Well if you still don't, then it's unlikely that I can convince you. Brittleness is not a function of a specific method or piece of code; it's intrinsic.

Anyway, good luck.

Winston
dennis deems
Ranch Hand

Joined: Mar 12, 2011
Posts: 808
Tudor Raneti wrote:
Dennis Deems wrote:
Tudor Raneti wrote:RTTI ... HQL ... ISP ... JIT

Please spell out words instead of using abbreviations like this. There may be readers of the forum who are not familiar with them.

RTTI
http://en.wikipedia.org/wiki/Run-time_type_information
HQL
http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.htm
OCP
http://en.wikipedia.org/wiki/Open/closed_principle
ISP
http://en.wikipedia.org/wiki/Interface_segregation_principle
JIT
http://en.wikipedia.org/wiki/Just-in-time_compilation


I'm not asking for links. I know how to use teh interWebs. I'm asking you to express yourself like a human being communicating with other human beings.
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Dennis Deems wrote:
Tudor Raneti wrote:
Dennis Deems wrote:
Tudor Raneti wrote:RTTI ... HQL ... ISP ... JIT

Please spell out words instead of using abbreviations like this. There may be readers of the forum who are not familiar with them.

RTTI
http://en.wikipedia.org/wiki/Run-time_type_information
HQL
http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.htm
OCP
http://en.wikipedia.org/wiki/Open/closed_principle
ISP
http://en.wikipedia.org/wiki/Interface_segregation_principle
JIT
http://en.wikipedia.org/wiki/Just-in-time_compilation


I'm not asking for links. I know how to use teh interWebs. I'm asking you to express yourself like a human being communicating with other human beings.


I don't think his use of those acronyms was really a problem. Acronyms abound in this business, and it's hard to know how widely known a given one is. I certainly wouldn't expect somebody to write out the full text for HTTP, SQL, TCP, UDP, etc. I consider myself to be of an average level of knowledge, and I knew 3 of the 5. And if someone doesn't know them, they can certainly google, or ask.
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7639
    
  19

Jeff Verdegan wrote:I consider myself to be of an average level of knowledge...

Fishing for compliments, Obi-wan?

Winston
dennis deems
Ranch Hand

Joined: Mar 12, 2011
Posts: 808
Winston Gutkowski wrote:
Jeff Verdegan wrote:I consider myself to be of an average level of knowledge...

Fishing for compliments, Obi-wan?
Winston

IKR? I LOL'd
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Winston Gutkowski wrote:
Jeff Verdegan wrote:I consider myself to be of an average level of knowledge...

Fishing for compliments, Obi-wan?


No, not at all. I used to think I was pretty smart, but the older I get, the more really smart people I meet, and the more pegs I get taken down. I guess in this case, though, I meant average in terms of people who are likely to be reading this thread.
Tudor Raneti
Ranch Hand

Joined: Nov 29, 2009
Posts: 145
Jeff Verdegan wrote:
Tudor Raneti wrote:
This way, I handle the casts myself (there's no compile time casts occuring in Java AFAIK though compile time checks are made), but being specific should yield a slight performance boost if JIT cooperates?


How do you figure?

It's hypothetical. What I read around said that RTTI always runs in Java, even when you cast (I even remember I read somewhere RTTI can be turned off, but can relocate that knowledge now; seems in Visual C++ compiler you can). I was refering to the C++ and C# capability to cast and use the supertype functionality, as for cooperation, perhaps I should've referred to Oracle doing something about it JIT, not JIT

P.S.
I'm not micro-optimizing, I'm just exploring design options (see title). I have nobody do discuss these things at work. There's another side of learning by mistakes, not being afraid to make them and see why they are mistakes and explore a bit... and sometimes you discover the mainstream is a mistake as a bonus, beside doing some theory cardio in the process.

My conclusion is that in the client code, there's no difference, hardly any difference in performance as for maintainability, you end up with roughly the same amount of types/interfaces.
What can I say... 'twas a nice trip, learned some things, remembered others, and that's all there is to it. Sometimes it's like this
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7639
    
  19

Tudor Raneti wrote:It's hypothetical. What I read around said that RTTI always runs in Java, even when you cast (I even remember I read somewhere RTTI can be turned off...

I certainly hope not. I'd hate all the lovely instanceofs in my equals() methods to suddenly stop working.

I was refering to the C++ and C# capability to cast and use the supertype functionality.

Which I suspect goes hand in hand with the ability to override final methods in C#; which I absolutely hate.

If you need such functionality (and I have to admit I never have in 11 years of writing Java), wouldn't it be simpler to just write a copy constructor for the superclass? Or again, maybe I'm being thick here.

Winston
Tudor Raneti
Ranch Hand

Joined: Nov 29, 2009
Posts: 145
I don't see how a copy constructor would work in this case. My objects are queried for data used in charts, they don't do something themselves with the data, and, sometimes the object has one behavior, sometimes another, sometimes none like the others, so I can't apply something that works like the composition pattern, that is polymorphism, because each behavior represents data fetching, each needing special treatment. Also, I mention my objects are like that because I broke the rule that my object model should represent the data model to the maximum of granularity, meaning I joined columns like Date from other table into my entity.

So I'm wondering if I should slap myself because Scott Meyers sais so in Effective C++:
Anytime you find yourself writing code of the form "if the object is of type T1, then do something, but if it's of type T2, then do something else," slap yourself.

This is a case just like that, but I can't use polymorphism except if I would generalize the attributes of the object into attribute1, ..., attributeN, then treat it by known data types when slapping them to the chart object, which again is a slappity slap logic bit.
For instance I got Sum objects with sum field (one field), and Parity object with odds and evens field (two fields). Both can be dated, but the number of fields differs. Sometimes I can get 6 fields...
Anyway... polymorphism means overhead, and if I generalize, it automatically means more overhead... so why do it? Surely generalizing means abstracting the business rules, making the code less readable IMO. Designing with interfaces looks clear to me since that's what interfaces do, declare a behavioral contract on an object.

P.S.
You can't override final, or sealed methods in C#.
Casting to the superclass to use its behavior is in respect to Liskov substitution principle, in reverse.
Overriding a final method makes no sense.
Maybe you are referring to hiding methods which is possible in Java as well with static methods.

Disclaimer. I may be excused for writing on this topic only when getting away from work, or like today, before I flee to the gym, or like now, before I go to sleep, so if it doesn't make sense, don't take it seriously, it's not because it's written smart
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7639
    
  19

Tudor Raneti wrote:I don't see how a copy constructor would work in this case.

Maybe I'm wrong, but from your post, it seems that you want to be able to "cast" an object to its supertype, and then have the resulting object use methods defined in the supertype rather than the subtype. This obviously won't work in Java because all non-final methods are virtual; however, if the supertype had a copy constructor, you could pass any subtype to it and return a cloned superclass object that would use the supertype methods.

So I'm wondering if I should slap myself because Scott Meyers sais so in Effective C++:
Anytime you find yourself writing code of the form "if the object is of type T1, then do something, but if it's of type T2, then do something else," slap yourself.

Probably; because he's absolutely right.

Anyway... polymorphism means overhead, and if I generalize, it automatically means more overhead...

Hunh? Explain please. Sure, polymorphism usually involves writing more code, but if you're worried about the nanoseconds of overhead for virtual calls then you truly are micro-optimizing.

Surely generalizing means abstracting the business rules, making the code less readable IMO. Designing with interfaces looks clear to me since that's what interfaces do, declare a behavioral contract on an object.

Hey, don't get me wrong: I'm all in favour of interfaces and designing to them; but the direction of design is normally from abstraction to specialization. It appears that you want to do a 180 and "re-abstract" the behaviour of an object that you've already specialized.

But, like I say, maybe I'm just not following your line of reasoning.

Winston
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: is this technique an antipattern?