91

Suppose I write 0.5 as 0.-5 in unexpected way, but it can still run. What does 0. in 0.-5 do so that it can still run and evaluates to -5?

I also tried alert(0.-5+1) which prints -4, does JavaScript ignore 0. in 0.-5?

Community
  • 1
  • 1
ocomfd
  • 4,010
  • 2
  • 10
  • 19
  • 56
    `0.` is like `0.0`. Or just `0`. – Ry- Feb 25 '19 at 03:48
  • 63
    What makes you think that `0.-5` is an "unexpected way"? – Nico Haase Feb 25 '19 at 09:28
  • 15
    @NicoHaase: I'm pretty sure the OP used "unexpected way" to mean "I did not intend/expect to write that, but somehow I did". – Filip Milovanović Feb 25 '19 at 09:54
  • 15
    This works in many other languages too (e.g. Python). I personally don't like it at all. I'd rather have `0.-5` be a syntax error and not allow float literals with a trailing period but force people to write `.0` at the end. – Giacomo Alzetta Feb 25 '19 at 13:22
  • 9
    It's especially bad because allowing numbers to end in `.` prevents you from writing something like `123.toString(16)` (A common trick is to use `123..toString(16)`, which is really `(123.).toString(16)`) – 12Me21 Feb 25 '19 at 23:26
  • 4
    @12Me21: Honestly, I don't think it's a good idea to write `123.toString(16)` anyway. `(123).toString(16)` is much clearer IMHO. – ruakh Feb 26 '19 at 00:31
  • 2
    @12Me21 try `123 .toString()`. – Salman A Feb 26 '19 at 06:10
  • Because that's what it means? Your preference? – user207421 Feb 26 '19 at 07:52
  • 2
    `0.-5 = ((0.)-5) = ((0.)-(5)) = ((0)-(5)) = (0-5) = -5` – Muntasir Feb 26 '19 at 09:39
  • 2
    Did you expect that `-5` to be treated as *minus five tenths*, in other words `-5/10`? – Jyrki Lahtonen Feb 26 '19 at 11:32
  • @JohnDvorak `0.chr` being a method **call** bothers me way more than `0.` being a valid floating point literal. – Giacomo Alzetta Feb 27 '19 at 08:05
  • @GiacomoAlzetta why? You can add parentheses to the call if you like, or you can think of it as property access even though it's actually a getter. – John Dvorak Feb 27 '19 at 08:20
  • @JohnDvorak I don't like context-sensitive syntax if available. In `f(0.chr)` this is clearly passing the reference to method `chr` of object `0` to function `f` (and if this is not the case that's an other reason I wouldn't like Ruby). So `0.chr` being a method call in other contexts doe not make sense. – Giacomo Alzetta Feb 27 '19 at 08:23
  • It's times like this that I realize Javascript's greatest strengths are also its greatest weaknesses. In this case it's a lack of linguistic structure that is the double edged sword. – Jacksonkr Jul 23 '19 at 15:03

5 Answers5

196

Trailing digits after a . are optional:

console.log(0. === 0); // true

So

0.-5

evalutes to

0 - 5

which is just -5. Similarly,

0.-5+1

is

0 - 5 + 1

which is

-5 + 1

or -4.

doppelgreener
  • 4,809
  • 10
  • 46
  • 63
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
48

0.-5 could be successfully parsed as 0.[1], - and 5. Below is the abstract syntax tree for the expression generated by AST explorer:

Parse tree generated by AST explorer

This (in an unexpected way) is valid JavaScript and evaluates to -5.


[1] According to the grammar for numeric literals the decimal digits and exponent parts are optional:

NumericLiteral ::
  DecimalLiteral
  [...]

DecimalLiteral ::
  DecimalIntegerLiteral . DecimalDigitsopt ExponentPartopt

Salman A
  • 262,204
  • 82
  • 430
  • 521
40

In JS you can express a number with optional decimal point.

x = 5.;    //5
x = 5. + 6.   //11

And as of Tvde1's comment, any Number method can be applied too.

