- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
Sure, why not.
I tested this scenario and accessing via Map-interface was 3,19% FASTER. Since you omit used JVM we can't compare results. Mine was j2re1.4.2_08.
(Actually I suspect first access would we slower but hotspot can somehow optimize subsequent accesses).
Admin
These stinkers usally accept Object[] "Because then you can pass around ANYTHING you may want".
And surely passing two parameter is BAD. They should have GenericObjectRequest which wraps those maps and arrays.
Admin
"fairly documented"? That's like "slightly alive"...
Admin
I use j2re1.4.2_03-b02 and interface calls are way, way slower. Here is the code I used,
interface I { void f(); }
class A implements I { public void f() { } }
class B {
public static void main(String args[]) {
A a = new A();
I i = new A();
long t1;
t1 = System.currentTimeMillis();
for(int c=0;c<1000000000;c++);
System.out.println(System.currentTimeMillis() - t1);
t1 = System.currentTimeMillis();
for(int c=0;c<1000000000;c++) a.f();
System.out.println(System.currentTimeMillis() - t1);
t1 = System.currentTimeMillis();
for(int c=0;c<1000000000;c++) i.f();
System.out.println(System.currentTimeMillis() - t1);
t1 = System.currentTimeMillis();
for(int c=0;c<1000000000;c++);
System.out.println(System.currentTimeMillis() - t1);
t1 = System.currentTimeMillis();
for(int c=0;c<1000000000;c++) a.f();
System.out.println(System.currentTimeMillis() - t1);
t1 = System.currentTimeMillis();
for(int c=0;c<1000000000;c++) i.f();
System.out.println(System.currentTimeMillis() - t1);
}
}
and here are the results: (the first time around it's slower because it hasn't been JITted yet)
2516
1359
5344
1250
1359
5375
Deduct the empty loop time and you have 1359-1250=109ms for normal calls and 5375-1250=4125ms for interface calls. That's 37.8 times slower!
Admin
YMMD. That's a good one.
Torsten
Admin
Which means they run out after 262626/20/12=73 years! assuming they use all TLN possible (which does not seem to be the case) and do not increase the rate of new tables
Admin
It's rather 263737, since the 2nd and 3rd characters can be digits or underscore. (Does SQLServer allow underscore for the first character? IIRC Oracle doesn't)
Admin
Then they wouldn't be TLNs
Admin
Unmitigated hogwash. That used to be the case somwhere around java 1.1.
Admin
Funny factoid:
The hexadecimal system should properly be called "sexadecimal", because "hexa" is greek, while "decimal" is latin.
You can thank IBM for depriving the world's programmers of the fun of talking about "sex numbers".
Admin
Good point. What about TLNs containing accents, umlauts etc., like
?
Admin
That's not correct, and it depends on the implementation details, but in general it's not just a pointer copy. If an object implements several interfaces, you cannot assume that a pointer to the object is also a pointer to one of the interfaces. The object's vtable's first byte is not going to be an interface's vtable's first byte. You must query the object by the normal methods in order to allow it to give you the proper reference. Luckily in Java and C#, this happens automagically. However, there is a (small) performance penalty when casting between interface an actual class.
Admin
Things are not that clear cut that you seem to think. Consider
private static void tsA(HashMap a) {
a.get("a");
}
private static void tsI(Map a) {
a.get("a");
}
public static void main(String[] args) {
HashMap m = new HashMap();
Map p = new HashMap();
long t1;
t1 = System.currentTimeMillis();
for(int c=0;c<1000000000;c++);
System.out.println(System.currentTimeMillis() - t1);
t1 = System.currentTimeMillis();
for(int c=0;c<1000000000;c++) tsA(m);
System.out.println(System.currentTimeMillis() - t1);
t1 = System.currentTimeMillis();
for(int c=0;c<1000000000;c++) tsI(p);
System.out.println(System.currentTimeMillis() - t1);
t1 = System.currentTimeMillis();
for(int c=0;c<1000000000;c++);
System.out.println(System.currentTimeMillis() - t1);
t1 = System.currentTimeMillis();
for(int c=0;c<1000000000;c++) tsA(m);
System.out.println(System.currentTimeMillis() - t1);
t1 = System.currentTimeMillis();
for(int c=0;c<1000000000;c++) tsI(p);
System.out.println(System.currentTimeMillis() - t1);
}
and results
4096
38095
37384
1863
37874
37364
Only thing right now I can think of is that your original code somehow throws hotspots inlining out of game. Dealing with dynamic compiling IS tricky.
Admin
I don't see anything like that. Given a program:
(the slight changes are so I can ascertain with some confidence that calls aren't being simply elided, though the opening loop looks like it's being removed anyway)
I see:
with:
The interface is slower, but not so much slower as to be grounds for concern. The general rule--program to interfaces--is still a sound one. The difference is a few clock cycles. The greater flexibility afforded by programming to interfaces more than makes up for this.
Admin
Bingo. It's an 'enterprise' solution, backed by a database. The performance bottleneck is going to be there, not in the java code using Map instead of HashMap. Especially as it has 200+ tables. I fear teh joins.
However, it gets bonus points for having a table called 'Rug'. 'Rug' makes me laugh.
Simon
Admin
The problem here is that your method does nothing. Yes there is an extra overhead for interface calls but if you actually do something (such as a Map lookup) in your method it quickly becomes insignificant.
Admin
It's not a derivative, Map is an interface and HashMap implements the Map interface. Map is not concrete, but a reference to a Map object can reference anything implementing the Map interface and therefore allows your steel-and-bolts Java Dreadnought to be slightly more flexible by being less implementation-dependant (e.g. if you want to change the type of map used, you only have to change the HashMap initialisation to WhateverYourMapIs, the references to the interface won't have to change)
It is, few other languages are as inflexible and as interface-reliant than Java.
And when you check the code, you see that the lifespan of the map is likely to be about 3 lines of code, I'd have a hard time calling that "class dependencies", using a Map in this case is more of an overengineering issue really.
Admin
To be fair, the owner of the table has absolutely no relevance to the DB users that may or may not have access to said tables. I would expect to see all the tables owned by sysadmin, or some similar user.
Of course, some people might decide to implement their security at the application level, rather than the database level. Or both.
Admin
In Oracle, there is typically a DB user (aka schema) dedicated to the application who owns all the tables, views etc.
One reason is that the owner of the application (the one to grant rights on that tables) is not necessarily a DBA, so he might not have DBA privileges at all. Another reason is visibility: If there are two apps, both having a table called CUSTOMERS, there is no conflict if one table belongs to the user APP1 and the other one to APP2.
Admin
Glad that nobody's mentioned Clarion yet in this language flame-fest.
Oops... [:D]
Admin
giggle
Try running that with the -server VM switch. Meditate on the results. Read an article in the difficulties of writing microbenchmarks:
http://www-128.ibm.com/developerworks/java/library/j-jtp02225.html
Admin
It's irrelevant in the code shown, that calls the method. But I strongly suspect (because I have seen it too often in the wild) that the method actually requires HashMap as its parameter type. And that is seriously crappy, because by tying you to a specific implementation class, it also denies you the use of all the nice conveniences in java.util.Collections (unmodifiableMap(), synchronizedMap(), singletonMap(), the EMPTY_MAP constant...).
Admin
And I perfectly agree on that.
Admin
Well the real WTF stays the same.
Managers hearing buzzwords....
Consultants who don't know shit and don't care.
i've seen it all my life, and I don't expect to see it change ever
Admin
True, but if it did something, anonymous wouldn't have accidentally given evidence that I could use against him ... his experiment shows that an interface call has a performance hit on the order of nanoseconds. 1000000000 requests, 4 seconds slower.
So, we can lock ourselves into a particular class implementation instead of programming against an interface, in order to save nanoseconds on what is essentially a memory dereference.
What is that again that they say about premature optimization? Oh, right, can lead to bad design. :)
Admin
Guys, you're all missing the point.
Which is indeed how this whole thing started, is just plain wrong anyway.Anyone who's suggesting that the declaration should be:
Why? It gains you nothing. If the actual type of the variable has to be changed to another implementation of Map, then you have to change the line anyway.
It gains you nothing else.
Now, if this were an argument to a method, there is potential justification for taking the highest-level interface that describes what behaviors you need. But it isn't.
Admin
The table structure -MIGHT- have some logic behind it...they might be part of a partition table (although given the gaps in letters that's either highly unlikely or highly unnecessary here).
For those of you that don't know, a partition table effectively allows you to store another clustered index on a table. It breaks down a table into N tables and stores data in each one based on a constraint. In this case, the constraints would be something like left(field, 3)='RUE'. In certain cases this can -drastically- increase the speed of things.
MSSQL 2k5 does this without the hundreds or thousands of tables actually showing up, but in MSSQL2k and MSSQL7 you had to create each table and join them together with a view.
We used this for the "do not call" list for example. We had 700 or so tables (one for each area code) and then the clustered index in each table was the first 3 digits of their phone number. Made count/group by statements and joins a lot faster (.1 sec from 2 or 3).
But as I said, I doubt that's what they're doing here....
Admin
My opinion is simple: I would quit pretty early, and any team member who stayed just DESERVES to spend his life with enterprise-the-fuck.
Admin
Sigh.
You're the one who's missing the point. You're arguing from strictly a whatever-compiles point of view, and not from an object-oriented point of view.
The reason all variables, parameters and return types should be of type Map rather than HashMap is that it's a separation of contract (functionality) from implementation.
The method needs the functionality of a Map. There is zero probability that the implementation of that Map needs to be a HashMap. By forcing the parameter to be a HashMap, you remove flexibility and you force an implementation when in fact you only need something that does what the contract of the Map interface specifies.
This goes for variables too. It's just good practice. The variable's type should indicate the object's contract and capabilities, not the implementation of those capabilities.
The performance arguments I've seen posted are ludicrous. Ever hear the saying "Premature optimization is the root of all evil"? (If you haven't, feel free to do a web search for it.) That's truer in OO than anywhere else. Overhead is a natural part of OO. Get over it already. And no your app will not be noticeably slower because it needs five additional microseconds to make a method call. (Unless it's, like, a first-person shooter.) Not even when you have a thousand threads doing it at once.
Admin
I see this opinion a lot and it gets me wondering if it's that easy for people to quit one job one day and get another (better of course) the other... I would be very cautious to quit my job instantly even _if_ I found a lot of WTF-ish code and endured general crappy management. I would obviously look for another job, but not quit right away...
Might be different in different countries, obviously. Perhaps it's that easy in, eg., the US, or the Netherlands, but I don't recognize it from Sweden... Comments?
Admin
You miss a bit of a point. If everyone there would care about their work, the output, the "good" of the company, etc, the whole team would just hand in their notice, and quite possibly the management reconsidered. So in the end they could stay and keep improving whatever they had.
OTOH if developers are content until their check gets bounced, no surprise the world is filled with all those enterprises, enterprise consultants and the results of their collaborated effort.
And yes, actual quitting comes without a guarantee you can find a job the next day, or a better one within whatever time period. The guarantee is found the other way: if you stay you will work in crap and be responsile for it too. Then again, if you chose that you deserve it IMO.
Admin
Admin
I hate enterprise "framework solutions." I hate it when some dork believes he can develop a generic system to do anything your heart desires. It's BI! It's CRM! It's a data warehouse! Great, but your code is completely unreadable and takes 20 times longer to execute than if you had just built what you were asked to build and nothing more.
You know what sucks? Code that looks like this:
EnterpriseBullshit bs = EnterpriseFramework.BullshitFactory.GetBullshitByString("CreateAccount");
EnterpriseGenericResult bsResult = bs.Execute();
Looks great on paper huh? But after lines and lines of this crap building up in your code, nobody even knows where the create account logic is stored anymore because everything is too damn generic!
Stop with the obsession with reuse. Reuse is OK when you write a class library with your data access layer in it or something. But you shouldn't be able to reconfigure your app to brush your ass hair at runtime. It's cheaper to build, easier to maintain, easier to understand and more performant when you build a system that meets the requirements and doesn't exceed them.
Admin
You're absolutely right! Thankyou for succinctly putting this argument to rest (I hope!). If anyone remains unconvinced, read about Dependecy Injection and become a better OO developer.
Admin
Obsession with the buzzword of the millenium is worse than any mistaken concept of code reuse.
On the flip side, tho... companies who fall prey to that mistake play good games of buzzword bingo.
PS: That "Cleveland" captcha has text that's partially blotted out because it colour-matches the background.
Admin
I used your code and managed to get pretty much the same results on my computer with J2RE 1.5.0_06-b05. However, like other posters, I think about your code is throwing the VM for a loop. To be honest, I think it's completely optimizing away the "a.f()" calls, so all you're seeing is the looping cost, which is why it's so low, and actually manages to be lower than the empty loop in the first run.
I put together a slightly different test, which called overridden, non-overriden, and virtual methods, through both the direct and indirect references.
Here's my (rather long) code (assuming the forum doesn't eat it):
class X
{
public void x() {}
};
abstract class A
{
public void f() {}
public abstract void g();
public void h() {}
};
interface I
{
void i();
}
class B extends A implements I
{
public void g() {}
public void h() {}
public void i() {}
public void j() {}
}
public class Test
{
public static void main(String [] args)
{
test();
test();
}
static void test()
{
final int N = 1000000000;
long starttime = System.currentTimeMillis();
for (int i = 0; i < N; i++)
{
}
long endtime = System.currentTimeMillis();
long baseline = endtime - starttime;
System.out.println(baseline + "\tbaseline");
X x = new X();
starttime = System.currentTimeMillis();
for (int i = 0; i < N; i++)
{
x.x();
}
endtime = System.currentTimeMillis();
System.out.println(endtime - starttime - baseline + "\tX as X (x)");
B b = new B();
starttime = System.currentTimeMillis();
for (int i = 0; i < N; i++)
{
b.f();
}
endtime = System.currentTimeMillis();
System.out.println(endtime - starttime - baseline + "\tB as B (f)");
A a = new B();
starttime = System.currentTimeMillis();
for (int i = 0; i < N; i++)
{
a.f();
}
endtime = System.currentTimeMillis();
System.out.println(endtime - starttime - baseline + "\tB as A (f)");
b = new B();
starttime = System.currentTimeMillis();
for (int i = 0; i < N; i++)
{
b.g();
}
endtime = System.currentTimeMillis();
System.out.println(endtime - starttime - baseline + "\tB as B (g)");
a = new B();
starttime = System.currentTimeMillis();
for (int i = 0; i < N; i++)
{
a.g();
}
endtime = System.currentTimeMillis();
System.out.println(endtime - starttime - baseline + "\tB as A (g)");
b = new B();
starttime = System.currentTimeMillis();
for (int i = 0; i < N; i++)
{
b.h();
}
endtime = System.currentTimeMillis();
System.out.println(endtime - starttime - baseline + "\tB as B (h)");
a = new B();
starttime = System.currentTimeMillis();
for (int i = 0; i < N; i++)
{
a.h();
}
endtime = System.currentTimeMillis();
System.out.println(endtime - starttime - baseline + "\tB as A (h)");
b = new B();
starttime = System.currentTimeMillis();
for (int i = 0; i < N; i++)
{
b.i();
}
endtime = System.currentTimeMillis();
System.out.println(endtime - starttime - baseline + "\tB as B (i)");
I in = new B();
starttime = System.currentTimeMillis();
for (int i = 0; i < N; i++)
{
in.i();
}
endtime = System.currentTimeMillis();
System.out.println(endtime - starttime - baseline + "\tB as I (i)");
b = new B();
starttime = System.currentTimeMillis();
for (int i = 0; i < N; i++)
{
b.j();
}
endtime = System.currentTimeMillis();
System.out.println(endtime - starttime - baseline + "\tB as B (j)");
}
}
Here is the output:
C:\Documents and Settings\jörg\Desktop>java Test
1984 baseline
4938 X as X (x)
5376 B as B (f)
4501 B as A (f)
4937 B as B (g)
5407 B as A (g)
4891 B as B (h)
4422 B as A (h)
4516 B as B (i)
6438 B as I (i)
4985 B as B (j)
1469 baseline
46 X as X (x)
500 B as B (f)
515 B as A (f)
500 B as B (g)
500 B as A (g)
906 B as B (h)
5015 B as A (h)
734 B as B (i)
4422 B as I (i)
781 B as B (j)
The first run shows that the cost of accessing, whether directly, via an abstract method, overridden virtual, non-overridden virtual, or through an interface is all pretty similar. The second run shows us that the VM can do whatever it wants and that we can't trust the results of trivial loop-on-an-empty-function benchmarks. Note how even on the functions inherited from A, the VM isn't consistent with its optimization.
Admin
This is 100% false. Just an FYI.
Good OO design dictates that a method should not accept HashMap, but rather Map. And the object type should also be map even if the specific implementation is HashMap.
So...the thing would look like this:
Map m = new HashMap()
public void aMethod(Map m, OtherParams...){}
There are specific design reasons for this that revolve around the idea that this code might be used else where. There is a reason to have interfaces after all and this is one of hte major reasons.
Admin
"Automobile" is a good example of a hybrid Greek-Latin compound word.
All-Latin would be "ipsomobile".
All-Greek would be "autokinetikon".
Admin
OK, but you mean the reference type should be Map - there's no such thing as an object type Map - it's an interface. Let's not cloud the issue further.
Admin
Honestly, this is kind of silly. There really is no reason to do
Map m = new HashMap();
instead of
HashMap m = new HashMap();
within the method itself. If the method wants to use a HashMap internally, by all means, do so, and even reference it as such.. If it returns it or passes it into a method call, then those should most likely be Map references.
There are reasons to do stuff like this. While probably not the case for Maps, there are times when a method needs to instantiate a class that is an implementation of an interface, and then call methods on it that aren't part of the interface itself, but are part of that specific class (perhaps to configure it). Often times factories work like this. They might return an interface, but inside the factory itself, they need to call specific methods on the class implementing it before they are ready to return it.
That being said, worrying about peformance of interface calls is really silly.
Admin
Regarding IBM having that 6-char limit, doesn't that extend all the way back to their FORTRAN compiler (70's)? Anyone remember that mess? I think they still ensure their "enterprise" products from the past are still compatible with today's ("Open Soars" initiatives) as well as some possible future that hasn't happened yet. [;)]
Admin
Actually, it takes an Object which is cast to a HashMap right of the bat. Who knows....?
Admin
Amen!
Admin
Oh, and for all of you in this Map-HashMap discussion, who cares. That's just one of the many many WTF-able code fragments that was chosen for posting. For instance, there's alot of:
catch(SomeException se) { throw se; }
catch(AnotherException ae) { throw ae; }
catch(ThirdException te) { throw te; }
... continue ad nauseum for 5-10 lines
catch(Exception e) { throw e; }
Here's another good one:
public ArrayList getCurrentProcessRoles(String[] req) -- req[0] is the userid, req[1] is the request id, and the rest of req[] are the column names to retrieve in addition to the process role
Admin
enterprison[tm] ASAP.
Admin
The problem is most language designers do not know the place of their language.
Java is not that much better than C++ that is should have been created. C++ is not better than smalltalk, so it should not have been created. Is C really better than BCPL better than ALGOL?
I presume ALGOL was better than Fortran (that isn't hard to do), so it can exist (maybe, since LISP also existed).
There is nothing wrong with creating your own programming language. In fact it is educational, and perhaps fun (depending on what type of person you are). However there is something wrong with releasing a language without first being sure it is better. (Other than to get peer review from others)
The only way that Java is better than its peers is marketing. As a programmer I do not consider this useful.
The JVM is an interesting idea perhaps worth bring out, but it does not need the Java language to exist. Many other languages run on the JVM.
Admin
I agree. Personally, I INSIST on having a dedicated routine built just for brushing my ass hair.
(Let the historians note; this is the first time I have ever used the term 'ass hair' in a public forum.)
Admin
That one...eleven...onehundredeleven thing just made me spit water onto my desk!
Thank you so much!
Admin
Yeah, that was so cool!!!!!11eleventy(i^2)*(e^i*pi)!!
Admin
I fixed that for you
Fixed that one too.