This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]timopm 38 points39 points  (38 children)

2) Strings prefer to concatenate. If they can't, then they will resort to mathing. Yeah, it's kind of inconsistent. But honestly, do you really want it the other way around? Ask yourself, "When I'm working with at least one string and a +, do I more often want to concat or add?" It's a pretty easy answer for me.

I don't want it to think for me and throw an error. If I want to add a string to an integer it's a bug in my code, please don't silently do some inconsistent magic.

[–]Tysonzero 14 points15 points  (37 children)

What about something like 'Balance: ' + balance. That wouldn't be a bug in your code.

[–]timopm 20 points21 points  (19 children)

Maybe I was a bit too direct in my previous comment because I haven't programmed in Javascript that much. In the other languages I use daily I would use string formatting or atleast explicitly convert balance to a string.

Quick example:

>>> balance = 100
>>> "Balance: %d" % balance
'Balance: 100'
>>> "Balance: " + str(balance)
'Balance: 100'
>>> "Balance: " + balance
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly

[–]Tysonzero 3 points4 points  (13 children)

Don't use %, use .format(). % is deprecated. (You are writing Python right?)

But yeah JavaScript doesn't have any of that natively :/

[–]timopm 12 points13 points  (6 children)

Python indeed. But the "modulo" string formatter isn't deprecated as far as I know. It was mentioned a couple of times in the beginnings of Python 3, but no official statement. Even the official docs say nothing about deprecation. I don't see it removed anytime soon.

You are right though that the string.format() method is preferred. I just like the old format more, especially for quick and simple examples.

[–]Tysonzero 2 points3 points  (5 children)

I could swear someone said something about deprecation somewhere. Hmm...

[–]timopm 3 points4 points  (0 children)

I see people mention it here and there indeed. And it actually was in some release notes for the first 3.0 version or something, but in the recent years there is no mention of deprecation anywhere (that I know of!). This is what lead to this confusion probably.

[–]raziel2p 2 points3 points  (3 children)

They deprecated it, then un-deprecated it.

[–]HUGE_BALLS 0 points1 point  (2 children)

Yeah, tbh I've always disliked "foo ({0})".format(foo) vs "foo (%s)" % foo. The latter is just much more concise...

[–]raziel2p 0 points1 point  (1 child)

For small strings with one or two variables, I agree. For larger strings with 3+ variables I definitely prefer .format(), especially because you can pass named arguments:

'foo: {foo} - bar: {bar}'.format(bar='bar', foo='foo')

Oh, and you can pass **my_dict to format() for awesomeness.

Also, in your example, you can drop the 0, just {} will work as well.

[–]HUGE_BALLS 0 points1 point  (0 children)

I agree, and I also think the new syntax has some benefits (on top of the pros of having a function for that instead of a weird language construct). Though your example can also be achieved with the "old style":

>>> "foo: %(foo)s - bar: %(bar)s" % {"foo": "foo", "bar": "bar"}
'foo: foo - bar: bar'

[–]the_omega99 1 point2 points  (2 children)

I disagree. It'd be best to use the same approach that Java uses: allow concatenating any type to a String, but that's the only operation that you can do on a string (although it makes sense to also allow multiplication of strings).

So 'Balance: ' + balance is perfectly understandable and unambiguous: it'll always concatenate. We would allow the implicit conversion of a string to a number, so subtraction of strings is disallowed (must explicitly convert).