5..toString()

This syntax let us run the Number functions without parentheses.

5.toString() //error
(5).toString() //good
5..toString() //good
5 .toString() // awesome

See this question to find out why.

Charlie
  • 22,886
  • 11
  • 59
  • 90
  • 5
    You can even do `5..toString()`. – Tvde1 Feb 25 '19 at 06:15
  • 3
    If fact, you have to do 5..toString() to call the method, otherwise, you have to use parenthesis: (5).toString() – jo_va Feb 25 '19 at 09:49
  • 1
    Not only in JavaScript. Is there even a language where this is not the case? – Peter Mortensen Feb 25 '19 at 11:36
  • 3
    @PeterMortensen Ruby, for one. Also ALGOL 68. In Common Lisp, weirdly enough, `1.0` is floating point but `1.` is an integer. – Sneftel Feb 25 '19 at 13:14
  • 1
    Why would you write `5..toString()` if you can write `'5'` ? – Florian F Feb 25 '19 at 17:49
  • So 5. parsing to 5 is tolerable but weird but why would two adjacent numbers parse? 0.-5 would parse to "0 -5" which seems like a syntax error. I'm not completely familiar with JavaScript so it might be totally valid, I just don't know what it would mean. – Bill K Feb 25 '19 at 18:17
  • @BillK In JavaScript, that would be parsed not as `(0) (-5)` but as `(0) - (5)`. The `-` is not parsed as being part of the integer, but rather as a unary operator. – Conor O'Brien Feb 25 '19 at 19:54
  • 2
    @FlorianF You wouldn't, but that doesn't mean the parser should be special-cased to reject it. `float`s have methods, and `5.` is a `float`. – chepner Feb 25 '19 at 19:58
  • @ConorO'Brien The `-` would be parsed as a binary operator, not a unary one (if it were unary we'd have the same issue of two integers squished next to each other with no indication of what to do with them) – Delioth Feb 25 '19 at 20:15
  • @PeterMortensen Swift. Ending a numeric literal with a period is a compiler error. (`expected member name following '.'` for a lone `.`, or `use of unresolved operator '.-'` for `0.-5`) – Kevin Feb 25 '19 at 21:54
  • 1
    @PeterMortensen Plenty. In any OO language where integers can be treated as objects with methods (except JavaScript because in this, as in so many other aspects, JavaScript is horrendously broken and poorly designed) the parse for a float requires digits after the dot specifically so you don't end up with the ambiguity that jo_va pointed out. – Mason Wheeler Feb 25 '19 at 22:08
  • @Delioth my mistake, I meant binary. Thanks! – Conor O'Brien Feb 25 '19 at 22:24
  • 2
    You could add `5 .toString() // awesome` to the list :) – Salman A Feb 26 '19 at 08:55
  • 2
    @MasonWheeler It's certainly *not* the case that any other language where `(1).toMethod()` is legal prohibits `(1.)` from parsing properly. The most traditional approach to parsing (greedy lexing of tokens, including literals, then parsing) produces the Javascript behavior. – Sneftel Feb 26 '19 at 10:29
7

I would think that the real answer is not about the decimal point, but is about the minus sign: isn't that going to be interpreted as an operator if it is preceded by anything that looks like a number?

Sean_999
  • 79
  • 1
  • 1
    Then, at least in some point of view, it still *is* about the decimal point being interpreted as part of a number literal, otherwise what preceded the minus sign wouldn't "looks like a number". – Pac0 Feb 26 '19 at 01:19
5

console.log(0. - 5)      // -5
console.log(0 - 5)       // -5
console.log('0.' - 5)    // -5
console.log('0' - 5)     // -5
console.log(0.-5 === -5) // true

'0.' or '0' is the same in JavaScript because the type is unique for numbers, called Number. The minus operator is between Numbers, try always to convert what you pass to a Number. In Python is different first is a Float and the second an Integer because it has several types.

doppelgreener
  • 4,809
  • 10
  • 46
  • 63
Κωλζαρ
  • 803
  • 1
  • 10
  • 22