Accessing Scala data structures in JRuby - scala

It looks like there's some magic translation between Java data structures when accessing them from JRuby; they appear to work like plain ruby maps and arrays. However, Scala data structures don't. I found surprisingly little when googling around for JRuby / Scala interop. How would you, for instance, iterate over Scala's Map and List types?

Sure you can. But it's a bit of hoop-jumping. For lists:
require "/usr/share/scala/lib/scala-library.jar" # load the scala lib
Java::scala.collection.immutable::List.empty.send("::", 1)
.map(lambda{|e|e+1},
Java::scala.collection.immutable.List.canBuildFrom) # by lopex
Now you have a scala list in jruby. You could write some nice Ruby API filling in the implicits for you.

If by "iterate over" you mean use the HOFs (higher-order functions) such as map, reduce, filter , collect and so on then you're going to have trouble. It's possible, but the syntactic elegance you get in Scala comes because it's so easy to write function literals. What the compiler is doing for you when you write something like this:
scala> val l1 = List(1, 2, 3)
l1: List[Int] = List(1, 2, 3)
scala> l1.map(i => i * i)
res0: List[Int] = List(1, 4, 9)
... is create and instantiate a subclass of Function1[Int, Int] whose apply method takes the single Int argument an evaluates the body of the function literal ((i => i * i)).
For you to use any Scala method that accepts a function you'll have to do the same. Something like:
scala> class ISquaredF extends Function1[Int, Int] { def apply(i: Int) = i * i }
defined class ISquaredF
scala> (new ISquaredF)(5)
res1: Int = 25
scala> val isf1 = new ISquaredF
isf1: ISquaredF = <function1>
scala> l1.map(isf1)
res2: List[Int] = List(1, 4, 9)
Overall, it's vastly easier to use Java libraries from Scala than it is to use Scala code from any other JVM language. That's why systems like Akka that want to support both Scala and Java clients have special Java APIs that avoid these parts of the Scala language.

Related

How to create a function that works generically on an Array as well as an Option

I would like to create a generic function that works for both an Array as an Option:
val numbers = Array(1, 2, 3)
val numberO: Option[Int] = Some(4)
def addOnes(numbers: ???[Int]) = numbers.map(_+1)
addOnes(numbers)
addOnes(numberO)
Right now I have a separate function for each structure
def addOnesForArray(numbers: Array[Int]) = numbers.map(_+1)
def addOnesForOption(numberO: Option[Int]) = numberO.map(_+1)
addOnesForArray(numbers)
addOnesForOption(numberO)
So basically I need a superclass of Array and Option that has the functor and monad methods map, flatMap, filter, ...
You could use structural typing (aka "duck typing"), with which we could say that you need literally "something with a map", written as { def map(): T }. But that's a) ugly, b) uses reflection, and c) hard (note that map(): T is just an example; in reality you will have to match the exact signature of map, with CanBuildFrom and all that jazz).
Better way would be to reach for scalaz or cats and use category theory concepts. Just pick the least powerful abstraction that does the job. If you need just map, then it's a Functor. If you want to map with (curried) functions of more than one parameter, then it's an Applicative. If you also want flatMap, then it's a monad, etc.
Example for functor:
import scalaz._, Scalaz._
def addOne[F[Int]](f: F[Int])(implicit m: Functor[F]) = f.map(_ + 1)
val numbers = Array(1, 2, 3).toList
val numberO = Option(123)
addOne(numbers) // List(2, 3, 4)
addOne(numberO) // Some(124)
You will notice that I had to convert your array to a List because there are no typeclass instances (that I know of) for functors, applicatives, monads etc. that work on arrays. But arrays are old fashioned and invariant and really not idiomatic Scala anyway. If you get them from elsewhere, just convert them to Lists, Vectors etc. (based on your use case) and work with those from that point onwards.
In general I agree with #slouc . If you want to make existing classes kinda extend some other trait you need typeclasses.
But in your particular case it is not required since Option and Array are both Traversable:
object Example extends App {
def plus1(data: Traversable[Int]): Traversable[Int] = data.map(x => x + 1)
println(plus1(Array(1, 2, 3)))
println(plus1(Some(4)))
}

constructor cannot be instantiated to expected type

