We are building some sync functionality using two-way json requests and this algorithm. All good and we have it running in prototype mode. Now I am trying to genericise the code, as we will be synching for several tables in the app. It would be cool to be able to define a class as "extends Synchable" and get the additional attributes and sync processing methods with a few specialisations/overrides. I have got this far:
abstract class Synchable [T<:Synchable[T]] (val ruid: String, val lastSyncTime: String, val isDeleted:Int) {
def contentEquals(Target: T): Boolean
def updateWith(target: T)
def insert
def selectSince(clientLastSyncTime: String): List[T]
def findByRuid(ruid: String): Option[T]
implicit val validator: Reads[T]
def process(clientLastSyncTime: String, updateRowList: List[JsObject]) = {
for (syncRow <- updateRowList) {
val validatedSyncRow = syncRow.validate[Synchable]
validatedSyncRow.fold(
valid = { result => // valid row
findByRuid(result.ruid) match { //- do we know about it?
case Some(knownRow) => knownRow.updateWith(result)
case None => result.insert
}
}... invalid, etc
I am new to Scala and know I am probably missing things - WIP!
Any pointers or suggestions on this approach would be much appreciated.
Some quick ones:
Those _ parameters you pass in and then immediately assign to vals: why not do it in one hit? e.g.
abstract class Synchable( val ruid: String = "", val lastSyncTime: String = "", val isDeleted: Int = 0) {
which saves you a line and is clearer in intent as well I think.
I'm not sure about your defaulting of Strings to "" - unless there's a good reason (and there often is), I think using something like ruid:Option[String] = None is more explicit and lets you do all sorts of nice monad-y things like fold, map, flatMap etc.
Looking pretty cool otherwise - the only other thing you might want to do is strengthen the typing with a bit of this.type magic so you'll prevent incorrect usage at compile-time. With your current abstract class, nothing prevents me from doing:
class SynchableCat extends Synchable { ... }
class SynchableDog extends Synchable { ... }
val cat = new SynchableCat
val dog = new SynchableDog
cat.updateWith(dog) // This won't end well
But if you just change your abstract method signatures to things like this:
def updateWith(target: this.type)
Then the change ripples down through the subclasses, narrowing down the types, and the compiler will omit a (relatively clear) error if I try the above update operation.
Related
I have the following case class:
case class Example[T](
obj: Option[T] | T = None,
)
This allows me to construct it like Example(myObject) instead of Example(Some(myObject)).
To work with obj I need to normalise it to Option[T]:
lazy val maybeIn = obj match
case o: Option[T] => o
case o: T => Some(o)
the type test for Option[T] cannot be checked at runtime
I tried with TypeTest but I got also warnings - or the solutions I found look really complicated - see https://stackoverflow.com/a/69608091/2750966
Is there a better way to achieve this pattern in Scala 3?
I don't know about Scala3. But you could simply do this:
case class Example[T](v: Option[T] = None)
object Example {
def apply[T](t: T): Example[T] = Example(Some(t))
}
One could also go for implicit conversion, regarding the specific use case of the OP:
import scala.language.implicitConversions
case class Optable[Out](value: Option[Out])
object Optable {
implicit def fromOpt[T](o: Option[T]): Optable[T] = Optable(o)
implicit def fromValue[T](v: T): Optable[T] = Optable(Some(v))
}
case class SomeOpts(i: Option[Int], s: Option[String])
object SomeOpts {
def apply(i: Optable[Int], s: Optable[String]): SomeOpts = SomeOpts(i.value, s.value)
}
println(SomeOpts(15, Some("foo")))
We have a specialized Option-like type for this purpose: OptArg (in Scala 2 but should be easily portable to 3)
import com.avsystem.commons._
def gimmeLotsOfParams(
intParam: OptArg[Int] = OptArg.Empty,
strParam: OptArg[String] = OptArg.Empty
): Unit = ???
gimmeLotsOfParams(42)
gimmeLotsOfParams(strParam = "foo")
It relies on an implicit conversion so you have to be a little careful with it, i.e. don't use it as a drop-in replacement for Option.
The implementation of OptArg is simple enough that if you don't want external dependencies then you can probably just copy it into your project or some kind of "commons" library.
EDIT: the following answer is incorrect. As of Scala 3.1, flow analysis is only able to check for nullability. More information is available on the Scala book.
I think that the already given answer is probably better suited for the use case you proposed (exposing an API can can take a simple value and normalize it to an Option).
However, the question in the title is still interesting and I think it makes sense to address it.
What you are observing is a consequence of type parameters being erased at runtime, i.e. they only exist during compilation, while matching happens at runtime, once those have been erased.
However, the Scala compiler is able to perform flow analysis for union types. Intuitively I'd say there's probably a way to make it work in pattern matching (as you did), but you can make it work for sure using an if and isInstanceOf (not as clean, I agree):
case class Example[T](
obj: Option[T] | T = None
) {
lazy val maybeIn =
if (obj.isInstanceOf[Option[_]]) {
obj
} else {
Some(obj)
}
}
You can play around with this code here on Scastie.
Here is the announcement from 2019 when flow analysis was added to the compiler.
I'm trying to implement something like clever parameters converter function with Scala.
Basically in my program I need to read parameters from a properties file, so obviously they are all strings and I would like then to convert each parameter in a specific type that I pass as parameter.
This is the implementation that I start coding:
def getParam[T](key : String , value : String, paramClass : T): Any = {
value match {
paramClass match {
case i if i == Int => value.trim.toInt
case b if b == Boolean => value.trim.toBoolean
case _ => value.trim
}
}
/* Exception handling is missing at the moment */
}
Usage:
val convertedInt = getParam("some.int.property.key", "10", Int)
val convertedBoolean = getParam("some.boolean.property.key", "true", Boolean)
val plainString = getParam("some.string.property.key", "value",String)
Points to note:
For my program now I need just 3 main type of type: String ,Int and Boolean,
if is possible I would like to extends to more object type
This is not clever, cause I need to explicit the matching against every possibile type to convert, I would like an more reflectional like approach
This code doesn't work, it give me compile error: "object java.lang.String is not a value" when I try to convert( actually no conversion happen because property values came as String).
Can anyone help me? I'm quite newbie in Scala and maybe I missing something
The Scala approach for a problem that you are trying to solve is context bounds. Given a type T you can require an object like ParamMeta[T], which will do all conversions for you. So you can rewrite your code to something like this:
trait ParamMeta[T] {
def apply(v: String): T
}
def getParam[T](key: String, value: String)(implicit meta: ParamMeta[T]): T =
meta(value.trim)
implicit case object IntMeta extends ParamMeta[Int] {
def apply(v: String): Int = v.toInt
}
// and so on
getParam[Int](/* ... */, "127") // = 127
There is even no need to throw exceptions! If you supply an unsupported type as getParam type argument, code will even not compile. You can rewrite signature of getParam using a syntax sugar for context bounds, T: Bound, which will require implicit value Bound[T], and you will need to use implicitly[Bound[T]] to access that values (because there will be no parameter name for it).
Also this code does not use reflection at all, because compiler searches for an implicit value ParamMeta[Int], founds it in object IntMeta and rewrites function call like getParam[Int](..., "127")(IntMeta), so it will get all required values at compile time.
If you feel that writing those case objects is too boilerplate, and you are sure that you will not need another method in these objects in future (for example, to convert T back to String), you can simplify declarations like this:
case class ParamMeta[T](f: String => T) {
def apply(s: String): T = f(s)
}
implicit val stringMeta = ParamMeta(identity)
implicit val intMeta = ParamMeta(_.toInt)
To avoid importing them every time you use getParam you can declare these implicits in a companion object of ParamMeta trait/case class, and Scala will pick them automatically.
As for original match approach, you can pass a implicit ClassTag[T] to your function, so you will be able to match classes. You do not need to create any values for ClassTag, as the compiler will pass it automatically. Here is a simple example how to do class matching:
import scala.reflect.ClassTag
import scala.reflect._
def test[T: ClassTag] = classTag[T].runtimeClass match {
case x if x == classOf[Int] => "I'm an int!"
case x if x == classOf[String] => "I'm a string!"
}
println(test[Int])
println(test[String])
However, this approach is less flexible than ParamMeta one, and ParamMeta should be preferred.
This is a situation I have encountered frequently, but I have not been able to find a solution yet.
Suppose you have a list of persons and you just want to verify the person names.
This works:
persons.map(_.name) should contain theSameElementsAs(List("A","B"))
Instead, I would rather write this like
val toName: Person => String = _.name
persons should contain theSameElementsAs(List("A","B")) (after mapping toName)
because this is how you would say this.
Sometimes however, you'd like to use a custom matcher which matches more than just one property of the object. How would it be possible to use
persons should contain(..)
syntax, but somehow be able to use a custom matcher?
Both these situations I could easily solve using JUnit or TestNG using Hamcrest matchers, but I have not found a way to do this with ScalaTest.
I have tried to use the 'after being' syntax from the Explicitly trait, but that's not possible since this takes a 'Normalization' which defines that the 'normalized' method uses the same type for the argument and return type. So it's not possible to change a Person to a String.
Also I have not succeeded yet in implementing an 'Explicitly' like trait because it does not like the Equality[.] type I return and/or it does not know anymore what the original list type was, so using '_.name' does not compile.
Any suggestions are welcome.
You can manage something similar via the word decided and moderate abuse of the Equality trait. This is because the Equality trait's areEqual method takes a parameter of the generic type and one of type Any, so you can use that to compare Person with String, and decided by simply takes an Equality object which means you don't have to futz around with Normality.
import org.scalactic.Equality
import org.scalatest.{FreeSpec, Matchers}
final class Test extends FreeSpec with Matchers {
case class Person(name: String)
val people = List(Person("Alice"), Person("Eve"))
val namesBeingEqual = MappingEquality[Person, String](p => p.name)
"test should pass" in {
(people should contain theSameElementsAs List("Alice", "Eve"))(
decided by namesBeingEqual)
}
"test should fail" in {
(people should contain theSameElementsAs List("Alice", "Bob"))(
decided by namesBeingEqual)
}
case class MappingEquality[S, T](map: S => T) extends Equality[S] {
override def areEqual(s: S, b: Any): Boolean = b match {
case t: T => map(s) == t
case _ => false
}
}
}
I'm not sure I'd say this is a good idea since it doesn't exactly behave in the way one would expect anything called Equality to behave, but it works.
You can even get the beingMapped syntax you suggest by adding it to after via implicit conversion:
implicit class AfterExtensions(aft: TheAfterWord) {
def beingMapped[S, T](map: S => T): Equality[S] = MappingEquality(map)
}
}
I did try getting it work with after via the Uniformity trait, which has similar methods involving Any, but ran into problems because the normalization is the wrong way around: I can create a Uniformity[String] object from your example, but not a Uniformity[Person] one. (The reason is that there's a normalized method returning the generic type which is used to construct the Equality object, meaning that in order to compare strings with strings the left-side input must be a string.) This means that the only way to write it is with the expected vs actual values in the opposite order from normally:
"test should succeed" in {
val mappedToName = MappingUniformity[Person, String](person => person.name)
(List("Alice", "Eve") should contain theSameElementsAs people)(
after being mappedToName)
}
case class MappingUniformity[S, T](map: S => T) extends Uniformity[T] {
override def normalizedOrSame(b: Any): Any = b match {
case s: S => map(s)
case t: T => t
}
override def normalizedCanHandle(b: Any): Boolean =
b.isInstanceOf[S] || b.isInstanceOf[T]
override def normalized(s: T): T = s
}
Definitely not how you'd usually want to write this.
use inspectors
forAll (xs) { x => x should be < 3 }
I know there are multiple questions addressing related problems, but I'm not sure it does attack exactly what I'm looking for. I'm still new to Scala, after several years of Java development. I'm looking for the best way to test if an object has been initialized, and if not, initialize it then. For example, in Java:
private MyObject myObj = null;
and at some point in the future:
public void initMyObj(){
if (myObj == null){
myObj = new MyObj();
}
// do something with myObj
}
After this, I might reassign myObj to a different object, but it is unlikely. In Scala, I have this:
class Test {
var myObj: MyObj = _
}
I've read that I could use Option instead, something like:
var myObj = None : Option[MyObj]
and then my check:
myObj match {
case None => ...
case Some(value) => ...
}
but it feels ackward to use this pattern when I might not make this kind of check anywhere else at any other time - though being so new to Scala, I might be wrong. Is this the best way to achieve what I want or is there any other option not involving Option?
It is not generally ideal practice in Scala to leave partially-constructed objects lying around. You would normally rethink how your objects were getting instantiated to see if you can't use a different pattern that is less fragile. For example, instead of setting uninitialized variables in methods:
class Foo { var a: String = null; var b: String = null }
def initFooA(s: String, f: Foo) { if (f.a == null) f.a = s }
def initFooB(s: String, f: Foo) { if (f.b == null) f.b = s }
f
initFooA("salmon", f)
// Do stuff
initFooB("herring", f)
you would attempt to restructure your code to generate the values you need on demand, and delay the instantiation of foo until then:
case class Bar(a: String, b: String) {}
def initBarA(s: String) = s
def initBarB(s: String) = s
val iba = initBarA("halibut")
// Do stuff
val ibb = initBarB("cod")
Bar(iba, ibb)
Because Scala has easy access to tuples (and type inference), this can be a lot less painful than in Java.
Another thing you can do is defer the late initialization to someone else.
case class Baz(a: String)(bMaker: => String) {
lazy val b = bMaker
}
Now you pass in something that will make parameter b, and arrange for it to handle any late initialization stuff that needs to be handled. This doesn't always avoid needing to set vars, but it can help push it out of your class code into your initialization logic (which is usually a better place for it).
Doing this with vars is a little less straightforward. Realistically, you're probably best off just devoting a class to it e.g. by:
class LazyVar[A](initial: => A) {
private[this] var loaded = false
private[this] var variable: A = _
def apply() = { if (!loaded) { loaded = true; variable = initial }; variable }
def update(a: A) { loaded = true; variable = a }
}
where you then (sadly) have to use () on every read and write.
scala> val lv = new LazyVar({ println("Hi!"); 5 })
lv: LazyVar[Int] = LazyVar#2626ea08
scala> lv()
Hi!
res2: Int = 5
scala> lv() = 7
scala> lv()
res4: Int = 7
Then you use an instance of this class instead of the actual var and pass through the lazy initializer. (lazy val is very much like this under the hood; the compiler just protects you from noticing.)
Finally, if you want to have a fully-functional object that is occasionally missing a value, var x: Option[X] is the construct you want to use; if you can't find a way around the standard Java creation patterns (and you don't want to try something more exotic like objects that create each other with more and more information, either because performance is critical and you can't afford it, or you dislike writing that much boilerplate to allow type-checking to verify that your object is properly created) but you otherwise want to use it, var x: X = null is what I'd choose, not _. If X is a primitive, you probably need to choose the correct value wisely anyway (for example, Double.NaN instead of 0.0, -1 rather than 0 for Int) to indicate I-am-not-initialized. If it's generic code and you want Any instead of AnyRef, asInstanceOf-ing back and forth between Any and AnyRef is probably the best way out of poorly typechecked situation (assuming you really, really can't use Option, which at that point is much clearer).
Maybe a lazy variable is what you need.
lazy val myObj: MyObj = //here you put the object creation code
In this way the object creation is postponed to the first time the code tries to access it.
As an exercise, I'd like to extend the Scala Array collection to my own OneBasedArray (does what you'd expect, indexing starts from 1). Since this is an immutable collection, I'd like to have it return the correct type when calling filter/map etc.
I've read the resources here, here and here, but am struggling to understand how to translate this to Arrays (or collections other than the ones in the examples). Am I on the right track with this sort of structure?
class OneBasedArray[T]
extends Array[T]
with GenericTraversableTemplate[T, OneBasedArray]
with ArrayLike[T, OneBasedArray]
Are there any further resources that help explain extending collections?
For a in depth overview of new collections API: The Scala 2.8 Collections API
For a nice view of the relation between main classes and traits this
By the way I don't think Array is a collection in Scala.
Here is an example of pimping iterables with a method that always returns the expected runtime type of the iterable it operates on:
import scala.collection.generic.CanBuildFrom
trait MapOrElse[A] {
val underlying: Iterable[A]
def mapOrElse[B, To]
(m: A => Unit)
(pf: PartialFunction[A,B])
(implicit cbf: CanBuildFrom[Iterable[A], B, To])
: To = {
var builder = cbf(underlying.repr)
for (a <- underlying) if (pf.isDefinedAt(a)) builder += pf(a) else m(a)
builder.result
}
}
implicit def toMapOrElse[A](it: Iterable[A]): MapOrElse[A] =
new MapOrElse[A] {val underlying = it}
The new function mapOrElse is similar to the collect function but it allows you to pass a method m: A => Unit in addition to a partial function pf that is invoked whenever pf is undefined. m can for example be a logging method.
An Array is not a Traversable -- trying to work with that as a base class will cause all sorts of problems. Also, it is not immutable either, which makes it completely unsuited to what you want. Finally, Array is an implementation -- try to inherit from traits or abstract classes.
Array isn't a typical Scala collection... It's simply a Java array that's pimped to look like a collection by way of implicit conversions.
Given the messed-up variance of Java Arrays, you really don't want to be using them without an extremely compelling reason, as they're a source of lurking bugs.
(see here: http://www.infoq.com/presentations/Java-Puzzlers)
Creaking a 1-based collection like this isn't really a good idea either, as you have no way of knowing how many other collection methods rely on the assumption that sequences are 0-based. So to do it safely (if you really must) you'll want add a new method that leaves the default one unchanged:
class OneBasedLookup[T](seq:Seq) {
def atIdx(i:Int) = seq(i-1)
}
implicit def seqHasOneBasedLookup(seq:Seq) = new OneBasedLookup(seq)
// now use `atIdx` on any sequence.
Even safer still, you can create a Map[Int,T], with the indices being one-based
(Iterator.from(1) zip seq).toMap
This is arguably the most "correct" solution, although it will also carry the highest performance cost.
Not an array, but here's a one-based immutable IndexedSeq implementation that I recently put together. I followed the example given here where they implement an RNA class. Between that example, the ScalaDocs, and lots of "helpful" compiler errors, I managed to get it set up correctly. The fact that OneBasedSeq is genericized made it a little more complex than the RNA example. Also, in addition to the traits extended and methods overridden in the example, I had to extend IterableLike and override the iterator method, because various methods call that method behind the scenes, and the default iterator is zero-based.
Please pardon any stylistic or idiomadic oddities; I've been programming in Scala for less than 2 months.
import collection.{IndexedSeqLike, IterableLike}
import collection.generic.CanBuildFrom
import collection.mutable.{Builder, ArrayBuffer}
// OneBasedSeq class
final class OneBasedSeq[T] private (s: Seq[T]) extends IndexedSeq[T]
with IterableLike[T, OneBasedSeq[T]] with IndexedSeqLike[T, OneBasedSeq[T]]
{
private val innerSeq = s.toIndexedSeq
def apply(idx: Int): T = innerSeq(idx - 1)
def length: Int = innerSeq.length
override def iterator: Iterator[T] = new OneBasedSeqIterator(this)
override def newBuilder: Builder[T, OneBasedSeq[T]] = OneBasedSeq.newBuilder
override def toString = "OneBasedSeq" + super.toString
}
// OneBasedSeq companion object
object OneBasedSeq {
private def fromSeq[T](s: Seq[T]) = new OneBasedSeq(s)
def apply[T](vals: T*) = fromSeq(IndexedSeq(vals: _*))
def newBuilder[T]: Builder[T, OneBasedSeq[T]] =
new ArrayBuffer[T].mapResult(OneBasedSeq.fromSeq)
implicit def canBuildFrom[T, U]: CanBuildFrom[OneBasedSeq[T], U, OneBasedSeq[U]] =
new CanBuildFrom[OneBasedSeq[T], U, OneBasedSeq[U]] {
def apply() = newBuilder
def apply(from: OneBasedSeq[T]): Builder[U, OneBasedSeq[U]] = newBuilder[U]
}
}
// Iterator class for OneBasedSeq
class OneBasedSeqIterator[T](private val obs: OneBasedSeq[T]) extends Iterator[T]
{
private var index = 1
def hasNext: Boolean = index <= obs.length
def next: T = {
val ret = obs(index)
index += 1
ret
}
}