- Feature Articles
- CodeSOD
-
Error'd
- Most Recent Articles
- The Song that Never Ends?
- Princess Pricing
- Einfach so
- Kaids Hen 2025
- Fi fa foe
- Microbits
- No Rush
- Bridge for Sale
-
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
Avtually the String is Life. The Long is the universe, and the HashMap is everything. Funnily enough all this program does is return "42"
Admin
I would argue that the C++ RAII mechanism fits these criteria; it's usually just as readable as making it explicit with a try/finally or an anonymous inner class, just as efficient (if not more so), and shorter.
I understand there's a good reason for it. But it does make some things harder if you know that it won't be called outside of the current function. Um, what? Please translate the following code that uses try/finally to one that uses an anonymous inner class (I make no guarantee that the syntax is correct, but it should be at least plenty clear enough to determine what I'm trying to do):int readFiles(string[] filenames) { int bytesRead = 0; for(string name : filenames) { try { FileInputStream f = new FileInputStream(name);}
If there is a trivial way of making this use an anonymous inner class, I'm missing it.
That's a matter of style; it often makes sense. That only works if the inner class doesn't have to modify them. You never know what a given function behaves like just by looking at it being used - you have to know it's implementation too. Should we banish functions as syntactic sugar for explicit stack management and a goto as well?(I'm being deliberately inflammatory; functions are clearly much more important syntactic sugar than operator overloading.)
Eventually. When the garbage collector gets around to it. If it does.In other words, no, it's not deterministic.
Admin
No, unfortunately not. This is actually hierarchical, not just a 3-tuple key. We needed to perform operations like deleting all data associated with a particular key at one layer of the hierarchy, etc.
Admin
Hey look, another page.
In Java this is much more true than in C++ (read: operator overloading is much more important in C++) since C++ templates are a lot more powerful. The fact that templates use compile-time duck typing means that you can write a template that uses * and it will operate the same on iterators and pointers, you can write a template that uses [] and it will operate the same on vectors and arrays, or you can write a template that uses + and operates the same on ints and quaternion objects.You could compensate by writing and overloading a bunch of functions (like "int add(int a, int b) { return a + b; }" then call them, but that's much more work. Java is missing some nice syntactic sugar by omitting operator overloading, but if it were removed from C++ it would greatly increase the overhead of doing many things with templates.
Aren't you the person who just a moment ago wrote "The more opportunities you give the people to shoot themselves in the foot, the more guns you will hear going off"?The converse is that if you make it easier to do something right, the fewer guns you will hear going off. I (and others) are arguing that RAII makes it easier to get resource management right.
Admin
Here we go:
static class FileProcessor { public abstract void processChar(char c); public int processFile(String filename) { int bytesRead = 0; FileInputStream f = null; try { f = new FileInputStream(filename); int c; while ((c = f.read()) != -1) { ++bytesRead; processChar((char)c); } } catch(Exception ex) { System.err.println(ex); } finally { try { if(f != null) f.close(); } catch(Exception ex) {} } return bytesRead; } } int readFiles(String[] filenames) { int bytesRead = 0; for(String name : filenames) bytesRead += new FileProcessor() { public void processChar(char c) { System.out.write(c); } }.processFile(name); return bytesRead; }I took the liberty to implement it as a template pattern with a hook method that allows processing of each character. Each call to processFile() returns the number of chars in this file. BTW, of course one could do the processing of all files in the local class i.e. move the foreach-loop inside the process-method and return the total count:
static class FilesProcessor { public abstract void processChar(char c); public int processFile(String[] filenames) { int bytesRead = 0; for(String name : filenames) { FileInputStream f = null; try { f = new FileInputStream(name); int c; while ((c = f.read()) != -1) { ++bytesRead; processChar((char)c); } } catch(Exception ex) { System.err.println(ex); } finally { try { if(f != null) f.close(); } catch(Exception ex) {} } return bytesRead; } } int readFiles(String[] filenames) { return new FilesProcessor() { public void processChar(char c) { System.out.write(c); } }.processFile(filenames); }The notation of local classes is admittedly something one has to get used to, but it is not more complex than other notations I know from various languages. Real closures would be better though.
It doesn't have to. See above. That's not what I meant. A function/method has a name that (hopefully...) describes what it does. And it does not change semantics compared to some built-in standard behaviour like an overloaded operator does. *If* it does change its semantics, this is within the rules of polymorphic behaviour, i.e. it is either overloaded (then the parameters provide the context) or overridden (which means its behaviour is specialized in the derived class). OTOH an operator which looks like a built-in standard can have completely different semantics if it is overloaded: a = b + c; is perhaps prettier to look at, but if I see a = b.add(c); I'm more likely to suspect that a,b and c are - say - complex numbers or matrices instead of primitives. It is debatable if this de- or increases readability, but still it is nothing but syntactic sugar, whereas functions are of course not. I already answered that in another follow-up. Point taken. I was oversimplifying, because I did not think "deterministic" was used in the correct narrow sense in the post I was answering. Sorry for that.Admin
I'm sorry, I inadvertently omitted the "abstract" keyword:
static abstract class FileProcessor { ...which is necessary, because I declared the hook method abstract. The class does not have to be static, but for testing purposes we can put it inside the test class - and then it makes sense to declare it static, because this makes it a "top level" class, similar to a class declared in its own file. When using it outside the declaring class, however, the complete name is "Outer.FileProcessor" (i.e. including the enclosing class' name, e.g. "Outer"). If we just use it inside the enclosing class, we could in fact make it private too:
private static abstract class FileProcessor { ...For broad re-use, however, we should normally put it in its own source file and declare it public (and not static, it is "top level" anyway then):
public abstract class FileProcessor { ...Admin
The best way to do it (read: I think the only way to do it in a suitably generic manner) would probably be to have the function return an Object, then box up the bytes read in this case within the anonymous class, and unbox it at the end.
With generics you can keep static type safety, but it still requires an extra boxing and unboxing step if you aren't just returning a primitive. Still way less convenient than not having to do anything special at all.
This has the same problem. An operator overload also has a name that (hopefully) describes what it does, it's just a funny looking name like "+" that operates in infix notation.(With regards to the next point, the semantics don't really change, you're providing new semantics. The exception to this is like the && and || operators in C++. If you look in style books they caution against overloading them because it breaks short-circuiting and such. You could make a strong case that these shouldn't be overloadable, though I have had use for them in a library where operator overloading vastly, vastly improves readability in locations where it's used.)
Sure they are. What can you do in functions that I can't do in a language that doesn't provide them? Agreed; I saw your post too late to do anything about it there.Admin
The WTF isn't the actual code, here, but two Java quirks:
I sometimes write code like this in C++, but it usually looks like this instead:
shared_ptr<dictionary_t> d(new dictionary_t());
In Haskell, you could just type this:
d <- Data.Map.empty
and let the compiler infer the full type.
The problem here is that the obvious way to piece together bits of generic libraries is way too verbose in Java, compared with other languages.
Admin
"Why hasn't Java got typedef?"
The short answer is: It didn't need them before it got generics.
Admin
"2) If you want to do flexible partial-match searches: use a friggin' DBMS."
I hope that was sarcasm. At last count, using a friggin' DBMS where it's not appropriate is the cause of far more Daily WTFs than Java generics.
Admin
int count = new FilesProcessor() { public void processChar(char c) { System.out.write(c); } }.processFiles(names).getCharCount();andString content = new FilesProcessor() { public void processChar(char c) { } }.processFiles(names).getContentAsString();Different getContentAs...() methods could cater for different conversion needs. If processChar() was not abstract (perhaps not a bad idea in this case), we could leave out its empty implementation in the second example as well.I find this a quite elegant solution - you are free to think otherwise, of course ;o)
Point taken rearding the name. But what I wanted to express is this: you do not have a "standard" version built into the system which behaves in a way everybody expects for each and every method - and then perhaps changes semantics in some but not in all cases. This is true for operators OTOH. Not "in" functions, but "with" them - two words: Structured programming. That does make quite a difference... because missing operator overloading does *not* remove a whole programming paradigm. Go ask Mr. Wirth if this makes any difference ;o)Admin
[quote user="EvanED"][quote user="RobFreundlich"][quote user="EvanED"] [quote]And any Java developer worth shit would be running findbug. Prob Sol.[/quote] For a few of these problems. Will it tell me that I forgot to change the cursor back to a pointer?[/quote] If you set it up correctly, yeah. Else your Unit Tests will.
But on the whole I agree, here is one of the few cases that Closures (Java 7) will help.
Admin
@yuumei:
Nothing is wrong with the CODE... it's perfectly reasonable. The WTF is with the LANGUAGE. (Although, in fairness to Java, the coder COULD have encapsulated some of the abstractions in a class just to shorten the syntax.)
Admin
Lots of this C++ vs. Java discussion is centering on things which are non-factors in another environment: C++/CLI. If you don't know much about this, rest assured, it's not C# on a C++ compiler. You want deterministic destruction of managed types? No problem - variables come as either heap-allocated 'gcnew' types, or stack-allocated automatic ones...the difference:
void a() { FileStream^ fs = gcnew FileStream(filename); }
Upon returning, 'fs' is still alive - on the GC heap. But, if you:
void b() { FileStream fs(filename); }
Here, when the call returns, 'fs' is no more.
So, it is trivial to use any type, managed or not, in the classic way of creating auto-reset objects. For example, in drawing code, you may make calls which affect the underlying DC, so you should reset them before you return. As was pointed out earlier, you can use the 'using' construct in C# or VB.Net as such:
using GraphicsResetter gr(e.Graphics) { e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; }
Where, GraphicsResetter stores the start state, and its' destruction at the end of the using statement resets things in the Graphics object. In C++/CLI, this is simpler yet...somewhere before using the Graphics object, you would just create an automatic local:
GraphicsResetter gr(e->Graphics); e->Graphics->TextRenderingHint = TextRenderingHint::ClearTypeGridFit;
No extra block-definition necessary, since 'gr' will be destroyed (i.e. disposed: ~GraphicsResetter() will be called) at the method's closing brace...just like any other stack-allocated C++ object would be.
This is just one small example of the many advantages C++/CLI has over the other .Net languages; in addition to .Net Generics you also have the STL.Net implemention, applicability of typedefs for managed types, hybrid managed/native types for interop, the ability to do simple things like:
DestroyIcon((HICON)cursor->Handle.ToPointer());
...which are impossible in C# without using PInvoke and dealing with the clutter and associated overhead. Overall, C++/CLI provides an excellent environment for programming .Net - and for Windows it's simply the best, hands-down. It's just surprising that so few people appear to be aware of it.
Admin
Admin
The longest generic type I have written has 119 characters for code in production. It could have been longer but that would have been really silly. :)
Admin
In terms of the Java/C++ discussion, I think we did quite a creditable and non-flameworthy job. Perhaps when there's any distinct reason to mention C++/CLI, we'll get round to it.
I'm aware of it. Quite a lot of people are, strangely enough (and I believe that Herb Sutter might even be one of those people).To put it kindly, I'd suggest that it only has value (in a weird and inverse sort of way) as a "glue" language when you need to tie other .Net assemblies together with legacy (or otherwise) C++ code. In which case, I expect that you'd still need "pinvoke" anyway. But in all honesty, I don't really care.
Admin
Admin
Well, excuse me for living. I mentioned it because, as I said, it offers most of the 'C++' things, with the exception of const (for managed), that people were complaining were 'missing' from managed languages. But I'll try to make sure I get your permission before I post next time.
While partially true, that statement makes no sense in this context. Why would you only use it to expose native code to managed code, when you can just take care of the managed side right there. Your example assumes that you're going to create client assemblies which will reference this one, so why would you plan on writing them in a less-capable language? Unless, you don't miss typedefs, automatic variables, etc. - in which case, you are obviously not in the group which I was addressing.
Fine by me - sorry for wasting your precious, precious time.
Admin
I've been away, sorry to ignore this nice debate for so long. ;-)
No, only in one place. If I want to count bytes, the way I use the file object is exactly the same as if I want to do something else. I don't have to go into the fstream class and change the destructor.If you don't use the suggestion that the FilesProcessor becomes a generic class FilesProcessor<T> that returns a T, you need to modify FilesProcessor if you want to do something different. This is the part of the code that ensures that you close the file when you are done, the equivalent of the fstream destructor.
If you do use the suggestion, then things look better, but at the same time you will often have to do an obnoxious amount of boxing and unboxing if you modify more than one variable.
Otherwise:
And I don't think that's nearly as good a solution as what you get in C++. I don't think I'd have thought of this; I do like it better the other suggestions. Though would you be able to get multiple return values without boxing them up into a single return value? (Again, Java's lack of either pass-by-reference or mutable boxed primitive types comes back to haunt.)I would still say that the C++ method is better; even with this you have to pull every value out of the inner class explicitly.
No, but you still have conventions. If I have a pseudo-numeric type that lets me write "a.add(b)", by convention that is returning their sum. (Never mind the fact that "a.add(b)" *still* looks to me more like "a += b" than "a + b", but that's another matter.)And Java doesn't have any mechanism for making your add() function not behave that way (because that would be pretty much impossible of course).
Now, this sounds to me like I'm making a sort of argument that I hate which "we can't fix the problem [operations that behave unexpectedly] entirely, so might as well not make an improvement [disallow operator overloading]"... so I don't claim to be entirely consistent. ;-)
I guess I would just say that I think that the benefits of being able to write more natural code ("a + b" no matter whether a and b are ints or complex numbers or vectors, rather than "a + b" if they are ints but "a.add(b)" if they are complex or vector types) outweigh the small loss in unexpectedness. In the C++ code I've worked with, I would say undoubtedly that operator overloading has increased readability rather than decrease it.
From your later post:
I think you said what I was thinking better than I did. ;-)I think the reason this whole syntactic sugar discussion came up was that I really don't like dismissing language features [op overloading] solely on the basis of them being syntactic sugar, because I think that in some cases these can be extremely powerful things.
Even I would not even think of saying that operator overloading is in the same class as functions in general. I would say that, in C++ at least, operator overloading is in the same class as function overloading.
If you're asking what I think you are, Maybe you have legacy C++ code that you don't want to translate to C++.Net? Maybe you have a program that you maintain on multiple platforms and Mono isn't up to snuff?Admin
And using the same complex type multiple times is not so unusual anyway. If you're using, say, a Map<String, String> in several methods, you'll have to declare variables and parameters of that type several times.
Not to mention the (in my eyes annoying) verbosity of the creation of the object in the first place: Map<String, String> = new SomethingMap<String, String>(); At least in C++, if you declare a map<string,string>, you have a map<string,string>, not a useless pointer to (n)one.
Then you used a strange compiler. As I said, all C++ compilers I sort-of know do have methods to make sure the types match. This includes GNU G++ and MS Visual C++.Admin
Admin
I've got sympathy for person writing the crazy generic definition. There is no "typedef" facility in Java and the workarounds for this limitation all have their problems.
Admin
Admin
I still think that this weakness is partly counterbalanced by the virtues of implicit memory management which facilitates program correctness in certain regards. It may admittedly decrease resource management correctness if not used correctly - but which errors are more prevalent and more of a problem in typical C(++) systems - memory leaks or failures to close a file?
There's obviously still room for improvement and there must be some good compromise for these issues and perhaps some lessons can be learned from C# here - C# as a language does have some very good concepts. The main reason why I do not like it is the obvious promotion of the well known MS business model (vendor lock in etc.) by the .net framework... I'm already expecting to get flamed for that by some other readers, but I can take that ;o)
Given modern IDEs I really do not see that as a very big problem, but you are right in stating that local variables are easier to handle in that case. Quite naturally, yes. But firstly, using encapsulated objects is (apart from needing a little more code) the much cleaner way to handle multiple return values. I assume that with "lack of (...) pass-by-reference" you mean primitive method/function parameters. Java objects are of course passed by reference, whether as parameters or return values. But I have to say that I think the use of (primitive) out- or in-out-parameters is one of the worst concepts carried over from procedural languages into OO. I think even in C it is much cleaner if function parameters are only used as in-parameters and multiple return values are wrapped in a struct, even when the standard libs do otherwise a whole lot ;o) Primitive (in-)out-parameters in OO languages are IMHO plain evil. Quite, but with the above concept you will (in most of the cases) pull exactly one scalar value with the specialized method call - it is likely that one only needs one value (e.g. the file length OR the contents). Of course in case you need both, you have to do that little more work of (un)boxing.That the wrapper classes are immutable is one of the single most important design decisions in early Java - they already blew it with java.util.Date, and this leads to many subtle flaws when passing around mutable Date instances without defensively copying them (which is also more work). The same argument also speaks against the possibility to getting the addresses of primitives and passing the pointers around.
I see it just the other way round now, but I do have to admit that I did miss op overloading when switching from C++ to Java ;o) Thanks a lot. If I may deduce from your user name that you are an english native speaker, that's even a greater compliment, because I ain't ;o) D'accord. This view is backed up by the fact that both concepts are called "overloading" after all ;o)Admin