Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ jobs:

- name: Make target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: mkdir -p munit/jvm/target core/native/target core/js/target munit/native/target core/jvm/target munit/js/target project/target
run: mkdir -p cats-effect/native/target munit/jvm/target core/native/target cats-effect/jvm/target core/js/target munit/native/target core/jvm/target cats-effect/js/target munit/js/target project/target

- name: Compress target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: tar cf targets.tar munit/jvm/target core/native/target core/js/target munit/native/target core/jvm/target munit/js/target project/target
run: tar cf targets.tar cats-effect/native/target munit/jvm/target core/native/target cats-effect/jvm/target core/js/target munit/native/target core/jvm/target cats-effect/js/target munit/js/target project/target

- name: Upload target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
Expand Down
11 changes: 10 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ThisBuild / startYear := Some(2021)
ThisBuild / crossScalaVersions := List("3.3.3", "2.12.19", "2.13.14")
ThisBuild / tlVersionIntroduced := Map("3" -> "1.0.2")

lazy val root = tlCrossRootProject.aggregate(core, munit)
lazy val root = tlCrossRootProject.aggregate(core, `cats-effect`, munit)

lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.settings(
Expand All @@ -20,6 +20,15 @@ lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform)
)
)

lazy val `cats-effect` = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.settings(
name := "scalacheck-cats-effect",
libraryDependencies ++= List(
"org.typelevel" %%% "cats-effect" % "3.5.4"
)
)
.dependsOn(core)

lazy val munit = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.settings(
name := "scalacheck-effect-munit",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2021 Typelevel
*
* 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.effect.std

import cats.effect.*
import cats.effect.std.Random.ScalaRandom
import cats.syntax.all.*
import org.scalacheck.{Arbitrary, Gen, Shrink}

trait ArbitraryRandom {

/** Generates a `Random[F]` instance seeded by a generated long value, so that the "randomness"
* will be repeatable given the same ScalaCheck seed.
*/
def genRandom[F[_]: Sync]: Gen[Random[F]] =
Gen.long
.map(new scala.util.Random(_).pure[F])
.map(new ScalaRandom[F](_) {})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, it looks a bit "hacky" to me: ArbitraryRandom is placed into cats.effect.std to let it access the ScalaRandom's private constructor. Whereas the other scalacheck-effect code lives in org.scalacheck.effect.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's true, but I did ask about this implementation in Discord and got an initial thumbs up from @djspiewak. (Although to be fair, I’m not sure he was thinking about it from this specific angle.) I suppose if Cats Effect could be persuaded to open up one of those constructors, we could move this somewhere else.

Really the problem is that the Random.scalaUtilRandomSeedLong returns F[Random[F]] and not just Random[F]. I don’t think that’s necessary for this particular case, but I’m not sure whether that’s true in general. If introducing a new constructor in Random is a better option, then we could use that here instead.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In regards to constructors safety, there are a couple of classes in Cats-Effect that got "unsafe" constructor counterparts: Ref and Deferred. Both are in "kernel" though. However, I don't think that it would hurt much if Random could get a couple of unsafe constructors too. At least to me it seems like a more viable solution comparing to tuning package names in order to access private constructors.

For example, Random.javaUtilRandom[F[_]](random: java.util.Random): F[Random[F]] is not fully referentially transparent, apparently. So, it wouldn't seem too bad if there was unsafeJavaUtilRandom[F[_]](random: java.util.Random): Random[F] counterpart.


implicit def arbRandom[F[_]: Sync]: Arbitrary[Random[F]] = Arbitrary(genRandom[F])

implicit def shrinkRandom[F[_]]: Shrink[Random[F]] = Shrink.shrinkAny
}

object ArbitraryRandom extends ArbitraryRandom