3 ms·
> However, these types (excepting unboxed types) can also be considered reference types since that is how values are passed. This is an implementation detail,
by 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.
- eru 11y ago> And Haskell's cost model says that values can be passed around in O(1) time. I am not sure of that. The compiler is free to inline expressions, or otherwise evaluate them multiple times.
- sievebrain 11y agoI know what optimisations identity-less aggregates allow. Objects can be passed around in O(1) time in any language that uses references. It's not the issue. Indeed passing value types is O(n) in the size of the value type, so that's a loss. The goal is to avoid data dependent loads (i.e. pointer dereferences) by flattening/inlining data structures. As you point out, Haskell could in theory merge things together and lay out memory more effectively, but in theory so could Java with e.g. interprocedural escape analysis. But in practice there's a limit to what automatic compiler optimisations can do - learning this the hard way is a big part of the history of functional languages (like, how many functional language runtimes automatically parallelise apps with real speedups?). Java sometimes does convert object allocations into value types via the scalarisation optimisations, but not always, hence the desire to add it to the language.