&gt; We&#x27;re talking about performance here, right? So unfortunately this statement is totally untrue in that context.<p>You don&#x27;t need implementation details to discuss performance. Abstractions can come with a cost model. (C++&#x27;s standard library concepts are a great example of this.) And Haskell&#x27;s cost model says that values can be passed around in O(1) time.<p>&gt; Java world wants value types largely to avoid pointer chasing that hurts cpu cache effectiveness. Haskell suffers the same issue, then.<p>That&#x27;s not the whole story. When the physical identity of an object no longer matters (note that immutability alone isn&#x27;t enough), the language implementation can, <i>without programmer intervention</i>:<p>(0) Merge several small objects into a single large object. (Laziness kind of gets in the way, though. ML fares better in this regard.)<p>(1) Use hash consing or the flyweight pattern more aggressively.<p>&gt; You can make what are effectively value types in Java as long as you don&#x27;t use == to compare but rather .equals, make all the fields final, override toString&#x2F;equals&#x2F;hashcode etc, and more sensible JVM targeting languages of course convert == into calls to .equals by default.<p>But the JVM itself is completely unaware that you intend to use a class as a value type, and thus can&#x27;t automatically apply optimizations that are no-brainers in runtime systems for languages where all types are value types.<p>Also, `.equals()`&#x27;s type is broken: it allows you to compare any pair of `Object`s, but it should only allow you to compare objects of the same class.