5 ms·
Many http://cr.openjdk.java.net/~jrose/values/values-0.html http://cr.openjdk.java.net/~jrose/values/values-0.html
by valarauca1 9y ago
Many
http://cr.openjdk.java.net/~jrose/values/values-0.html http://cr.openjdk.java.net/~jrose/values/values-0.html
- bluejekyll 9y agoTuples! Finally. > Finalization. Finalization makes no sense for values and should be disallowed (though values may hold reference-typed components that are themselves finalizable.) This is a little disappointing. I was hoping that the lifetime of essentially stack based variables could be tracked, and finalization could be bound to the stack. That would be really powerful; though mind bending after beating so many Devs to not rely on finalization. Imagine wrapping a Closable object in a Closing tuple for instance, and that is guaranteed to run when the tuple goes out of scope.
- clhodapp 9y agoAt first reading, that sounds nigh-impossible to get right in a world where values on the stack can be closed over.
- haimez 9y agoAnd voila, rust.
- clhodapp 9y agoExactly! Now let's just amend the value types proposal to include ownership tracking! Should be simple, right?
- _old_dude_ 9y agoThe Value Types proposed in TFA are immutable so no need to have a borrow checker for them :)
- clhodapp 9y agoYou wouldn't need such a sophisticated tracker as Rust has because the implementation here rules out mutable borrows but you'd still need something that looked like ownership tracking or something that looked like garbage collection to correctly implement finalizers on value classes in the face of closure, right? When you close over a stack-allocated immutable value, the low-level effect is that you make a copy of it onto the heap, I'd think. However, at higher-level, you create another reference whose lifespan staves off finalization, no? Edit: I'll add that it's possible that the proper implementation for even a bog-standard, assign-to-a-variable copying would need to work this way (make another finalization-delaying handle) but I think that's less-certainly true.
- dkersten 9y agoClosing over value types could capture by value and make a copy, like you would typically do in C++ when capturing values in lambdas. Of course, since value types are immutable, that would be a bit memory wasteful I guess.
- clhodapp 9y agoYep. But how would you correctly deal with finalizers in the face of those copies? See my comment a bit deeper in the thread.
- dkersten 9y agoYeah, you're right. I guess it doesn't typically make sense to capture a RAII object and have the copy outlive the original, but it also may not make sense to delay the lifecycle of the original since it breaks the expectation of "i put this on the stack, so expect it to finalize when it goes out of scope". Probably best not to mix the two. That is, a stack-allocated RAII object whose finalizer is called when it goes out of scope, which references some data that can be closed over, with a lifetime separate from the RAII object. At the very least, you would call finalizers on both (the stack one when it goes out of scope and the copy when it gets garbage collected) and then its up to the programmer to make sure that shared resources are finalized correctly (eg by keeping a shared reference count...). (I'm thinking a use case where the object represents some external resource that should be freed only once) Sounds pretty error prone though. I suppose that Java's solution is KISS: simply don't support finalizers on value objects.
- barrkel 9y agoThe copy would be living on a heap object only reachable via the interface reference the lambda implements. Deterministic finalization of that copy would be a Hard Problem.
- pseudoramble 9y agoThis was handy to glance through. Thanks! I did notice one point that struck me as odd (under "Details, details"): > Can a value class implement interfaces? Yes. Boxing may occur when we treat a value as an interface instance. I don't normally think of values in other languages as having methods directly or an interface like this. I wonder what the primary reasons for this would be. Backwards compatibility might be one reason.
- taspeotis 9y agoC# permits it but it's not completely intuitive [1]. As to why, it has some benefits, like letting all types (value or otherwise) implement IComparable, IEquatable, IFormattable etc. [1] https://blogs.msdn.microsoft.com/abhinaba/2005/10/05/c-structs-and-interface/ https://blogs.msdn.microsoft.com/abhinaba/2005/10/05/c-struc...
- pjmlp 9y agoA few examples are D, C#, VB, F#, Eiffel, Delphi, C++, Rust.
- pseudoramble 9y agoThanks for the examples. Seems clear that I don't fully understand it then, but it's good to know that it's common so I can look around some more.
- runeks 9y ago> I don't normally think of values in other languages as having methods directly or an interface like this. If I understand you correctly, Haskell has this, and it's basically all you have to implement generic interfaces in Haskell. A simple example is the Bounded class, whose interface exposes two functions: minBound and maxBound. So, for example, all integers (int8, uint8, int16, uint16, [...], uint64) have upper and lower bounds, and can implement this interface, like so (Word8 is uint8): instance Bounded Word8 where minBound = 0 maxBound = 255 This forces all instances of a class to be a type that contains all information needed to implement the interface (as opposed to some construct that needs to accumulate state at runtime in order for it to work properly), which means the compiler can check almost everything at compile-time. This is where monads come in, which is simply a value that describes a computation, e.g. fetching a value of a specific type from a web server at a given URL. So, in Haskell, all that exists are values, and they're also used to represent an operation which, at runtime, performs a certain action. So, for example, the following function: concatStr :: String -> String -> String is a pure function which only modifies it's two arguments (String and String) and produces a String, whereas printReadStdIn :: String -> IO String printReadStdIn str = do putStrLn str getLine is a function which, when given a String, will -- at runtime -- print out a String and read a String from standard input, and this String will be available inside the IO monad (which can implement interfaces, because it's just a value).