4 ms·
To a Haskeller, you could explain Java-style reference types by saying “it's an artificial limitation whereby every value is behind an IORef, and the value itse
by catnaroek 11y ago
To a Haskeller, you could explain Java-style reference types by saying “it's an artificial limitation whereby every value is behind an IORef, and the value itself isn't a first-class entity”. But Haskell itself doesn't have this artificial limitation, and every type is a value type.
- jstimpfle 11y agoIn Haskell, since it is a pure language, every type is a value type in the sense that you can pass around values without worrying that callees might overwrite your data. However, these types (excepting unboxed types) can also be considered reference types since values are technically passed by reference. Boxed values are stored in thunks, and only accessed through these (at least conceptually). Thunks in turn have GC overhead. Boxed values have even associated internal state, but there is not much control over it: the state of their evaluation. So another viewpoint is that boxed Haskell types are just like Java reference types, but from the outside they seem immutable.
- catnaroek 11y ago> However, these types (excepting unboxed types) can also be considered reference types since that is how values are passed. This is an implementation detail, and abstractions shall never be conflated with their possible implementations. What matters to the user of the abstraction is that you're passing around (a computation[0] that evaluates to) the value itself, not some mutable entity whose current state is the value. > So another viewpoint is that boxed Haskell types are just like Java reference types, but they are immutable. This is wrong. In Java, all objects have a distinct identity, so, for instance, `new Complex(2,3) == new Complex(2,3)` evaluates to `false`, even if both objects represent the complex number `2+3i`. [0] Since Haskell is non-strict.
- jstimpfle 11y agoYeah as I said it's a viewpoint. The viewpoint I meant is the technical (and performance-centric) one, not the mathematical one.
- catnaroek 11y ago> The viewpoint I meant is the technical My objection was also a technical one: Haskell doesn't give you access to the physical identity of any runtime object that isn't a reference cell (`IORef`, `STRef`, `MVar`, `TVar`, etc.). > (and performance-centric) one The ability to pass around arbitrarily complicated values in O(1) time is an intrinsic part of Haskell's cost model. This is the most natural thing in the world, unless you've lived all your life subordinating values to object identities, in which case, yes, non-destructively transferring a value from one object identity to another (aka “deep cloning”) might be an arbitrarily expensive operation.
- sievebrain 11y agoThis is an implementation detail, and abstractions shall never be conflated with their possible implementations We're talking about performance here, right? So unfortunately this statement is totally untrue in that context. Java world wants value types largely to avoid pointer chasing that hurts cpu cache effectiveness. Haskell suffers the same issue, then. You can make what are effectively value types in Java as long as you don't use == to compare but rather .equals, make all the fields final, override toString/equals/hashcode etc, and more sensible JVM targeting languages of course convert == into calls to .equals by default.
- catnaroek 11y ago> We're talking about performance here, right? So unfortunately this statement is totally untrue in that context. You don't need implementation details to discuss performance. Abstractions can come with a cost model. (C++'s standard library concepts are a great example of this.) And Haskell's cost model says that values can be passed around in O(1) time. > Java world wants value types largely to avoid pointer chasing that hurts cpu cache effectiveness. Haskell suffers the same issue, then. That's not the whole story. When the physical identity of an object no longer matters (note that immutability alone isn't enough), the language implementation can, without programmer intervention: (0) Merge several small objects into a single large object. (Laziness kind of gets in the way, though. ML fares better in this regard.) (1) Use hash consing or the flyweight pattern more aggressively. > You can make what are effectively value types in Java as long as you don't use == to compare but rather .equals, make all the fields final, override toString/equals/hashcode etc, and more sensible JVM targeting languages of course convert == into calls to .equals by default. But the JVM itself is completely unaware that you intend to use a class as a value type, and thus can't automatically apply optimizations that are no-brainers in runtime systems for languages where all types are value types. Also, `.equals()`'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.
- jstimpfle 11y agoWhat you say is not incorrect. But you totally miss the context of the discussion. And you switch sides just to disagree with your last quote.