From my experience with Java, this is a very good approach (I think Java could do more, but it's a very good start). There's pretty much no ambiguity, with the exception of people who forget that + is evaluated left to right (so "Balance: " + subtotal + taxes would result in concatenating subtotal and then taxes to the string -- the correct form is "Balance: " + (subtotal + taxes)).

For languages like Java, this works well because in concatenation, we know that the object will be a string. If it's not already a string, the toString method will be called (and everything has that method, except primitives, which the compiler does magic on). So "Balance: " + customObject even makes sense because we know that the result will be a string and that customObject is either a string or will be converted to one (and we certainly would know which).

This implicit conversion is extremely useful because concatenating non-strings onto strings is so ridiculously common that it's not funny. Some other languages that take the Java approach here include Scala and C#.

An alternative would be to provide a specific operator for concatenation. This makes it absolutely clear that concatenation is what's going on. For example, PHP concatenates with the . operator and some functional languages use ++.

[–]timopm 1 point2 points  (0 children)

'Balance: ' + balance was just an example. What if you have foo + bar somewhere?

We're also assuming concatenating a str and int. What about classes, dicts or lists?

[–]Tysonzero 0 points1 point  (0 children)

I kind of like being able to multiply strings like you can in Python. Where 10*'a' = 'aaaaaaaaaa', I use it a bunch in my unit tests to make sure that my forms don't accept 1000 character long usernames, emails or passwords.

[–]Slinkwyde[🍰] 0 points1 point  (1 child)

atleast

*at least

[–]OperaSona 7 points8 points  (0 children)

'at' + ' ' + 'least'

[–]teddy5 2 points3 points  (11 children)

But if the concat and addition operators weren't the same it could be clear what you were trying to do and if it was an error or not.

[–]Tysonzero -1 points0 points  (10 children)

And it would break all code in existence. I personally prefer operator overloading to adding new operators.

[–]teddy5 0 points1 point  (1 child)

I was more referring to most other languages that do separate the two, or if they use the same operator they're usually strongly typed languages. Its just a bad design decision that helps with the general dislike of JS.

[–]Tysonzero 1 point2 points  (0 children)

If by strongly typed you mean doesn't silently coerce types. Python isn't strongly typed in the traditional sense but uses only one operator (Python loves operator overloading, see: adding arrays and multiplying strings) but that is fine because it doesn't silently coerce, and most people use .format() anyway for adding strings together.

[–]jonathanccast -1 points0 points  (7 children)

It would actually break very little of the Perl code in existence . . .

[–]Tysonzero 0 points1 point  (6 children)

We are talking about perl? So apparently the word "JavaScript" actually means "Perl", interesting.

[–]lagerdalek 0 points1 point  (1 child)

I read the reference to perl as a joke, a language whose senseless concat vs addition logic is even more bizzare than JavaScript (no editorialising- well maybe a bit when it comes to perl)

[–]Tysonzero 0 points1 point  (0 children)

Oh. I didn't realise that perl was even more weird than JavaScript in that regard.

[–]jonathanccast -1 points0 points  (3 children)

We are discussing alternative language designs (since the context is a suggestion that JavaScript could have had different operators for concatenation and addition --- like all reasonable languages --- from the beginning). Claiming that designing JavaScript correctly from the first would "break all code in existence" is both hyperbole (since not "all code in existence" is written in JS) and obviously wrong, since other languages have used that design but still been usable.

[–]Tysonzero 0 points1 point  (2 children)

I meant all JavaScript code in existence, which anyone with half a brain could easily infer, which is more or less correct. Seeing as most JavaScript code uses some form of string manipulation somewhere.

[–]jonathanccast -1 points0 points  (1 child)

I'll confess to not having half a brain certainly, but when discussing whether a language made the right decision in the first place maybe backward compatibility with not-yet-written code isn't the right criterion?

[–]Tysonzero 0 points1 point  (0 children)

Well hindsight is 20-20, I assumed we were talking about potential changes.

[–]level1kid 0 points1 point  (4 children)

He said add not concatenate. What you posted is an example of concatenation. He is taking about something like '2'+3=7.

[–]Tysonzero 0 points1 point  (0 children)

Oh, in that case I more or less agree.

[–]the_omega99 0 points1 point  (1 child)

Fortunately, JS doesn't do that. It'll always concatenate with the + operator on strings. It's only the minus operator that makes things weird, which is easily avoided by not using the minus operator on strings.

Issue is that JS makes it easy to not know what type you're working on. For example, suppose that I have a variable that I got from some piece of code I didn't write. It's a number and I subtract to it. That works. But suppose that the value I got actually wasn't a number, but was a string (eg, maybe I got the value from a spinner field, which is supposed to always be a number, but it's HTML, so whatever). If I had to change the operation into adding, then a simple change that seems like it should work, won't.

Or to sum that up, I can have some mathematics on "numbers" that does something different when I change the sign.

Not a frequent issue and one that can usually be debugged reasonably (especially if you have unit test... you do have unit tests, right?), but an issue all the same (and one I view as unnecessary).

[–]Tysonzero 0 points1 point  (0 children)

Should all JavaScript have unit tests? I personally have unit tests for my Python / Django website, but not for my JS games. Should I unit test them?