Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Bracket type class #113

Merged
merged 56 commits into from
Apr 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
a318a4c
Add initial bracket
Jan 10, 2018
1b8f273
Quick update
Jan 10, 2018
1f12aba
Add discipline bracket tests
Jan 12, 2018
75d8a43
Use Option for left side
Jan 12, 2018
a479184
Initial implementation WIP for EitherT and OptionT
Jan 14, 2018
8ffffcd
Move to ADT
Jan 15, 2018
e507a3a
Make Bracketresult abstract class
Jan 15, 2018
f2ee74f
Add Writer and State instances
Jan 15, 2018
3bb2106
Merge branch 'master' into add-bracket
Jan 18, 2018
43f5488
Merge branch 'master' into add-bracket
Jan 18, 2018
5e7119e
Laws
Jan 18, 2018
5fa474e
Merge branch 'add-bracket' of https://github.com/LukaJCB/cats-effect …
Jan 18, 2018
e4cc1fa
Fix 2.10 compiler error
Jan 18, 2018
4c2bea6
Remove equivalence law
Jan 21, 2018
595b1b0
Add extra law
Jan 25, 2018
cb53957
Add Test that checks if release is called no matter what use does
Jan 25, 2018
db757aa
Add Mima exceptions
Jan 25, 2018
87e2cec
Remove result type from bracketresult
Jan 31, 2018
96538fd
Revert "Remove result type from bracketresult"
Jan 31, 2018
859d50f
Merge branch 'add-bracket' of https://github.com/LukaJCB/cats-effect …
alexandru Feb 25, 2018
45edf70
Change Bracket
alexandru Feb 25, 2018
e3e730e
Merge pull request #1 from alexandru/add-bracket
Mar 1, 2018
e88bef3
Merge branch 'master' into add-bracket
Mar 1, 2018
6c41b50
Remove type lambda and add back flattap
Mar 5, 2018
0bd2149
Merge branch 'umaster' into add-bracket
Mar 9, 2018
d91060e
Raise exception when canceled during bracket
Mar 9, 2018
54e176c
Fix IO.bracket and use american spelling
Mar 16, 2018
590e6bd
Merge branch 'umaster' into add-bracket
Mar 16, 2018
7a38584
Move Bracket implementation to internals
Mar 20, 2018
1f2b8b2
Formatting
Mar 20, 2018
b994d83
Don't call fa twice in bracketReleaseLaw
Mar 20, 2018
6838b7e
Add law that describes what happens when both use and release fail
Mar 22, 2018
596c17a
Make law more generic
Mar 22, 2018
e26f667
Add first draft for Bracket-Concurrent law
Mar 22, 2018
05fd2e6
Merge branch 'master' into add-bracket
Mar 27, 2018
eadba2f
Use rightCast
Mar 27, 2018
d3b7879
Merge branch 'add-bracket' of https://github.com/LukaJCB/cats-effect …
Mar 27, 2018
a82d3fc
BracketResult final
Apr 1, 2018
c70cdec
Merge remote-tracking branch 'upstream/master' into LukaJCB-add-bracket
alexandru Apr 15, 2018
7a2b91b
Bracket changes
alexandru Apr 15, 2018
b6aebec
Fix sample to use IO instead of Task
alexandru Apr 15, 2018
e6c524c
Merge pull request #2 from alexandru/LukaJCB-add-bracket
Apr 15, 2018
00d6f5b
Fix MiMa errors
alexandru Apr 15, 2018
09f83c5
Add mima exception
Apr 15, 2018
646ec4c
Merge branch 'add-bracket' of https://github.com/LukaJCB/cats-effect …
Apr 15, 2018
05032dd
Merge branch 'add-bracket' of https://github.com/LukaJCB/cats-effect …
alexandru Apr 15, 2018
cd9c318
Rename bracketE -> bracketCase; add microsite documentation
alexandru Apr 15, 2018
796c519
Rename laws
alexandru Apr 15, 2018
aab8173
Merge pull request #3 from alexandru/LukaJCB-add-bracket2
Apr 15, 2018
8a4b74f
Merge branch 'master' into add-bracket
Apr 15, 2018
f536d79
Add mima exception for missing eitherT eval
Apr 15, 2018
84edccd
Merge branch 'add-bracket' of https://github.com/LukaJCB/cats-effect …
Apr 15, 2018
28a05b4
Typo
Apr 15, 2018
008f29f
More Mima exceptions
Apr 15, 2018
596f0cd
Make ExitCase serializable
Apr 15, 2018
5bbbea7
Add product
Apr 16, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 18 additions & 68 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ val commonSettings = Seq(
val mimaSettings = Seq(
// Setting the previous artifact manually at 0.9
// as a temporary measure until we release 0.10
mimaPreviousArtifacts := Set(organization.value %% name.value % "0.9"),
mimaPreviousArtifacts := Set(organization.value %% name.value % "0.10"),
/*
mimaPreviousArtifacts := {
val TagBase = """^(\d+)\.(\d+).*"""r
Expand All @@ -156,73 +156,23 @@ val mimaSettings = Seq(
import com.typesafe.tools.mima.core._
import com.typesafe.tools.mima.core.ProblemFilters._
Seq(
// Not a problem: AsyncInstances is a private class, we just moved those
// directly in the companion object.
//
// Manually checked:
// - catsEitherTAsync
// - catsOptionTAsync
// - catsStateTAsync
// - catsWriterTAsync
exclude[MissingClassProblem]("cats.effect.AsyncInstances"),
// Not a problem: AsyncInstances is a private class, WriterTAsync too
exclude[MissingClassProblem]("cats.effect.AsyncInstances$WriterTAsync"),
// Not a problem: AsyncInstances is a private class, OptionTAsync too
exclude[MissingClassProblem]("cats.effect.AsyncInstances$OptionTAsync"),
// Not a problem: AsyncInstances is a private class, EitherTAsync too
exclude[MissingClassProblem]("cats.effect.AsyncInstances$EitherTAsync"),
// Not a problem: AsyncInstances is a private class, StateTAsync too
exclude[MissingClassProblem]("cats.effect.AsyncInstances$StateTAsync"),
//
// Not a problem: EffectInstances is a private class and we just moved
// those in the companion object.
//
// Manual check for:
// - catsEitherTEffect
// - catsStateTEffect
// - catsWriterTEffect
// - catsWriterTEffect
exclude[MissingClassProblem]("cats.effect.EffectInstances"),
// Not a problem: Missing private traits being inherited
exclude[MissingTypesProblem]("cats.effect.Effect$"),
//
// Not a problem: SyncInstances is a private class, we just moved those
// directly in the companion object.
//
// Manual check for:
// - catsEitherTEvalSync
// - catsEitherTSync
// - catsOptionTSync
// - catsStateTSync
// - catsWriterTSync
exclude[MissingClassProblem]("cats.effect.SyncInstances"),
// Not a problem: no longer implementing private traits
exclude[MissingTypesProblem]("cats.effect.Sync$"),
// Not a problem: SyncInstances and StateTSync are private.
exclude[MissingClassProblem]("cats.effect.SyncInstances$StateTSync"),
// Not a problem: SyncInstances and OptionTSync
exclude[MissingClassProblem]("cats.effect.SyncInstances$OptionTSync"),
// Not a problem: SyncInstances and EitherTSync
exclude[MissingClassProblem]("cats.effect.SyncInstances$EitherTSync"),
// Not a problem: SyncInstances and WriterTSync are private
exclude[MissingClassProblem]("cats.effect.SyncInstances$WriterTSync"),
//
// Not a problem: LiftIOInstances is a private class, we just moved
// those directly in the companion object.
//
// Manual check for:
// - catsEitherTLiftIO
// - catsKleisliLiftIO
// - catsOptionTLiftIO
// - catsStateTLiftIO
// - catsWriterTLiftIO
exclude[MissingTypesProblem]("cats.effect.LiftIO$"),
exclude[MissingClassProblem]("cats.effect.LiftIOInstances"),
exclude[MissingClassProblem]("cats.effect.LiftIOInstances$OptionTLiftIO"),
exclude[MissingClassProblem]("cats.effect.LiftIOInstances$KleisliLiftIO"),
exclude[MissingClassProblem]("cats.effect.LiftIOInstances$EitherTLiftIO"),
exclude[MissingClassProblem]("cats.effect.LiftIOInstances$StateTLiftIO"),
exclude[MissingClassProblem]("cats.effect.LiftIOInstances$WriterTLiftIO"),
exclude[DirectMissingMethodProblem]("cats.effect.Sync#StateTSync.map"),
exclude[IncompatibleMethTypeProblem]("cats.effect.Sync#StateTSync.map"),
exclude[InheritedNewAbstractMethodProblem]("cats.effect.Bracket.bracket"),
exclude[InheritedNewAbstractMethodProblem]("cats.effect.Bracket.bracketCase"),
exclude[ReversedMissingMethodProblem]("cats.effect.Sync#OptionTSync.bracketCase"),
exclude[ReversedMissingMethodProblem]("cats.effect.Sync#WriterTSync.bracketCase"),
exclude[ReversedMissingMethodProblem]("cats.effect.Sync#StateTSync.bracketCase"),
exclude[ReversedMissingMethodProblem]("cats.effect.Sync#EitherTSync.bracketCase"),
exclude[ReversedMissingMethodProblem]("cats.effect.Sync#KleisliSync.bracketCase"),
exclude[MissingClassProblem]("cats.effect.internals.AndThen"),
exclude[MissingClassProblem]("cats.effect.internals.AndThen$"),
exclude[MissingClassProblem]("cats.effect.internals.AndThen$Concat"),
exclude[MissingClassProblem]("cats.effect.internals.AndThen$Concat$"),
exclude[MissingClassProblem]("cats.effect.internals.AndThen$Single"),
exclude[MissingClassProblem]("cats.effect.internals.AndThen$Single$"),
exclude[ReversedMissingMethodProblem]("cats.effect.Async.never"),
exclude[DirectMissingMethodProblem]("cats.effect.Sync.catsEitherTEvalSync"),
//
// Following are all internal implementation details:
//
Expand Down
144 changes: 144 additions & 0 deletions core/shared/src/main/scala/cats/effect/Bracket.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Copyright (c) 2017-2018 The Typelevel Cats-effect Project Developers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package cats
package effect

/**
* An extension of `MonadError` exposing the `bracket` operation,
* a generalized abstracted pattern of safe resource acquisition and
* release in the face of errors or interruption.
*
* @define acquireParam is an action that "acquires" some expensive
* resource, that needs to be used and then discarded
*
* @define useParam is the action that uses the newly allocated
* resource and that will provide the final result
*/
trait Bracket[F[_], E] extends MonadError[F, E] {
/**
* A generalized version of [[bracket]] which uses [[ExitCase]]
* to distinguish between different exit cases when releasing
* the acquired resource.
*
* @param acquire $acquireParam
* @param use $useParam
* @param release is the action that's supposed to release the
* allocated resource after `use` is done, by observing
* and acting on its exit condition
*/
def bracketCase[A, B](acquire: F[A])(use: A => F[B])
(release: (A, ExitCase[E]) => F[Unit]): F[B]

/**
* Operation meant for specifying tasks with safe resource
* acquisition and release in the face of errors and interruption.
*
* This operation provides the equivalent of `try/catch/finally`
* statements in mainstream imperative languages for resource
* acquisition and release.
*
* @param acquire $acquireParam
* @param use $useParam
* @param release is the action that's supposed to release the
* allocated resource after `use` is done, irregardless of
* its exit condition
*/
def bracket[A, B](acquire: F[A])(use: A => F[B])
(release: A => F[Unit]): F[B] =
bracketCase(acquire)(use)((a, _) => release(a))

}

/**
* Type for signaling the exit condition of an effectful
* computation, that may either succeed, fail with an error or
* get canceled.
*
* The types of exit signals are:
*
* - [[ExitCase$.Completed Completed]]: for successful
* completion (from the type of view of this `MonadError`)
* - [[ExitCase$.Error Error]]: for termination in failure
* (via `MonadError[F, E]`)
* - [[ExitCase$.Canceled Canceled]]: for abortion
*/
sealed abstract class ExitCase[+E] extends Product with Serializable

object ExitCase {
/**
* An [[ExitCase]] that signals successful completion.
*
* Note that "successful" is from the type of view of the
* `MonadError` type that's implementing [[Bracket]].
* When combining such a type with `EitherT` or `OptionT` for
* example, this exit condition might not signal a successful
* outcome for the user, but it does for the purposes of the
* `bracket` operation.
*/
final case object Completed extends ExitCase[Nothing]

/**
* An [[ExitCase]] signaling completion in failure.
*/
final case class Error[+E](e: E) extends ExitCase[E]

/**
* An [[ExitCase]] signaling that the action was aborted.
*
* As an example this can happen when we have a cancelable data type,
* like [[IO]] and the task yielded by `bracket` gets canceled
* when it's at its `use` phase.
*
* Thus [[Bracket]] allows you to observe interruption conditions
* and act on them.
*/
final case class Canceled[+E](e: Option[E]) extends ExitCase[E]

/**
* Parametrized alias for the [[Completed]] data constructor.
*/
def complete[E]: ExitCase[E] = Completed

/**
* Alias for the [[Error]] data constructor.
*/
def error[E](e: E): ExitCase[E] = Error[E](e)

/**
* Alias for `Canceled(None)`.
*/
def canceled[E]: ExitCase[E] = Canceled(None)

/**
* Alias for `Canceled(Some(e))`.
*/
def canceledWith[E](e: E): ExitCase[E] = Canceled(Some(e))

/**
* Converts from Scala's `Either`, which is often the result of
* `MonadError`'s `attempt` operation, into an [[ExitCase]].
*/
def attempt[E, A](value: Either[E, A]): ExitCase[E] =
value match {
case Left(e) => ExitCase.error(e)
case Right(_) => ExitCase.complete
}
}

object Bracket {
def apply[F[_], E](implicit ev: Bracket[F, E]): Bracket[F, E] = ev
}
Loading