I am using Scala 2.11.8
I have this code
val i1 = Either[ErrorCode, Person] = getMaybePerson().toRight(ErrorCode.NOTFOUND)
val i2 = Either[ErrorCode, (Int, FiniteDuration)] = getMaybeConfig().toRight(ErrorCode.NOCONFIG)
for {
a <- i1.right
(c, d) <- i2.right
} yield {...}
The IDE (IntelliJ 2017.1) does not show any errors. but when I compile from SBT. it says
Warning:(163, 43) `withFilter' method does not yet exist on scala.util.Either.RightProjection[ErrorCode,(Int, scala.concurrent.duration.FiniteDuration)], using `filter' method instead
(maxReward, checkDuration) <- i2.right
Error:(163, 10) constructor cannot be instantiated to expected type;
found : (T1, T2)
required: scala.util.Either[Nothing,(Int, scala.concurrent.duration.FiniteDuration)]
(maxReward, checkDuration) <- i2.right
This is driving me nuts, because In the REPL. I can easily write this code.
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_121).
Type in expressions for evaluation. Or try :help.
scala> case class Person(name: String, age: Int)
defined class Person
scala> val x = Some(Person("foo", 20))
x: Some[Person] = Some(Person(foo,20))
scala> val y = Some(("foo", 20))
y: Some[(String, Int)] = Some((foo,20))
scala> for {
| a <- x.toRight("wrong").right
| b <- y.toRight("wrong").right
| } yield (a.name, a.age, b._1, b._2)
res0: scala.util.Either[String,(String, Int, String, Int)] = Right((foo,20,foo,20))
scala>
The short answer is that Either does not sit well with for comprehensions (at least in scala <2.11).
So you first have to remember that for comprehensions are syntactic sugar for monadic operations map, flatMap, and withFilter.
In particular, when doing pattern matching on an extracted value (such as the (c, d) <- i2.right in your code), this is replaced by (something equivalent to)
i2.right.withFilter(_.isInstanceOf[Tuple2[A, B]]).map{p =>
val (c, d) = p.asInstanceOf[Tuple2[A, B]]
...
}
Now you may see more clearly what the problem is: first, there is no withFilter method on RightProjection, so it uses filter instead (as the error statement says). Then the filter method outputs an Option[Either[ErrorCode, (Int, FiniteDuration)]], so you cannot pattern match with a tuple against it.
If you can get around the filter problem, you will probably come against the problem with map (I know I did):
If you try using an assignment in for comprehension:
for {
a <- Right("foo").right
b = a + "bar"
} yield a + b
This won't work either, because it is replaced by a map call on an Either... but since Either is not right-biased (or left-), it does not have a map method, so the compiler will be lost (and give you some confusing error message, if you don't think about how the for is desugared).
In general, you should avoid using Either in for comprehension if you want to do some filtering (pattern matching included) or assignements. You might want to consider some equivalent monads in some libs, such as Validation or \/ in catz or scalaz.
NB I said something about scala 2.11, because in scala 2.12, Either becomes right-biased, so some of the afore-mentioned problems disappear, but I haven't tried my hands on it yet.

