News for hackers. Stuff that matters.
Re:Rust for C++ programmers – part 3: primitive types and op... by mercurial on Wednesday April 23, 2014 @01:26AM (#7632299)
Having been the victim of a fun Javascript bug recently (something like ("1" + 10)*2), I must say that I agree that type coercion is the wrong thing to do 99% of the time (probably with the exception of attempting to divide integers).
Re:Rust for C++ programmers – part 3: primitive types and op... by sehugg on Wednesday April 23, 2014 @07:15AM (#7633228)
I think that one safe exception is upcasting of integer types (e.g. i8 to i32) and I think it's a little awkward to program in Rust without it.

It seems also that using the "as" syntax for both upward and downward casts makes code a little harder to read. Either allowing implicit upcasting or having separate syntaxes for safe vs. unsafe numeric casts would make more sense to me.

Re:Rust for C++ programmers – part 3: primitive types and op... by masklinn on Wednesday April 23, 2014 @03:49AM (#7632690)
A colleague recently went through that as well, a (JS) graphing package would sometimes display bar charts with an incorrect scale (it would pick the wrong maximum value, so part of the bars would be cut off).

Turns out the package expected numbers, but sometimes a bug meant the data source would give arrays (of a single number each), the package's own max (using <) would perform a lexical comparison (comparison would coerce to string and a graph with a value at 800 and one at 1800 would pick a y-scale for 800 and cut off 1800) but further operations would coerce to number, so there was no error anywhere and most graphs looked correct.

Re:Rust for C++ programmers – part 3: primitive types and op... by repsilat on Wednesday April 23, 2014 @04:00AM (#7632730)
Add me to the list. The other day I was debugging some simple Python code that worked something like

    return 10000 if x > 10000 else x
and it wasn't working because x was a string. Instead of raising an exception, though, Python decided that all strings are "greater than" all integers, and code was essentially equivalent to

    return x
Re:Rust for C++ programmers – part 3: primitive types and op... by masklinn on Wednesday April 23, 2014 @04:54AM (#7632908)
> Instead of raising an exception, though, Python decided that all strings are "greater than" all integers

Yep. That's one of the things they changed/fixed in Python 3, comparisons are not defined across and between any and all types:

    >>> "foo" > 3
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unorderable types: str() > int()
Re:Rust for C++ programmers – part 3: primitive types and op... by nnq on Wednesday April 23, 2014 @04:23AM (#7632804)
99% of such bugs can be avoided in a weakly typed language by simply having the string concatenation operator different from the "+" operator (PHP has the "." operator for this, VisualBasic has "&" ...Haskell has "++" ) ...yet Javascript, Python and Ruby seem to stubbornly avoid this simple way of achieving some sort of sanity (and yeas on this one PHP is above Python and Javascript!).

Also, having "<" and ">" also work for strings is another semantic abomination. You need different operators or just functions for doing this on strings (and if you treat strings as collections they can also be your collections operators).

These problems are not cause by "type coercion" itself (even if lots of people agree that "type coercion" in general is a bad idea...), they are caused by mixing scalar operators and vector operators and converting one way or another when doing this. The only solution out of this is to either throw and error for these coercion cases, or, when it actually makes sense, like in Matlab you have scalars and matrixes, have a new separate set of operators for these cases (like ".+" and friends family of operators).

Re:Rust for C++ programmers – part 3: primitive types and op... by lifthrasiir on Wednesday April 23, 2014 @04:29AM (#7632824)
No. PHP's `+` operator always tries to convert to the number, and uses 0 (!!!) when it is not possible. (e.g. what is `"hello" + "world"`?) Having different operators hardly matters; operators should cause a visible and clear error if they were given unexpected operands. Python is better in that regard since it does not allow `str + int` and so on.
Re:Rust for C++ programmers – part 3: primitive types and op... by nnq on Wednesday April 23, 2014 @04:33AM (#7632842)
You're right, I forgot about this abomination. I retract any praise for PHP :) But I still think having one operator "+" for scalars, one like "&" for strings and another one like "++" for lists makes a lot of sense even in a dynamic language.
Re:Rust for C++ programmers – part 3: primitive types and op... by saurik on Wednesday April 23, 2014 @04:41AM (#7632872)
FWIW, I would not call this "coercion", I'd call this "destruction": while I personally prefer languages that statically don't allow even-potentially-lossy conversions (such as string to number, or float to int) without explicit syntax bounding the error, languages that blow up at runtime if you try to numeric-add "hello" yet accept the string "0" without complaint are "acceptable" in a way that PHP (and MySQL) simply destroying data (whether by replacement or truncation) and returning/storing garbage in an attempt to satisfy the required type constraints is not :/.
Re:Rust for C++ programmers – part 3: primitive types and op... by Aqwis on Wednesday April 23, 2014 @04:30AM (#7632832)
Have you used Python a lot? That's not how it works. Python is not weakly typed and

"string" + 5

throws an exception.

Re:Rust for C++ programmers – part 3: primitive types and op... by mercurial on Wednesday April 23, 2014 @04:36AM (#7632855)
Yes (though it treats 1 as True and 0 as False, which it really ought to avoid).
Re:Rust for C++ programmers – part 3: primitive types and op... by masklinn on Wednesday April 23, 2014 @04:52AM (#7632905)
Historical imperative though, for backwards compatibility with

    if some_bool == 1
or

    if isinstance(some_bool, int)
written before the bool type was added (which only happened 2.3)
Re:Rust for C++ programmers – part 3: primitive types and op... by unwind on Wednesday April 23, 2014 @09:44AM (#7633873)
I dream of a language where booleans cannot be compared explicitly against literals, that would be awesome.

I have powerful dislike for code like the future version of the above, i.e.

    if some_bool == True
since that, in my mind's machine, just generates a bool result, which then (in the logic of the code) must be compared to True. If the result of == doesn't have to be compared, then why does some_bool? It's brutally inconsistent and fantastically annoying.

Unfortunately, to many programmers it's also second nature to write such comparisons. Gaah. :(

Re:Rust for C++ programmers – part 3: primitive types and op... by Dylan16807 on Wednesday April 23, 2014 @09:55AM (#7633937)
>where booleans cannot be compared

Sounds like a way to make XOR be a big pain.

Or do you only want to ban comparing to literals? It can make things clearer to write something like "if bool==false" rather than "if not bool", especially when double negatives get involved.

Only ban comparing to literal true? Sure, go for it. But then the language is more complex for no real benefit.

Re:Rust for C++ programmers – part 3: primitive types and op... by masklinn on Wednesday April 23, 2014 @09:54AM (#7633927)
Equality might be used for other things, e.g. a map with boolean keys, stuff like that. So I don't think it would be workable.

You could try removing Eq, Ord and TotalOrd from Rust's bool and see what breaks.

Re:Rust for C++ programmers – part 3: primitive types and op... by elktea on Wednesday April 23, 2014 @04:33AM (#7632844)
Python is safe from this:

    Python 2.7.5 (default, Feb 19 2014, 13:47:28) 
    [GCC 4.8.2 20131212 (Red Hat 4.8.2-7)] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> "0" + 5
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: cannot concatenate 'str' and 'int' objects
Re:Rust for C++ programmers – part 3: primitive types and op... by mercurial on Wednesday April 23, 2014 @11:14AM (#7634446)
Haskell is a more complex case. (++) is the list concatenation operator, eg: [1,2,3,4] = [1,2} ++ [3,4]. While the default String type is nothing more than a linked list of Unicode codepoints, it's notoriously inefficient. The preferred way of representing strings is usually Data.Text, which being a monoid, supports <> for concatenation. However, if you only kept the addition operation for number, you could perfectly well do 1 <> 2 and obtain 3 (you can actually do that with Sum 1 <> Sum 2, obtaining Sum 3 as a result - wrapping with Sum is necessary due to the fact that numbers are also a monoid under multiplication). What would save you from a runtime error is the fact that the monoid concatenation operator expects its two parameters to have the same datatype.
Re:Rust for C++ programmers – part 3: primitive types and op... by nnq on Wednesday April 23, 2014 @04:36AM (#7632854)
EDIT: My bad, I retract all reference to Python, its dynamic strong typing really prevents these kings of problems. The behaviors I was thinking on happen in Javascript (and sometimes in Ruby as I recollect).
Re:Rust for C++ programmers – part 3: primitive types and op... by adamnemecek on Wednesday April 23, 2014 @04:37AM (#7632859)
Ruby is the same as Python in this aspect.
Re:Rust for C++ programmers – part 3: primitive types and op... by saurik on Wednesday April 23, 2014 @03:46AM (#7632681)
It isn't as much about the coercion as the consistency: the division case returning a float when given integers is fine if the division operator always does that. Some languages (VB being an example; I wish more were) have a "string concatenation" operator that is separate from numeric addition; 1 & 2 is always going to be "12".
Re:Rust for C++ programmers – part 3: primitive types and op... by alok-g on Wednesday April 23, 2014 @02:14PM (#7635805)
I think too that integer division should by default yield floating-point. And likewise for uint subtraction, which should yield int and not uint by default. The programmer may appropriately cast to uint if she knows that the result will not be negative.