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

Scala 3 #1105

Open
wants to merge 37 commits into
base: develop
Choose a base branch
from
Open

Scala 3 #1105

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
1846662
prepare for scala 3
i10416 Mar 4, 2023
1d4bf3d
prepare: move scala 2.x macros to dedicated directory
i10416 Mar 4, 2023
dfe6cf1
prapare: move or copy source files to compile in Scala 3
i10416 Apr 2, 2023
11e2345
feat: implement derive macros for common typeclasses
i10416 Apr 2, 2023
dd316f5
tweak to compile
i10416 Apr 3, 2023
d725b47
add Cuber and Cuber derivation
i10416 Apr 3, 2023
cbfac0f
explicitly abort on Sum types
i10416 Apr 3, 2023
9991f1c
update: tweak build to reduce copy-paste
i10416 Apr 3, 2023
727a430
remove changes in 2.11
i10416 Apr 3, 2023
ec1643c
remove changes in 2.11
i10416 Apr 3, 2023
4500887
make kind projector symbol consistent
i10416 Apr 3, 2023
9f3722b
feat: add roller macro and refine Abstract member type
i10416 Apr 7, 2023
d123047
workaround: comment out lines to compile
i10416 Apr 7, 2023
8863340
tweak: prepare for compiling algebird-tests
i10416 Apr 7, 2023
ea9e5b3
copy changes from #1108
i10416 Apr 7, 2023
12bab8e
address compiler warnings
i10416 Apr 7, 2023
48bbd70
prefer explicit apply
i10416 Apr 7, 2023
e8335bd
address compiler warnings
i10416 Apr 7, 2023
caa51f0
update dependencies
i10416 Apr 7, 2023
aae4864
resolve conflict
i10416 Apr 7, 2023
88526ad
cross compile algebird core and test against 2.11,12,13
i10416 Apr 7, 2023
a25138a
address some compiler warnings
i10416 Apr 7, 2023
331415c
fix: use Math.random()
i10416 Apr 7, 2023
5ec33b9
prepare for cross build
i10416 Apr 7, 2023
c3b84ae
chore: fmt
i10416 Apr 7, 2023
6784882
feat: implement ArbitraryCaseClassMacro
i10416 Apr 9, 2023
7042270
update: address compiler errors and warnings
i10416 Apr 9, 2023
9bd13ba
ci: add 3.2.2 to test matrix
i10416 Apr 9, 2023
09c7a79
improve: reduce copy-pastes
i10416 Apr 9, 2023
0f44cc1
improve: reduce copy paste in tests
i10416 Apr 9, 2023
5274d3f
fix compiler error due to missing collection compat import
i10416 Apr 9, 2023
2f1f2f7
hack: skip CollectionSpecification in Scala 3
i10416 Apr 9, 2023
f462fd5
fix: address format errors
i10416 Apr 13, 2023
72f68f1
fix: address scalafix errors
i10416 Apr 13, 2023
b3c6195
fix: workaround false-positive format error
i10416 Apr 13, 2023
d51aa1b
fix: address compiler errors
i10416 Apr 13, 2023
d5defd6
update Scala to 3.3.0
i10416 Jun 4, 2023
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
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
- 2.11.12
- 2.12.17
- 2.13.10
- 3.3.0
test-coverage:
runs-on: ubuntu-latest
steps:
Expand All @@ -45,6 +46,7 @@ jobs:
sbt ++2.12.17 coverage test coverageReport
bash <(curl -s https://codecov.io/bash)
mimaReport:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ sonatype.sbt
BUILD
target/
lib_managed/
project/metals.sbt
project/boot/
project/build/target/
project/plugins/target/
Expand Down
11 changes: 10 additions & 1 deletion .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
version=3.6.0
runner.dialect = scala212
fileOverride {
"glob:**/scala-2.13*/**" {
"glob:**/scala-3/**" {
runner.dialect = scala3
}
"glob:**/scala-2*/**" {
runner.dialect = scala213
}
}

project.excludeFilters = [
algebird-test/src/main/scala-3/com/twitter/algebird/macros/ArbitraryCaseClassMacro.scala,
algebird-test/src/main/scala-3/com/twitter/algebird/macros/Cuber.scala,
]

maxColumn = 110
docstrings.style = Asterisk
newlines.alwaysBeforeMultilineDef = false
Expand Down
42 changes: 42 additions & 0 deletions algebird-core/src/main/scala-2.11/AggregatorCompat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.twitter.algebird

trait AggregatorCompat {
implicit def applicative[I]: Applicative[({ type L[O] = Aggregator[I, _, O] })#L] =
new AggregatorApplicative[I]
}

/**
* Aggregators are Applicatives, but this hides the middle type. If you need a join that does not hide the
* middle type use join on the trait, or GeneratedTupleAggregator.fromN
*/
class AggregatorApplicative[I] extends Applicative[({ type L[O] = Aggregator[I, _, O] })#L] {
override def map[T, U](mt: Aggregator[I, _, T])(fn: T => U): Aggregator[I, _, U] =
mt.andThenPresent(fn)
override def apply[T](v: T): Aggregator[I, _, T] =
Aggregator.const(v)
override def join[T, U](mt: Aggregator[I, _, T], mu: Aggregator[I, _, U]): Aggregator[I, _, (T, U)] =
mt.join(mu)
override def join[T1, T2, T3](
m1: Aggregator[I, _, T1],
m2: Aggregator[I, _, T2],
m3: Aggregator[I, _, T3]
): Aggregator[I, _, (T1, T2, T3)] =
GeneratedTupleAggregator.from3((m1, m2, m3))

override def join[T1, T2, T3, T4](
m1: Aggregator[I, _, T1],
m2: Aggregator[I, _, T2],
m3: Aggregator[I, _, T3],
m4: Aggregator[I, _, T4]
): Aggregator[I, _, (T1, T2, T3, T4)] =
GeneratedTupleAggregator.from4((m1, m2, m3, m4))

override def join[T1, T2, T3, T4, T5](
m1: Aggregator[I, _, T1],
m2: Aggregator[I, _, T2],
m3: Aggregator[I, _, T3],
m4: Aggregator[I, _, T4],
m5: Aggregator[I, _, T5]
): Aggregator[I, _, (T1, T2, T3, T4, T5)] =
GeneratedTupleAggregator.from5((m1, m2, m3, m4, m5))
}
22 changes: 22 additions & 0 deletions algebird-core/src/main/scala-2.11/FoldCompat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.twitter.algebird

trait FoldApplicativeCompat {
implicit def applicative[I]: Applicative[Fold[I, *]] =
new FoldApplicative[I]
}

/**
* Folds are Applicatives!
*/
class FoldApplicative[I] extends Applicative[Fold[I, *]] {
override def map[T, U](mt: Fold[I, T])(fn: T => U): Fold[I, U] =
mt.map(fn)
override def apply[T](v: T): Fold[I, T] =
Fold.const(v)
override def join[T, U](mt: Fold[I, T], mu: Fold[I, U]): Fold[I, (T, U)] =
mt.join(mu)
override def sequence[T](ms: Seq[Fold[I, T]]): Fold[I, Seq[T]] =
Fold.sequence(ms)
override def joinWith[T, U, V](mt: Fold[I, T], mu: Fold[I, U])(fn: (T, U) => V): Fold[I, V] =
mt.joinWith(mu)(fn)
}
24 changes: 24 additions & 0 deletions algebird-core/src/main/scala-2.11/InvariantAlgebrasCompat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.twitter.algebird

class InvariantSemigroup[T, U](val forward: T => U, val reverse: U => T)(implicit val semigroup: Semigroup[T])
extends Semigroup[U] {
override def plus(l: U, r: U): U =
forward(semigroup.plus(reverse(l), reverse(r)))
override def sumOption(iter: TraversableOnce[U]): Option[U] =
semigroup.sumOption(iter.map(reverse)).map(forward)

/*
* Note these work for the subclasses since in those cases semigroup
* will be the appropriate algebra.
*/
override val hashCode: Int = (forward, reverse, semigroup).hashCode
override def equals(that: Any): Boolean =
that match {
case r: InvariantSemigroup[_, _] =>
(hashCode == r.hashCode) &&
(forward == r.forward) &&
(reverse == r.reverse) &&
(semigroup == r.semigroup)
case _ => false
}
}
60 changes: 60 additions & 0 deletions algebird-core/src/main/scala-2.11/JMapMonoidsCompat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.twitter.algebird
import java.lang.{
Boolean => JBool,
Double => JDouble,
Float => JFloat,
Integer => JInt,
Long => JLong,
Short => JShort
}
import java.util.{ArrayList => JArrayList, HashMap => JHashMap, List => JList, Map => JMap}

import scala.collection.JavaConverters._

/**
* Since maps are mutable, this always makes a full copy. Prefer scala immutable maps if you use scala
* immutable maps, this operation is much faster TODO extend this to Group, Ring
*/
class JMapMonoid[K, V: Semigroup] extends Monoid[JMap[K, V]] {
override lazy val zero: JHashMap[K, V] = new JHashMap[K, V](0)

val nonZero: (V => Boolean) = implicitly[Semigroup[V]] match {
case mon: Monoid[_] => mon.isNonZero(_)
case _ => _ => true
}

override def isNonZero(x: JMap[K, V]): Boolean =
!x.isEmpty && (implicitly[Semigroup[V]] match {
case mon: Monoid[_] =>
x.values.asScala.exists(v => mon.isNonZero(v))
case _ => true
})
override def plus(x: JMap[K, V], y: JMap[K, V]): JHashMap[K, V] = {
val (big, small, bigOnLeft) =
if (x.size > y.size) {
(x, y, true)
} else {
(y, x, false)
}
val vsemi = implicitly[Semigroup[V]]
val result = new JHashMap[K, V](big.size + small.size)
result.putAll(big)
small.entrySet.asScala.foreach { kv =>
val smallK = kv.getKey
val smallV = kv.getValue
if (big.containsKey(smallK)) {
val bigV = big.get(smallK)
val newV =
if (bigOnLeft) vsemi.plus(bigV, smallV) else vsemi.plus(smallV, bigV)
if (nonZero(newV))
result.put(smallK, newV)
else
result.remove(smallK)
} else {
// No need to explicitly add with zero on V, just put in the small value
result.put(smallK, smallV)
}
}
result
}
}
75 changes: 75 additions & 0 deletions algebird-core/src/main/scala-2.11/MapAlgebraCompat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.twitter.algebird

import scala.collection.mutable.{Builder, Map => MMap}
import scala.collection.{Map => ScMap}
import scala.collection.compat._

abstract class GenericMapMonoid[K, V, M <: ScMap[K, V]](implicit val semigroup: Semigroup[V])
extends Monoid[M]
with MapOperations[K, V, M] {

val nonZero: (V => Boolean) = semigroup match {
case mon: Monoid[_] => mon.isNonZero(_)
case _ => _ => true
}

override def isNonZero(x: M): Boolean =
!x.isEmpty && (semigroup match {
case mon: Monoid[_] =>
x.valuesIterator.exists(v => mon.isNonZero(v))
case _ => true
})

override def plus(x: M, y: M): M = {
// Scala maps can reuse internal structure, so don't copy just add into the bigger one:
// This really saves computation when adding lots of small maps into big ones (common)
val (big, small, bigOnLeft) =
if (x.size > y.size) {
(x, y, true)
} else {
(y, x, false)
}
small match {
// Mutable maps create new copies of the underlying data on add so don't use the
// handleImmutable method.
// Cannot have a None so 'get' is safe here.
case _: MMap[_, _] => sumOption(Seq(big, small)).get
case _ => handleImmutable(big, small, bigOnLeft)
}
}

private def handleImmutable(big: M, small: M, bigOnLeft: Boolean) =
small.foldLeft(big) { (oldMap, kv) =>
val newV = big
.get(kv._1)
.map { bigV =>
if (bigOnLeft)
semigroup.plus(bigV, kv._2)
else
semigroup.plus(kv._2, bigV)
}
.getOrElse(kv._2)
if (nonZero(newV))
add(oldMap, kv._1 -> newV)
else
remove(oldMap, kv._1)
}
override def sumOption(items: TraversableOnce[M]): Option[M] =
if (items.iterator.isEmpty) None
else {
val mutable = MMap[K, V]()
items.iterator.foreach { m =>
m.foreach { case (k, v) =>
val oldVOpt = mutable.get(k)
// sorry for the micro optimization here: avoiding a closure
val newV =
if (oldVOpt.isEmpty) v else Semigroup.plus(oldVOpt.get, v)
if (nonZero(newV))
mutable.update(k, newV)
else
mutable.remove(k)
}
}
Some(fromMutable(mutable))
}
}
15 changes: 15 additions & 0 deletions algebird-core/src/main/scala-2.11/ScanApplicativeCompat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.twitter.algebird

class ScanApplicative[I] extends Applicative[Scan[I, *]] {
override def map[T, U](mt: Scan[I, T])(fn: T => U): Scan[I, U] =
mt.andThenPresent(fn)

override def apply[T](v: T): Scan[I, T] =
Scan.const(v)

override def join[T, U](mt: Scan[I, T], mu: Scan[I, U]): Scan[I, (T, U)] =
mt.join(mu)
}
trait ScanApplicativeCompat {
implicit def applicative[I]: Applicative[Scan[I, *]] = new ScanApplicative[I]
}
42 changes: 42 additions & 0 deletions algebird-core/src/main/scala-2.12+/AggregatorCompat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.twitter.algebird

private[algebird] trait AggregatorCompat {
implicit def applicative[I]: Applicative[({ type L[O] = Aggregator[I, ?, O] })#L] =
new AggregatorApplicative[I]
}

/**
* Aggregators are Applicatives, but this hides the middle type. If you need a join that does not hide the
* middle type use join on the trait, or GeneratedTupleAggregator.fromN
*/
class AggregatorApplicative[I] extends Applicative[({ type L[O] = Aggregator[I, ?, O] })#L] {
override def map[T, U](mt: Aggregator[I, ?, T])(fn: T => U): Aggregator[I, ?, U] =
mt.andThenPresent(fn)
override def apply[T](v: T): Aggregator[I, ?, T] =
Aggregator.const(v)
override def join[T, U](mt: Aggregator[I, ?, T], mu: Aggregator[I, ?, U]): Aggregator[I, ?, (T, U)] =
mt.join(mu)
override def join[T1, T2, T3](
m1: Aggregator[I, ?, T1],
m2: Aggregator[I, ?, T2],
m3: Aggregator[I, ?, T3]
): Aggregator[I, ?, (T1, T2, T3)] =
GeneratedTupleAggregator.from3((m1, m2, m3))

override def join[T1, T2, T3, T4](
m1: Aggregator[I, ?, T1],
m2: Aggregator[I, ?, T2],
m3: Aggregator[I, ?, T3],
m4: Aggregator[I, ?, T4]
): Aggregator[I, ?, (T1, T2, T3, T4)] =
GeneratedTupleAggregator.from4((m1, m2, m3, m4))

override def join[T1, T2, T3, T4, T5](
m1: Aggregator[I, ?, T1],
m2: Aggregator[I, ?, T2],
m3: Aggregator[I, ?, T3],
m4: Aggregator[I, ?, T4],
m5: Aggregator[I, ?, T5]
): Aggregator[I, ?, (T1, T2, T3, T4, T5)] =
GeneratedTupleAggregator.from5((m1, m2, m3, m4, m5))
}
Loading