Is there a way to print out an object from a script as it would appear in the REPL? (e.g. myList: List[String] = List(Hello there, World!)

I'm coming from a long time Python background. I've always leaned heavily on the type function in Python to spit out what kind of object I'm working with.
e.g.
In[0]: print type("Hello")
Out[0]: >>> string
In[0]: print type(1234)
Out[0]: >>> int
As I make my way into Scala territory, there are times when I'm not entirely sure what kind of object I've ended up with. being able to lay down a quick print type(obj) whenever I get a little lost would be a huge help.
e.g.
println(type(myObj)) /* Whatever the scala equivalent would be */
>>> myObj: List[String] = List(Hello there, World!)
The Scala equivalent of this would be the getClass method (from Java) on java.lang.Object.
For instance:
scala> 1.getClass
res0: Class[Int] = int
scala> Nil.getClass
res1: Class[_ <: scala.collection.immutable.Nil.type] = class scala.collection.immutable.Nil$
scala> "hello".getClass
res2: Class[_ <: String] = class java.lang.String
You can easily access high-fidelity type information using reflection as of Scala 2.10.
Make sure to add the scala-reflect JAR to your classpath beforehand.
A little helper method is useful here:
import scala.reflect.runtime.universe._
def showTypeOf[T: TypeTag](obj: T) {
println(typeOf[T])
}
Usage:
showTypeOf(List(1, 2, 3)) // prints List[Int]

Best practice: "If not immutable create copy"-pattern

I have function which gets a Seq[_] as an argument and returns an immutable class instance with this Seq as a val member. If the Seq is mutable I obviously want to create a defensive copy to guarantee that my return class instance cannot be modified.
What are the best practice for this pattern? First I was surprised that it is not possible to overload the function
def fnc(arg: immutable.Seq[_]) = ...
def fnc(arg: mutable.Seq[_]) = ...
I could also pattern-match:
def fnc(arg: Seq[_]) = arg match {
case s: immutable.Seq[_] => { println("immutable"); s}
case s: mutable.Seq[_] => {println("mutable"); List()++s }
case _: ?
}
But I am not sure about the _ case. Is it guaranteed that arg is immutable.Seq or mutable.Seq? I also don't know if List()++s is the correct way to convert it. I saw many posts on SO, but most of them where for 2.8 or earlier.
Are the Scala-Collections "intelligent" enough that I can just always (without pattern matching) write List()++s and I get the same instance if immutable and a deep copy if mutable?
What is the recommend way to do this?
You will need to pattern match if you want to support both,. The code for Seq() ++ does not guarantee (as part of its API) that it won't copy the rest if it's immutable:
scala> val v = Vector(1,2,3)
v: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3)
scala> Seq() ++ v
res1: Seq[Int] = List(1, 2, 3)
It may pattern-match itself for some special cases, but you know the cases you want. So:
def fnc[A](arg: Seq[A]): Seq[A] = arg match {
case s: collection.immutable.Seq[_] => arg
case _ => Seq[A]() ++ arg
}
You needn't worry about the _; this just says you don't care exactly what the type argument is (not that you could check anyway), and if you write it this way, you don't: pass through if immutable, otherwise copy.
What are the best practice for this pattern?
If you want to guarantee immutability, the best practice is to make a defensive copy, or require immutable.Seq.
But I am not sure about the _ case. Is it guaranteed that arg is immutable.Seq or mutable.Seq?
Not necessarily, but I believe every standard library collection that inherits from collection.Seq also inherits from one of those two. A custom collection, however, could theoretically inherit from just collection.Seq. See Rex's answer for an improvement on your pattern-matching solution.
Are the Scala-Collections "intelligent" enough that I can just always (without pattern matching) write List()++s and I get the same instance if immutable and a deep copy if mutable?
It appears they are in certain cases but not others, for example:
val immutableSeq = Seq[Int](0, 1, 2)
println((Seq() ++ immutableSeq) eq immutableSeq) // prints true
val mutableSeq = mutable.Seq[Int](0, 1, 2)
println((Seq() ++ mutableSeq) eq mutableSeq) // prints false
Where eq is reference equality. Note that the above also works with List() ++ s, however as Rex pointed out, it does not work for all collections, like Vector.
You certainly can overload in that way! E.g., this compiles fine:
object MIO
{
import collection.mutable
def f1[A](s: Seq[A]) = 23
def f1[A](s: mutable.Seq[A]) = 42
def f2(s: Seq[_]) = 19
def f2(s: mutable.Seq[_]) = 37
}
In the REPL:
Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_37).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import rrs.scribble.MIO._; import collection.mutable.Buffer
import rrs.scribble.MIO._
import collection.mutable.Buffer
scala> f1(List(1, 2, 3))
res0: Int = 23
scala> f1(Buffer(1, 2, 3))
res1: Int = 42
scala> f2(List(1, 2, 3))
res2: Int = 19
scala> f2(Buffer(1, 2, 3))
res3: Int = 37

what is the use case for scala List's companion function returning GenericCompanion?

I am reading the Scala List API. I couldn't figure out the use for the companion function below.
def companion : GenericCompanion[List]
The factory companion object that builds instances of class List.
It seems that it is meant for some functions in List but not for the end users to consume it directly. If it is the case so, how would one know if the function is not to be consumed by the application developer directly? Of course, this is my educated assumption only and would like to be corrected if I am wrong.
Without knowing the details of design choices in the collections library I think I can see two uses here:
DRY. Somewhat internal but having a companion object which acts as a factory building from a type specific Builder is a common pattern in the collections library so refactoring this into a class each collection implementation composes reduces duplication.
Abstraction. Exposing "companion" provides a means for client code to construct a new collection of the same type as an instance without necessarily knowing what that type is. This would be useful if you want to create more general collection handling functions that return consistent types.
Here are some examples of how it might be useful:
scala> val a: Traversable[Int] = Set(1,2,3,4)
a: Traversable[Int] = Set(1, 2, 3, 4)
scala> a.companion(1,2,3)
res1: Traversable[Int] = Set(1, 2, 3)
scala> val b: Traversable[Int] = List(1,2,3,4)
b: Traversable[Int] = List(1, 2, 3, 4)
scala> b.companion(1,2,3)
res2: Traversable[Int] = List(1, 2, 3)
scala> def ends[T](c: Traversable[T]) : Traversable[T]= {
| c.companion(c.head, c.last)
| }
ends: [T](c: Traversable[T])Traversable[T]
scala> ends[Int](List(1,2,3,4,5))
res3: Traversable[Int] = List(1, 5)
scala> ends[Int](Set(1,2,3,4,5))
res4: Traversable[Int] = Set(5, 4)
Note that "ends" doesn't know which subtype of Traversable it receives but is able to give back a new collection of a compatible type built using the companion.
The idea is that a trait in the top of the hierarchy can get the companion (and the builders contained therein) so that it can build a collection of the type of the collection in the bottom of the hierarchy. Only I don't know where, exactly, it is used, since there's already a newBuilder method that provides for that.