Loom on Scala

Alex Otenko oleksandr.otenko at gmail.com
Sat Nov 27 22:14:40 UTC 2021


Scala Stream.map(_.get) will cause the same grief as you encountered in
Java. So it's not a problem specific to Java, it is lazy evaluation in
general, and that closures can make things outlive their syntactic scope.

Alex

On Sat, 27 Nov 2021, 21:03 Eric Kolotyluk, <eric at kolotyluk.net> wrote:

> Alex was right, Using.Manager was consuming the exception. The better
> solution is
>
> object HelloScala {
>   def main(args: Array[String]) {
>     Context.printHeader(HelloScala.getClass)
>
>     val results =
>       Using(StructuredExecutor.open("HelloScala")) { structuredExecutor =>
>         val futureResults = (0 to 15).map { item =>
>           println(s"item = $item, Thread ID = ${Thread.currentThread}")
>           structuredExecutor.fork { () =>
>             println(s"\ttask = $item, Thread ID = ${Thread.currentThread}")
>             item
>           }
>         }
>         structuredExecutor.join
>         futureResults.map(_.get)
>       }
>
>     println(results)
>   }
> }
>
> Which outputs either
>
> Success(Vector(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))
> or
> Failure(java.lang.IllegalStateException: Owner did not invoke join or
> joinUntil)
>
> Depending on if join() is called.
>
> Alex, map(_.get) works fine because get() will wait for the value to
> become available, while resultNow() won't.
>
> I am somewhat disappointed that Using consumes the exception rather than
> letting it be caught in a try block, but it does return the exception as a
> Scala Try result of either Success or Failure, which I can live with.
> Still, this is not intuitive.
>
> It is interesting to note that IMHO the Scala code is aesthetically more
> beautiful than the equivalent Java code, but Java has a stronger commitment
> to safety and backward compatibility which creates challenges to good
> aesthetics.
>
> Is there a JEP on extending Java collections to support monadic operators
> such as map()? After this experience, I now feel that Java Stream creates
> dangerous situations that are not intuitive to troubleshoot, and it would
> be nice if Java Collections had the same functionality as Kotlin and Scala
> Collections.
>
> Cheers, Eric
>
>
> On Fri, Nov 26, 2021 at 11:41 PM Alex Otenko <oleksandr.otenko at gmail.com>
> wrote:
>
>> Most likely Scala's try-with-resource catches and handles the exception
>> during close()
>>
>> Same with map(_.get) vs map(Future::resultNow) - the difference is only
>> in who's waiting and what kind of exception is thrown, so if Scala handles
>> checked exceptions for you, you aren't inconvenienced.
>>
>> Alex
>>
>> On Sat, 27 Nov 2021, 07:19 Eric Kolotyluk, <eric at kolotyluk.net> wrote:
>>
>>> package net.kolotyluk.loom
>>>
>>> import java.util.concurrent.StructuredExecutor
>>> import scala.util.Using
>>>
>>> object HelloScala {
>>>   def main(args: Array[String]) {
>>>     Context.printHeader(HelloScala.getClass)
>>>
>>>     Using.Manager { use => // Scala's version of try-with-resources
>>>       val structuredExecutor = use(StructuredExecutor.open("HelloScala"))
>>>
>>>       val futureResults = (0 to 15).map{ item =>
>>>         println(s"item = $item, Thread ID = ${Thread.currentThread}")
>>>         structuredExecutor.fork{ () =>
>>>           println(s"\ttask = $item, Thread ID = ${Thread.currentThread}")
>>>           item
>>>         }
>>>       }
>>>       println(futureResults.map(_.get))
>>>       structuredExecutor.join
>>>     }
>>>   }
>>> }
>>>
>>> Yes, Loom does run on Scala 2.13... I cannot get Scala 3 to work with
>>> Maven
>>> yet... might have to resort to SBT... ��
>>>
>>> I wonder if ScopeLocal works correctly in Scala? �� I guess it should...
>>>
>>> Don't have to worry about lazy Stream termination here ��
>>>
>>> Don't need Future::resultNow either
>>>
>>> For some reason, if you don't call join(), close() does not throw an
>>> exception �� -- that's not right?
>>>
>>> The Kotlin version was much harder to write and I will post later...
>>>
>>> A fun way to end the week... ��
>>>
>>> Cheers, Eric
>>>
>>>
>>> "C:\Program Files (Open)\jdk-18\bin\java.exe" --enable-preview
>>> -Dfile.encoding=windows-1252 -jar
>>> C:\Users\ERIC\Documents\git\loom-lab\laboratory\target\laboratory.jar
>>> Hello net.kolotyluk.loom.HelloScala$
>>> PID       = 23312
>>> CPU Cores = 12
>>> Heap Size = 6442450944 bytes
>>>
>>> ______________________________________________________________________________
>>>
>>> item = 0, Thread ID = Thread[#1,main,5,main]
>>> item = 1, Thread ID = Thread[#1,main,5,main]
>>> item = 2, Thread ID = Thread[#1,main,5,main]
>>> item = 3, Thread ID = Thread[#1,main,5,main]
>>> item = 4, Thread ID = Thread[#1,main,5,main]
>>> item = 5, Thread ID = Thread[#1,main,5,main]
>>> item = 6, Thread ID = Thread[#1,main,5,main]
>>> item = 7, Thread ID = Thread[#1,main,5,main]
>>> item = 8, Thread ID = Thread[#1,main,5,main]
>>> item = 9, Thread ID = Thread[#1,main,5,main]
>>> item = 10, Thread ID = Thread[#1,main,5,main]
>>> item = 11, Thread ID = Thread[#1,main,5,main]
>>> item = 12, Thread ID = Thread[#1,main,5,main]
>>>      task = 0, Thread ID =
>>> VirtualThread[#15]/runnable at ForkJoinPool-1-worker-1
>>> item = 13, Thread ID = Thread[#1,main,5,main]
>>> item = 14, Thread ID = Thread[#1,main,5,main]
>>>      task = 1, Thread ID =
>>> VirtualThread[#17]/runnable at ForkJoinPool-1-worker-2
>>>      task = 2, Thread ID =
>>> VirtualThread[#18]/runnable at ForkJoinPool-1-worker-3
>>>      task = 4, Thread ID =
>>> VirtualThread[#20]/runnable at ForkJoinPool-1-worker-3
>>>      task = 5, Thread ID =
>>> VirtualThread[#22]/runnable at ForkJoinPool-1-worker-2
>>>      task = 7, Thread ID =
>>> VirtualThread[#24]/runnable at ForkJoinPool-1-worker-2
>>>      task = 6, Thread ID =
>>> VirtualThread[#23]/runnable at ForkJoinPool-1-worker-3
>>>      task = 8, Thread ID =
>>> VirtualThread[#25]/runnable at ForkJoinPool-1-worker-3
>>>      task = 9, Thread ID =
>>> VirtualThread[#27]/runnable at ForkJoinPool-1-worker-2
>>>      task = 3, Thread ID =
>>> VirtualThread[#19]/runnable at ForkJoinPool-1-worker-4
>>>      task = 10, Thread ID =
>>> VirtualThread[#28]/runnable at ForkJoinPool-1-worker-3
>>>      task = 11, Thread ID =
>>> VirtualThread[#29]/runnable at ForkJoinPool-1-worker-2
>>>      task = 12, Thread ID =
>>> VirtualThread[#31]/runnable at ForkJoinPool-1-worker-4
>>>      task = 13, Thread ID =
>>> VirtualThread[#34]/runnable at ForkJoinPool-1-worker-5
>>> item = 15, Thread ID = Thread[#1,main,5,main]
>>>      task = 14, Thread ID =
>>> VirtualThread[#35]/runnable at ForkJoinPool-1-worker-5
>>>      task = 15, Thread ID =
>>> VirtualThread[#42]/runnable at ForkJoinPool-1-worker-11
>>> Vector(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
>>>
>>> Process finished with exit code 0
>>>
>>


More information about the loom-dev mailing list