We can use the ‘L’ suffix to qualify any number with the intent of making it an explicit integer. So ‘0x10L’ creates the integer value 16 from the hexadecimal representation. The constant 1e3L gives 1000 as an integer rather than a numeric value and is equivalent to 1000L. (Note that the ‘L’ is treated as qualifying the term 1e3 and not the 3.) If we qualify a value with ‘L’ that is not an integer value, e.g. 1e-3L, we get a warning and the numeric value is created. A warning is also created if there is an unnecessary decimal point in the number, e.g. 1.L.

L specifies an integer type, rather than a double that the standard numeric class is.

1
2
3
4
> str(1)
 num 1
> str(1L)
 int 1

Most of the time it makes no difference - but sometimes you can use it to get your code to run faster and consume less memory. A double (“numeric”) vector uses 8 bytes per element. An integer vector uses only 4 bytes per element. For large vectors, that’s less wasted memory and less to wade through for the CPU (so it’s typically faster).

Mostly this applies when working with indices. Here’s an example where adding 1 to an integer vector turns it into a double vector:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
x <- 1:100
typeof(x) # integer

y <- x+1
typeof(y) # double, twice the memory size
object.size(y) # 840 bytes (on win64) 

z <- x+1L
typeof(z) # still integer
object.size(z) # 440 bytes (on win64) 

…but also note that working excessively with integers can be dangerous:

1
2
1e9L * 2L # Works fine; fast lean and mean!
1e9L * 4L # Ooops, overflow!