7 ms·
What is the most intrusive wart on your favourite programming language?
- mdasen 18y agoJava: The fact that I have to manually cast Arrays to a template. Everything else allows me to template nicely except arrays. Python: The error message passed when you call a method with the wrong number of arguments. It's just off since the method "def apple(self, steve, new_product)" has three args, but you'll call it with two "apple(steve, new_product)". So, the message that gets passed back if I pass in one or three arguments is just wrong. I actually like the explicit self in the definition, but the error message needs to say something like "method given the wrong number of args. 1 argument passed when there are 2 arguments plus implicitly passed self." Python: The functions that should be methods. len(list) just doesn't rub me as well as list.len(). It's such a stupid criticism that I'm hesitant to post it, but whatever, it bothers me. Likewise, Ruby's int.to_f seems much nicer than a built-in function float(int). Same with int and str. PHP: The fact that 0 == "apple". Yeah, integer 0 is equal to any string. That means: $a = 0; $b = "apple" $c = "ms" $a == $b $b != $c $a == $c Yeah, a == b, a == c and b != c. Um? Heck, integer 0 is equal to an uninitialized variable. It just makes bugs that are so hard to find. Yeah, it stops you from having to cast in certain situations, but for the little time it takes to cast, you end up with horrible bugs. Java: The fact that I can't do if(a) { return true } else { return false } in a method. The Java compiler will say that I don't have a return in that method because all of my returns are within a conditional even though it will always hit one of the return statements. if the Java compiler is going to check that I have an appropriate return, be smart enough to figure out that I do.
- windsurfer 18y agoAbout your last point: You can get around it by typing return (a);
- jaxn 18y agoor... if (a) { return true; } return false;
- RWilson 18y agoagreed, if (a) then just return a; if (a) { return true; } is just as redundant as an if (a == true) statement.
- RWilson 18y agoHmm... not sure what justified the -1 on this. Perhaps that in some languages if (a) can be used as a shortcut for if (a != null), where a is an object and not a boolean. So, as a correction to my previous comment. If (typeof a == "Boolean" || a instanceof boolean), I still stand by reducing redundancy, but if a is an object, then fine, if (a) return true;
- mdasen 18y agoI should have used a better example, but there are a good number of cases where the Java compiler complains about missing return statements that just don't need to be there. It's a wart in the language.
- dcminter 18y agoCan you cite a specific example where the condition is NOT ambiguous and the Java compiler WILL produce an error? The example you cite is incorrect (see my post later) - you can compile code of this form just fine. I'm not aware of unambiguous situations where the compiler will complain; if you see an error it's usually pebkac!
- zain 18y agoIt isn't always that straightforward. For example: if (a) return (some && complicated || boolean && calculation); else return (some || other && boolean || calculation); edit: I suppose you can get rid of the "else", but you shouldn't have to sacrifice readability for a compiler shortcoming. I'm with mdasen; the compiler should figure it out.
- ralph 18y agoReadability is improved by not having the else clause. It makes it clear that the return in the then-block is there and the code won't continue after the end-if.
- ars 18y agoYou (and some posters below you) missed the point. It's just an example. Think of the more general case.
- bendotc 18y agoPython: "Ruby's int.to_f seems much nicer than a built-in function float(int)." >>> print float.__class__.__name___ type See, "float" is a type. float(int) is a constructor for a floating point number. It's not a magic built-in function, it's just a constructor for type float. Same with int and str. I can't say there's anything wrong with Ruby's int.to_f, but I actually like the Python design better. Now, as far as len() goes, I agree. It's easy to forget about such troubles, but I definitely wasted a good 10 minutes when I was learning Python trying to figure out what property or method of type list (or str--I don't remember) I should use to get its length.
- ROFISH 18y agoThe C code for Fixnum#to_f is quite literally fix_to_f(VALUE num) { double val; val = (double)FIX2LONG(num); //RSHIFTs sign return DBL2NUM(val); //Ruby float constructor of C double value } It does the same thing. Ruby, by design, flows left to right instead of nested params. This way you don't have float(user.timestamp) but instead user.timestamp.to_f.
- jganetsk 18y agoAbout your last point: return (a ? ... : ... );
- dcminter 18y agoYour two Java points - the first one: Amen. The latter - not true: public static String foo(final boolean b) { if( b ) { return "Yes"; } else { return "No"; } } Compiles just fine.
- cabalamat 18y ago> Ruby's int.to_f seems much nicer than a built-in function float(int) I multiply by 1.0 to turn an int into a float: Python 2.5.1 (r251:54863, Jul 31 2008, 23:17:40) >>> 3/2 1 >>> 3*1.0/2 1.5 >>> float(3)/2 1.5
- riobard 18y agoPython (prior to 3.0): 1/3 == 0 well, unless you do from __future__ import division
- Dilpil 18y agoIf your working with integers, 1 div 3 is indeed zero.
- Zaak 18y agoThat makes sense in a language like C, but in Python there's no telling if you've got integers or floats at the point the division happens. I'm very happy it's fixed in Python 3.
- Raphael 18y agoWait, then how do you do integer division in Python 3?
- rwiser 18y ago1 // 3 == 0
- figured 18y agosubmitted to reddit, here is the thread:http://www.reddit.com/r/programming/comments/7hv0j/ask_proggit_what_is_the_most_intrusive_wart_on/ http://www.reddit.com/r/programming/comments/7hv0j/ask_progg... has some good responses
- apgwoz 18y agoActually, that's weird. I thought I attached that url to the post...
- IsaacSchlueter 18y agoNote the helpful text on the submit page: http://skitch.com/isaacschlueter/76ee/the-helpful-text-it-is-for-reading http://skitch.com/isaacschlueter/76ee/the-helpful-text-it-is...
- twism 18y agoPython: "<br>".join(["string1","string2"]) Maybe it shouldn't but this pisses me off.
- apu 18y agoWhat don't you like about this?
- twism 18y agoThe fact 'join' being a method of a string that accepts an array as an argument. I guess it isn't that bad, I just think I've been conditioned to expect it the other way around.
- Zaak 18y agostr.join("<br>", ["string1", "string2"]) I hate it too.
- eru 18y agoI like it.
- rbanffy 18y agoI would think a more natural approach of making join a method of any sequence would result in cleaner programs. (a, b, c).join(',') instead of: ','.join((a, b, c))
- cabalamat 18y agoI agree. Join should word the same as split: >>> "abcbe".split("b") ['a', 'c', 'e'] So to get back the original string you should be able to say: ['a', 'c', 'e'].join("b") #!!! WRONG !!! but this doesn't work and instead you have to say: >>> "b".join(['a', 'c', 'e']) 'abcbe'
- zepolen 18y agoYou miss out on a nice side-effect of join being a method of string: br = '<br>'.join br((a, b, c)) Personally I think it makes more sense the ruby way but it's never bugged me.
- IsaacSchlueter 18y agoMy favorite language is Javascript, so I've got plenty of warts to choose from. I think that the most intrusive one is semicolon insertion. This is perfectly valid code that does not do what it looks like: return { a: "foo" }; That's quite different from: return { a: "foo" };
- ars 18y agoThat's a pretty good argument to never use Allman, Whitesmiths, GNU, or Horstmann indent style. There can only be one and that's K&R. Woho! I just won a religious war.
- bayareaguy 18y agoTcl's string quoting conventions also try to force you to use K&R style for procedure bodies. e.g proc foo {x} { # do stuff } but if you really want to get around this you can abuse the continuation character proc foo {x} \ { # do stuff }
- IsaacSchlueter 18y agoAbsolutely! For Javascript at least, putting the { on the same line as the thing that caused it is pretty much the only rational policy. The weird thing is just how the interpreter handles this: return; { a: "foo"; } That's a null return, a block (not that JS supports block-level scope, so blocks are pointless), a labeled line (line-labels aren't actually used for anything, since there's no GOTO), and on that labeled line, there's a string expression that does nothing. So, this is really like 4 different warts working together, but semicolon insertion is by far the most insidious. Also, liberal use of parens can help prevent semicolon insertion bugs.
- cousin_it 18y agoMy favorite language is JavaScript too, and the most annoying wart for me is function scope instead of lexical scope. For example, var closures = []; for (var i = 0; i < 10; i++) { var j = i; closures[i] = function() { alert(j); } } closures[0](); // outputs 9, WTF? How to fix it: var closures = []; for (var i = 0; i < 10; i++) (function() { var j = i*i; closures[i] = function() { alert(j); } })(i) closures[0](); // outputs 0 as it should
- DarkShikari 18y agoThe aliasing rules in C. Almost every single case I have found of performance-critical code being compiled suboptimally is due to redundant load/stores being emitted due to aliasing restrictions. And no, the "restrict" keyword doesn't fix much of anything. The most annoying rule is that char * pointers can alias anything... especially when one has to deal with enormous amounts of 8-bit image data.
- potatolicious 18y agoObjective-C: lack of enforced constructors. Sure, by convention you're supposed to call the "init" function for the class, but you don't have to. There's really no good way to guarantee your object has been initialized correctly!
- rbanffy 18y agoIt's objetive, but, after all, it's also C... I find the Smalltalk-ishness of it a little weird when it intersperses with more traditional C code.
- jemmons 18y agoI don't get what the noise is about here. Millions of lines of objc code have been written without mass confusion of how to init objects. It might look good on paper, but in practice telling people "this is the designated initializer" seems to be more than sufficient to sort things out. And being able to initialize an object with anything (or, remember, to have anything initialize an object) only adds to the flexibility and dynamic character of the language.
- bayareaguy 18y agoI use Lua a lot these days and coming from Python, it seems silly that I have to provide my own empty? function since standard Lua doesn't offer any way to get the number of elements in an arbitrary table other than to iterate over it: function empty_p(t) for k,v in pairs(t) do return true end return false end -- later on if not empty_p(t) then do_processing(t) end This is because although Lua offers a #t operator, it's only guaranteed to be correct if you're careful about how the table is constructed. That and the weird ipairs() behavior for non-trivial tables drives me crazy sometimes. Here's an example: Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio > t = {1,2,3} > print(#t) 3 > for i,v in ipairs(t) do print(i,v) end 1 1 2 2 3 3 Ok so all is good. But now what happens when the table contains a nil? > t = {1,nil,3} > print(#t) 3 > for i,v in ipairs(t) do print(i,v) end 1 1 ipairs() stops at the first nil value even though Lua knows there is data past it. Things get more interesting for tables with non-integer keys: > t = {} > t['a'] = 1 > t['b'] = 2 > print(#t) 0 > t[1] = 1 > print(#t) 1 > for i,v in ipairs(t) do print(i,v) end 1 1 What's going on here is each Lua table has an array for integer valued keys and a separate hash table for non-integer keys and # and ipairs() only operate on the first array. To process all the keys you use pairs(): > for k,v in pairs(t) do print(k,v) end 1 1 a 1 b 2 While at first this doesn't seem to be such a big issue, it's easy to forget when it's safe to use the #t construct. I've made this error so often that now whenever my Lua code doesn't do what I expect the first thing I look for are places where I have something like: if #t > 0 then do_processing(t) end or for i,v in ipairs(t) process(v) end because chances are the real problem will turn out to be the particular way I initialized the table.
- silentbicycle 18y agoI suspect this is because a table may be used for an object (or some other abstract data type) which has a different data type. Adding another metatable hook for __empty might be another solution, though. (I agree it's a bit annoying.) > Ok so all is good. But now what happens when the table contains a nil? One of the invariants for the way Lua tables are implemented is that they won't contain nil as a value, IIRC. Using a multifaceted table type for both arrays and dicts is a mixed blessing. It is really convenient much of the time, but it does lead to some quirks. NB: The i in "ipairs" means "integer (keyed) pairs".
- lucraft 18y agoI just did this in Ruby and got a syntax error: Time.now -1.day Of course, what it should have been was: Time.now - 1.day
- sc 18y agoYou mean Rails. This works as expected, though: Time.now-1.day
- sunkencity 18y agothe poor unicode support in ruby
- pc 18y agoObjective-C: @property requires duplication of the ivar type, and doesn't imply @synthesize. (To do either of these would stop it being a simple macro, but that elegance comes at the expense of a frustrating amount of unnecessary typing.) Common Lisp: built-in functions aren't generic. Tedious verbosity of defclass. No literal syntax for hash tables. Debuggers so much worse than they should be. Smalltalk: having to manually implement getters/setters. Awkwardness of code generation. Ruby: gems not having a single canonical name (what you require != what you install).
- jemmons 18y agoObjC: You don't have to declare ivars for your @properties if you target 64bit. The 64bit runtime Does Magic. Also, @property cannot imply @synthesize because you might want to use @dynamic instead.
- gruseom 18y agoI missed this thread, but I'll add another Common Lisp annoyance: the way DESTRUCTURING-BIND is inconsistent with destructuring lists in LOOP. Specifically, I want to bind to NIL for variables I don't care about (rather than having to explicitly ignore them) and bind to heads of lists rather than always the whole thing. I've been meaning to check out the open-source BIND macro and see if it does any better.
- vegai 18y agoHaskell: people start talking behind my back when I mention implementing something on it
- habs 18y agoJava - I love Javadoc Tool. Don't really get to use it much now, but still love it. c# - Constraints on typed params. public T AssignLiteItem<T>(ArchivingItem archivingItem ) where T : Item { T myITem = (T)typeof(T).GetConstructor(new System.Type[] {}).Invoke(new Object[] { }); myITem.ItemReference = new ItemReference(archivingItem.Id); return myITem; }
- mindviews 18y agoDon't forget you can add an empty constructor constraint in c# generics. public T AssignLiteItem<T>(ArchivingItem archivingItem ) where T : Item, new() { T myITem = new T(); myITem.ItemReference = new ItemReference(archivingItem.Id); return myITem; } I do wish the compiler handled constraints for arbitrary constructor signatures on generic types, however...
- habs 18y agoNice, I guess I can get rid of the reflection invocation of the T Type constructor. Should speed things up a bit. Cheers.
- taw 18y agoPython: Too many things evaluate to false, like midnight datetime.time(0, 0), and XML nodes with 0 XML children ET.parse("<foo;>Hello</foo;>"). Perl: Too many things evaluate to false, like string containing single character "0". Both make "if foo" testing too fragile, so I'm back to "if foo != None", "if foo == True", "if defined $foo" etc. Python: Explicit self makes some really crappy testing DSLs. Perl: No way to compare two structures for equality, so no generic assert_equal. I hacked myself assert_equal with Data::Dumper, but it breaks in many cases that would be trivial in Ruby/Python. Ruby doesn't seem to have any particularly intrusive warts.
- hxa7241 18y agoLua: array indexing starting at 1 (and interoperating with C is one of the main purposes of the language)
- silentbicycle 18y agoSee also: (http://lua-users.org/wiki/CountingFromOne http://lua-users.org/wiki/CountingFromOne) There are arguments for doing it either way, but making indexing incompatible with the language in which it is expected to embed in is just rude.
- silentbicycle 18y agoWhich really is too bad, by the way - the language designers seem to have done a brilliant job of shrugging off potential design warts otherwise. It's a very clean language.
- hxa7241 18y agoOCaml: can't split modules/packages/namespaces across files (I can't remember exactly, but that is the gist)
- thelema 18y agoOCaml: no library compatibility between compiler versions -- recompile everything when you upgrade compiler.
- smtlaissezfaire 18y agoRuby: methods != lambdas != procs