Search code examples
pythonjavac++computer-science

The definition of the literal


When we do some operation on a variable, we just change pointer to another literal? I am a bit confused understanding the exact meaning of the term 'literal'.

Suppose we have int x = 3; // 3 is literal and immutable , x is variable

Doing operation for ex: x++

And now x == 4; so our var x is just pointing to a new literal. Does the computer just remember that 3 + 1 is 4?


Solution

  • x isn't a pointer.

    The JVM spec just says what happens; how it happens is intentionally not specified. So, this answer merely explains how it works on all JVMs I'm aware of. Almost as good. It should certainly clarify matters:

    class Example {
      int x = 3;
    
      void foo() {
        x++;
      }
    }
    

    Here, any time new Example() is executed, some block of memory is reserved for this instance. An instance of an object is simply a block of memory that holds its basic properties (including that this is an object of type Example) and room to store the value of every non-static field. In this case, int x - that's a non-static field.

    Primitives are special data types: It's a hard coded list: int, long, short, byte, double, float, boolean, and char. That's it. That's the whole list, you can't add any new types. They are 'special' - any value of a primitive type is just the value. not a pointer.

    Thus, int x = 3 means that any attempt to make a new Example instance (new Example()) will, as mentioned, reserve some space in memory to store the value of the x field, and that value is directly 3. It's not 'a pointer to a 3 object'. It's just.. 3. It'll take at least 32-bits (as int is 32 bits), it might effectively take 64 (CPUs pretty much require that objects are nicely aligned: That they start on a value that is divisible by 64, on 64-bit CPUs).

    x++ simply finds that memory position with the bit sequence 0000....0000011 (0011 is binary for '3'), and increments it, turning that into 0000....0000100.

    In contrast, let's try with an object - anything that isn't on that list of primitives is an object, and all such values are pointers. (In java speak, 'references'). So, in this very slightly changed code:

    class Example {
      Integer x = 3;
    
      void foo() {
        x++;
      }
    }
    

    Something very very different is going on. For starters, auto-boxing: That is syntax sugar and is compiled as if you wrote:

    class Example {
      Integer x = Integer.valueOf(3);
    
      void foo() {
        x = Integer.valueOf(x.intValue() + 1);
      }
    }
    

    Why? Because the JLS says so - that's what happens when you try to x++ where x is a non-primitive type, but, is autoboxable to an int.

    So, what happens here? Who knows? Who cares - the code of valueOf does what it does. It acts as the spec says it acts, it's generally not useful to ask how. But, if you're interested:

    Integer (the class), upon loading (which it always will, as its such a core class) creates a 'cache', and makes 1 Integer object for each value between -128 and +127. Integer.valueOf will return you the value from the cache if possible (i.e. the argument you pass to it is between -128 and +127) otherwise it creates a new Integer object. Given that 3 and 4 fit, you get something like this:

    package java.lang;
    
    public class Integer {
      private static final Integer[] cache = new Integer[255];
    
      static {
        for (int i = 0; i < 256; i++) {
          cache[i] = new Integer(i - 128);
        }
      }
    
      public static Integer valueOf(int v) {
        if (v >= -128 && v <= 127) return cache[v + 128];
        return new Integer(v);
      }
    
      private final int value;
    
      public Integer(int v) {
        this.value = v;
      }
    
      public int intValue() {
        return v;
      }
    }
    

    x + 1 in java works because the spec says so. It doesn't have some lookup table that says '3 + 1 is 4', the concept of adding is baked into CPUs. Forget about pointers and such, computers are binary so numbers can only exist strictly in terms of zeroes and ones. Hence, even -1 is tricky (there's no '-'. Just zeroes and ones!). However, just because a number is stored in binary doesn't mean that adding is somehow impossible.

    Given, say, 5 and 9:

    • 5 = 00000101 in binary
    • 9 = 00001001 in binary

    to add them, you do the same thing you'd do when adding 2 decimal numbers. Add each element and make sure to carry any excess. So:

    • the final digits are 1 and 1. Add those together: That's 0, carry the 1. We have: ???????0
    • The next two digits are 0 and 0. But we did have that carry, so, that's a 1. So far, we're at ??????10.
    • The 3rd digit from the left is 1 and 0. Add em up, that's a 1. We're at ?????110.

    ... and so on. Arriving at 00001110. There is no need for lookup tables to do this. Just a repeated application of this trivial table:

    carry-in digit1 digit2 output carry
    0 0 0 0 0
    0 1 0 1 0
    0 0 1 1 0
    0 1 1 0 1
    1 0 0 1 0
    1 1 0 0 1
    1 0 1 0 1
    1 1 1 1 1

    That logic (that 'table' + the logic to repeatedly apply it to every digit) is baked into the silicon of your CPU.