From d59b095af64105875b40801b6a8a310dae4cffff Mon Sep 17 00:00:00 2001 From: "Yang, Bo" Date: Sun, 26 Dec 2021 11:34:27 -0800 Subject: [PATCH 1/8] Move TrampolineContinuation to Dsl --- .../main/scala/com/thoughtworks/dsl/Dsl.scala | 26 ++++++++++++++ .../com/thoughtworks/dsl/keywords/Shift.scala | 34 +++---------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala b/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala index f77aea9d..bbc3a51a 100644 --- a/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala +++ b/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala @@ -126,6 +126,32 @@ object Dsl extends LowPriorityDsl0 { ) =:= Dsl[Keyword, Domain, Value] = summon + private[dsl] abstract class TrampolineContinuation[LeftDomain] + extends (LeftDomain !! Throwable) { + protected def step(): LeftDomain !! Throwable + + @tailrec + private final def last(): LeftDomain !! Throwable = { + step() match { + case trampoline: TrampolineContinuation[LeftDomain] => + trampoline.last() + case notTrampoline => + notTrampoline + } + } + + final def apply(handler: Throwable => LeftDomain): LeftDomain = { + val protectedContinuation: LeftDomain !! Throwable = + try { + last() + } catch { + case NonFatal(e) => + return handler(e) + } + protectedContinuation(handler) + } + } + trait IsStackSafe[Domain] object IsStackSafe extends IsStackSafe.LowPriority0: private[IsStackSafe] trait LowPriority0: diff --git a/keywords-Shift/src/main/scala/com/thoughtworks/dsl/keywords/Shift.scala b/keywords-Shift/src/main/scala/com/thoughtworks/dsl/keywords/Shift.scala index 80a99397..cca4547d 100644 --- a/keywords-Shift/src/main/scala/com/thoughtworks/dsl/keywords/Shift.scala +++ b/keywords-Shift/src/main/scala/com/thoughtworks/dsl/keywords/Shift.scala @@ -142,37 +142,11 @@ object Shift extends LowPriorityShift0 { } - private abstract class TrampolineContinuation[LeftDomain] - extends (LeftDomain !! Throwable) { - protected def step(): LeftDomain !! Throwable - - @tailrec - private final def last(): LeftDomain !! Throwable = { - step() match { - case trampoline: TrampolineContinuation[LeftDomain] => - trampoline.last() - case notTrampoline => - notTrampoline - } - } - - final def apply(handler: Throwable => LeftDomain): LeftDomain = { - val protectedContinuation: LeftDomain !! Throwable = - try { - last() - } catch { - case NonFatal(e) => - return handler(e) - } - protectedContinuation(handler) - } - } - private def suspend[LeftDomain, Value]( continuation: LeftDomain !! Throwable !! Value, handler: Value => LeftDomain !! Throwable - ): TrampolineContinuation[LeftDomain] = - new TrampolineContinuation[LeftDomain] { + ): Dsl.TrampolineContinuation[LeftDomain] = + new Dsl.TrampolineContinuation[LeftDomain] { protected def step() = continuation(handler) } @@ -192,8 +166,8 @@ object Shift extends LowPriorityShift0 { handler: Value => LeftDomain !! Throwable !! RightDomain, value: Value, continue: RightDomain => LeftDomain !! Throwable - ): TrampolineContinuation[LeftDomain] = - new TrampolineContinuation[LeftDomain] { + ): Dsl.TrampolineContinuation[LeftDomain] = + new Dsl.TrampolineContinuation[LeftDomain] { protected def step() = { handler(value)(continue) } From 7478d9241a71cba73c3aaa57af022168a0a689b7 Mon Sep 17 00:00:00 2001 From: "Yang, Bo" Date: Sun, 26 Dec 2021 15:52:27 -0800 Subject: [PATCH 2/8] Add TrampolineContinuation.apply --- Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala b/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala index bbc3a51a..e31764bf 100644 --- a/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala +++ b/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala @@ -151,6 +151,10 @@ object Dsl extends LowPriorityDsl0 { protectedContinuation(handler) } } + private[dsl] object TrampolineContinuation { + def apply[LeftDomain](continuation: TrampolineContinuation[LeftDomain]) = + continuation + } trait IsStackSafe[Domain] object IsStackSafe extends IsStackSafe.LowPriority0: From 0618ce34a92ceadff9c9f430a9fa1808f6017bf4 Mon Sep 17 00:00:00 2001 From: "Yang, Bo" Date: Sun, 26 Dec 2021 13:08:45 -0800 Subject: [PATCH 3/8] Add TrampolineFunction1 --- .../main/scala/com/thoughtworks/dsl/Dsl.scala | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala b/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala index e31764bf..c5c47466 100644 --- a/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala +++ b/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala @@ -125,22 +125,31 @@ object Dsl extends LowPriorityDsl0 { ) => Domain ) =:= Dsl[Keyword, Domain, Value] = summon - - private[dsl] abstract class TrampolineContinuation[LeftDomain] - extends (LeftDomain !! Throwable) { - protected def step(): LeftDomain !! Throwable - + private[dsl] abstract class TrampolineFunction1[-A, +R] extends (A => R) { + protected def step(): A => R @tailrec - private final def last(): LeftDomain !! Throwable = { + protected final def last(): A => R = { step() match { - case trampoline: TrampolineContinuation[LeftDomain] => + case trampoline: TrampolineFunction1[A, R] => trampoline.last() case notTrampoline => notTrampoline } } - final def apply(handler: Throwable => LeftDomain): LeftDomain = { + def apply(state: A): R = { + last()(state) + } + + } + object TrampolineFunction1 { + def apply[A, R](trampoline: TrampolineFunction1[A, R]) = trampoline + } + + private[dsl] abstract class TrampolineContinuation[LeftDomain] + extends TrampolineFunction1[Throwable => LeftDomain, LeftDomain] { + + override final def apply(handler: Throwable => LeftDomain): LeftDomain = { val protectedContinuation: LeftDomain !! Throwable = try { last() From 57b7ddaac3df386209c8e5d0f8c56faf3ed6925e Mon Sep 17 00:00:00 2001 From: "Yang, Bo" Date: Sun, 26 Dec 2021 15:52:38 -0800 Subject: [PATCH 4/8] Use trampoline in Suspend Dsl instances --- .../thoughtworks/dsl/keywords/Suspend.scala | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/keywords-Suspend/src/main/scala/com/thoughtworks/dsl/keywords/Suspend.scala b/keywords-Suspend/src/main/scala/com/thoughtworks/dsl/keywords/Suspend.scala index 32959b37..10e5df2f 100644 --- a/keywords-Suspend/src/main/scala/com/thoughtworks/dsl/keywords/Suspend.scala +++ b/keywords-Suspend/src/main/scala/com/thoughtworks/dsl/keywords/Suspend.scala @@ -1,6 +1,7 @@ package com.thoughtworks.dsl package keywords import Dsl.IsKeyword +import Dsl.!! import Dsl.cpsApply import scala.concurrent.Future import scala.concurrent.ExecutionContext @@ -17,19 +18,26 @@ object Suspend extends Suspend.LowPriority0 { upstreamIsKeyword: => IsKeyword[Upstream, UpstreamValue] ): IsKeyword[Suspend[Upstream], UpstreamValue] with {} - private[Suspend] trait LowPriority0: + private[Suspend] trait LowPriority1: given [Keyword, Domain, Value](using Dsl.Searching[Keyword, Domain, Value] ): Dsl.Composed[Suspend[Keyword], Domain, Value] = Dsl.Composed { (keyword: Suspend[Keyword], handler: Value => Domain) => keyword().cpsApply(handler) } + private[Suspend] trait LowPriority0 extends LowPriority1: + given [Keyword, State, Domain, Value](using + Dsl.Searching[Keyword, State => Domain, Value] + ): Dsl.Composed[Suspend[Keyword], State => Domain, Value] = Dsl.Composed { + (keyword: Suspend[Keyword], handler: Value => State => Domain) => + Dsl.TrampolineFunction1(() => keyword().cpsApply(handler)) + } - given [Keyword, State, Domain, Value](using - Dsl.Searching[Keyword, State => Domain, Value] - ): Dsl.Composed[Suspend[Keyword], State => Domain, Value] = Dsl.Composed { - (keyword: Suspend[Keyword], handler: Value => State => Domain) => value => - keyword().cpsApply(handler)(value) + given [Keyword, Domain, Value](using + Dsl.Searching[Keyword, Domain !! Throwable, Value] + ): Dsl.Composed[Suspend[Keyword], Domain !! Throwable, Value] = Dsl.Composed { + (keyword: Suspend[Keyword], handler: Value => (Domain !! Throwable)) => + Dsl.TrampolineContinuation(() => keyword().cpsApply(handler)) } given [Keyword, Result, Value](using From ff4dff6ea339c490e453ab3472bd5c901d1176dc Mon Sep 17 00:00:00 2001 From: "Yang, Bo" Date: Sun, 26 Dec 2021 17:47:47 -0800 Subject: [PATCH 5/8] Reuse TrampolineContinuation for exception handling in throwableContinuationDsl --- .../main/scala/com/thoughtworks/dsl/Dsl.scala | 35 ++++--------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala b/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala index c5c47466..a6a8e806 100644 --- a/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala +++ b/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala @@ -67,43 +67,20 @@ private[dsl] trait LowPriorityDsl1 { this: Dsl.type => private[dsl] trait LowPriorityDsl0 extends LowPriorityDsl1 { this: Dsl.type => -// // FIXME: Shift -// implicit def continuationDsl[Keyword, LeftDomain, RightDomain, Value]( -// implicit restDsl: Dsl.Original[Keyword, LeftDomain, Value], -// shiftDsl2: Dsl.Original[Shift[LeftDomain, RightDomain], LeftDomain, RightDomain] -// ): Dsl.Original[Keyword, LeftDomain !! RightDomain, Value] = { -// new Dsl.Original[Keyword, LeftDomain !! RightDomain, Value] { -// def cpsApply(keyword: Keyword, handler: Value => LeftDomain !! RightDomain): LeftDomain !! RightDomain = { -// (continue: RightDomain => LeftDomain) => -// restDsl.cpsApply(keyword, { a => -// restDsl2.cpsApply(handler(a), continue) -// }) -// } -// } -// } - private def throwableContinuationDsl[Keyword, LeftDomain, Value](implicit restDsl: Dsl.Searching[Keyword, LeftDomain, Value] ): Dsl[Keyword, LeftDomain !! Throwable, Value] = Dsl { - (keyword, handler) => continue => + (keyword, handler) => (continue: Throwable => LeftDomain) => restDsl( keyword, - // Use `new` to support the `return` - new (Value => LeftDomain) { - def apply(value: Value): LeftDomain = { - val protectedContinuation = - try { - handler(value) - } catch { - case NonFatal(e) => - return continue(e) - } - // FIXME: Shift[Domain, Throwable] - protectedContinuation(continue) - } + { value => + TrampolineContinuation { () => + handler(value) + }(continue) } ) } + given [Keyword, LeftDomain, Value](using Dsl.IsStackSafe[LeftDomain], Dsl.Searching[Keyword, LeftDomain, Value] From 227a683657fec5cd90d8dad89a134870f17d12f5 Mon Sep 17 00:00:00 2001 From: "Yang, Bo" Date: Sun, 26 Dec 2021 22:31:58 -0800 Subject: [PATCH 6/8] Let AsynchronousIo support any domains that support Lift[Unit, ?] --- build.sbt | 3 +- .../dsl/keywords/AsynchronousIo.scala | 43 ++++++++++--------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/build.sbt b/build.sbt index ec5083e7..59ad13a2 100644 --- a/build.sbt +++ b/build.sbt @@ -119,7 +119,8 @@ lazy val `keywords-AsynchronousIo` = crossProject(JSPlatform, JVMPlatform) .crossType(CrossType.Pure) .dependsOn( - `keywords-Shift`, + `keywords-Fence`, + `keywords-Shift` % Test, `keywords-Each` % Test, `keywords-Using` % Test, `domains-Task` % Test diff --git a/keywords-AsynchronousIo/src/main/scala/com/thoughtworks/dsl/keywords/AsynchronousIo.scala b/keywords-AsynchronousIo/src/main/scala/com/thoughtworks/dsl/keywords/AsynchronousIo.scala index 1e5e7f3d..53c9ccd1 100644 --- a/keywords-AsynchronousIo/src/main/scala/com/thoughtworks/dsl/keywords/AsynchronousIo.scala +++ b/keywords-AsynchronousIo/src/main/scala/com/thoughtworks/dsl/keywords/AsynchronousIo.scala @@ -147,29 +147,32 @@ object AsynchronousIo { } } - private def completionHandler[Value](successHandler: Value => (Unit !! Throwable)) = { - new CompletionHandler[Value, Throwable => Unit] { - def failed(exc: Throwable, failureHandler: Throwable => Unit): Unit = { - failureHandler(exc) - } + given [Domain, Value](using + fenceDsl: Dsl.Searching[Fence.type, Domain, Unit], + liftUnit: Dsl.Lift[Unit, Domain] + ): Dsl.Original[AsynchronousIo[Value], Domain, Value] = + Dsl.Original { (keyword, handler) => + liftUnit( + keyword.start( + handler, + new CompletionHandler[Value, Value => Domain] { + def failed( + exception: Throwable, + handler: Value => Domain + ): Unit = { + fenceDsl(Fence, (_: Unit) => throw exception) + } - def completed(result: Value, failureHandler: Throwable => Unit): Unit = { - val protectedContinuation = - try { - successHandler(result) - } catch { - case NonFatal(e) => - val () = failureHandler(e) - return + def completed( + result: Value, + handler: Value => Domain + ): Unit = { + fenceDsl(Fence, (_: Unit) => handler(result)) + } } - protectedContinuation(failureHandler) - } - } - } + ) + ) - given [Value]: Dsl.Original[AsynchronousIo[Value], Unit !! Throwable, Value] = - Dsl.Original { (keyword, handler) => - keyword.start(_, completionHandler(handler)) } } From 2f9bb309fa2ad3dc2b444952e8d697049f9e255c Mon Sep 17 00:00:00 2001 From: "Yang, Bo" Date: Sun, 26 Dec 2021 22:35:14 -0800 Subject: [PATCH 7/8] Remove derivedThrowableTailRecDsl --- .../main/scala/com/thoughtworks/dsl/Dsl.scala | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala b/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala index a6a8e806..b0b93275 100644 --- a/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala +++ b/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala @@ -375,42 +375,6 @@ object Dsl extends LowPriorityDsl0 { ): Dsl.Derived.StackUnsafe[Keyword, TailRec[Domain], Value] = Dsl.Derived.StackUnsafe(derivedTailRecDsl) - private def derivedThrowableTailRecDsl[Keyword, LeftDomain, Value](implicit - restDsl: Dsl.Searching[Keyword, LeftDomain !! Throwable, Value] - ): Dsl[Keyword, TailRec[LeftDomain] !! Throwable, Value] = - Dsl { - ( - keyword: Keyword, - handler: (Value => TailRec[LeftDomain] !! Throwable) - ) => (tailRecFailureHandler: Throwable => TailRec[LeftDomain]) => - TailCalls.done( - restDsl( - keyword, - { value => failureHandler => - handler(value) { e => - TailCalls.done(failureHandler(e)) - }.result - } - ) { e => - tailRecFailureHandler(e).result - } - ) - } - given [Keyword, LeftDomain, TailRecValue](using - Dsl.IsStackSafe[LeftDomain], - Dsl.Searching[Keyword, LeftDomain !! Throwable, TailRecValue] - ): Dsl.Derived.StackSafe[Keyword, TailRec[ - LeftDomain - ] !! Throwable, TailRecValue] = - Dsl.Derived.StackSafe(derivedThrowableTailRecDsl) - given [Keyword, LeftDomain, TailRecValue](using - util.NotGiven[Dsl.IsStackSafe[LeftDomain]], - Dsl.Searching[Keyword, LeftDomain !! Throwable, TailRecValue] - ): Dsl.Derived.StackUnsafe[Keyword, TailRec[ - LeftDomain - ] !! Throwable, TailRecValue] = - Dsl.Derived.StackUnsafe(derivedThrowableTailRecDsl) - private[dsl] type !![R, +A] = (A => R) => R @FunctionalInterface From 18cb5c1cdf99ebd92faa0163c3fc8f11bf6d5e20 Mon Sep 17 00:00:00 2001 From: "Yang, Bo" Date: Sun, 26 Dec 2021 23:45:45 -0800 Subject: [PATCH 8/8] Make Await generic WIP --- build.sbt | 1 + .../com/thoughtworks/dsl/keywords/Await.scala | 35 +++++--- .../src/main/scala/localdebug/test.scala | 82 +++++++++++++++++++ 3 files changed, 108 insertions(+), 10 deletions(-) create mode 100644 localDebug/src/main/scala/localdebug/test.scala diff --git a/build.sbt b/build.sbt index 59ad13a2..ed667087 100644 --- a/build.sbt +++ b/build.sbt @@ -152,6 +152,7 @@ lazy val `keywords-Await` = .dependsOn( Dsl, `domains-Continuation`, + `domains-Fence`, `macros-Reset` % Test, `domains-Task` % Test, `keywords-Get` % Test, diff --git a/keywords-Await/src/main/scala/com/thoughtworks/dsl/keywords/Await.scala b/keywords-Await/src/main/scala/com/thoughtworks/dsl/keywords/Await.scala index 7c8a1539..04af99d3 100644 --- a/keywords-Await/src/main/scala/com/thoughtworks/dsl/keywords/Await.scala +++ b/keywords-Await/src/main/scala/com/thoughtworks/dsl/keywords/Await.scala @@ -7,6 +7,7 @@ import scala.concurrent.Await.result import scala.concurrent.duration.Duration import scala.concurrent.{ExecutionContext, Future} import scala.language.implicitConversions +import scala.util.* /** [[Await]] is a [[Dsl.Keyword Keyword]] to extract value from a * [[scala.concurrent.Future]]. @@ -113,27 +114,41 @@ import scala.language.implicitConversions */ opaque type Await[+AwaitableValue] <: Dsl.Keyword.Opaque = Dsl.Keyword.Opaque.Of[AwaitableValue] -object Await extends AwaitJS { +object Await extends AwaitJS with Await.LowPriority0 { @inline def apply[AwaitableValue]: AwaitableValue =:= Await[AwaitableValue] = Dsl.Keyword.Opaque.Of.apply - given [FutureResult]: IsKeyword[Await[Future[FutureResult]], FutureResult] with {} + given [FutureResult]: IsKeyword[Await[Future[FutureResult]], FutureResult] + with {} given [FutureResult, That](using ExecutionContext - ): Dsl.Original[Await[Future[FutureResult]], Future[That], FutureResult] = Dsl.Original( - _ flatMap _) + ): Dsl.Original[Await[Future[FutureResult]], Future[That], FutureResult] = + Dsl.Original(_ flatMap _) // // TODO: // implicit def tailRecContinuationAwaitDsl[Value](implicit // executionContext: ExecutionContext // ): Dsl.Original[Await[Value], TailRec[Unit] !! Throwable, Value] + private[Await] trait LowPriority0: + inline given [Domain, Value](using + fenceDsl: Dsl.Searching[Fence.type, Domain, Unit], + liftUnit: Dsl.Lift[Unit, Domain], + executionContext: ExecutionContext, + ): Dsl.Composed[Await[Future[Value]], Domain, Value] = Dsl.Composed { + println(compiletime.codeOf( + {(x: Domain) => ()} + )) + + (keyword: Await[Future[Value]], handler: Value => Domain) => + keyword.onComplete { + case Failure(e) => + fenceDsl(Fence, (_: Unit) => throw e) + case Success(result) => + fenceDsl(Fence, (_: Unit) => handler(result)) + } + liftUnit(()) + } - given [Value](using - ExecutionContext - ): Dsl.Original[Await[Future[Value]], Unit !! Throwable, Value] = Dsl.Original { - (keyword: Await[Future[Value]], handler: Value => Unit !! Throwable) => - !!.fromTryContinuation[Unit, Value](keyword.onComplete)(handler) - } extension [FA, A](inline fa: FA)(using inline notKeyword: util.NotGiven[ FA <:< Dsl.Keyword diff --git a/localDebug/src/main/scala/localdebug/test.scala b/localDebug/src/main/scala/localdebug/test.scala new file mode 100644 index 00000000..908aff79 --- /dev/null +++ b/localDebug/src/main/scala/localdebug/test.scala @@ -0,0 +1,82 @@ +package localdebug + +import scala.concurrent.duration.Duration +import scala.concurrent.Future +import scala.concurrent.ExecutionContext.Implicits.given +import com.thoughtworks.dsl.Dsl +import com.thoughtworks.dsl.keywords.*, Match.+: +import com.thoughtworks.dsl.macros.Reset.Default.* + +@main +def test = { + val buffer = new StringBuffer + def recoverFuture = Future { + buffer.append("Oh") + } + def exceptionalFuture = Future[StringBuffer] { + throw new IllegalStateException("No") + } + val reified = reify[Char => Future[StringBuffer]] { + !Return(try { + !Await(exceptionalFuture) + } catch { + case e: IllegalStateException => + !Await(recoverFuture) + buffer.append(!Get[Char]) + buffer.append(e.getMessage) + } finally { + buffer.append("!") + }) + } + + summon[ + reified.type <:< + com.thoughtworks.dsl.keywords.Typed[com.thoughtworks.dsl.keywords.Suspend[ + com.thoughtworks.dsl.keywords.FlatMap[ + com.thoughtworks.dsl.keywords.TryCatchFinally[ + com.thoughtworks.dsl.keywords.Await[ + scala.concurrent.Future[StringBuffer] + ], + com.thoughtworks.dsl.keywords.Match.WithIndex[ + (0), + com.thoughtworks.dsl.keywords.FlatMap[ + com.thoughtworks.dsl.keywords.Await[ + scala.concurrent.Future[StringBuffer] + ], + com.thoughtworks.dsl.keywords.FlatMap[ + com.thoughtworks.dsl.keywords.Get[Char], + com.thoughtworks.dsl.keywords.Pure[StringBuffer] + ] + ] + ] + +: Nothing, + com.thoughtworks.dsl.keywords.Pure[Unit] + ], + com.thoughtworks.dsl.keywords.FlatMap[ + com.thoughtworks.dsl.keywords.Return[StringBuffer], + com.thoughtworks.dsl.keywords.Pure[ + Char => concurrent.Future[StringBuffer] + ] + ] + ] + ], Char => concurrent.Future[StringBuffer]] + ] + + def myFuture = summon[Dsl.Run[reified.type, Char => Future[ + StringBuffer + ], Char => Future[StringBuffer]]](reified) + + // def myFuture = reset[Char => Future[StringBuffer]](!Return { + // try { + // !Await(exceptionalFuture) + // } catch { + // case e: IllegalStateException => + // !Await(recoverFuture) + // buffer.append(!Get[Char]) + // buffer.append(e.getMessage) + // } finally { + // buffer.append("!") + // } + // }) + print(scala.concurrent.Await.result(myFuture(' '), Duration.Inf)) +}