Methods taking a single argument can be written as an infix operators in Scal. I.e. adding *(other:C) = foo(this, other) to class C, will allow us to write c1 * c2 instead of foo(c1,c2). But is there a way to define infix operators on existing classes that you cannot modify?
E.g. if I wanted to write c1 + c2 instead of xor(c1,c2), where c1,c2:Array[Byte], I obviously cannot modify the Array-Class.
I found this and tried
implicit class Bytearray(a1:Array[Byte]) extends Anyval {
def +(a2:Array[Byte]) = xor(a1,a2)
}
But that doesn't seem to work (c1 + c2).
Type mismatch, expected:String, actual:Array[Byte]
I thought that perhaps the issue was my using +, so I exchanged it for xor
but c1 xor c2 only lead to
Cannot resolve symbol xor
Any suggestions?
UPDATE
Interesting. I had a class Foo with an object Foo defined below it, containing the implicit class. This lead to the aforementioned errors.
However, deleting the object and instead putting the implicit class into a trait BytearrayHandling and then extending it (class Foo extends BytearrayHandling) seems to work. Why is that?
It should be straight forward with the normal declaration of extension methods:
implicit class ByteArrayOps(private val a1: Array[Byte]) extends AnyVal {
def + (a2: Array[Byte]): Array[Byte] =
(a1 zip a2).map { case (x, y) => (x ^ y).toByte }
}
"foo".getBytes + "bar".getBytes // Array(4, 14, 29)
However be aware that sometimes you will run into this:
Type mismatch, expected:String, actual: X
This is because of an implicit conversion kicking in that allows you to + anything by converting it to a String. I have given up trying to understand how to deactivate it. It will finally go in Scala 2.12 if I'm not mistaken.
As eugener pointed out, this error message may indicate that you haven't actually imported your extension method (implicit conversion). For example:
object MyStuff {
implicit class ByteArrayOps(private val a1: Array[Byte]) extends AnyVal {
def + (a2: Array[Byte]): Array[Byte] =
(a1 zip a2).map { case (x, y) => (x ^ y).toByte }
}
}
"foo".getBytes + "bar".getBytes // error
gives:
<console>:14: error: type mismatch;
found : Array[Byte]
required: String
"foo".getBytes + "bar".getBytes
^
because of this Predef conversion. After you import MyStuff.ByteArrayOps, it works.
You can do something like:
class ByteArray(self: Array[Byte]) {
def +(other: Array[Byte]) = Array[Byte](1, 2, 3) // replace with your code
}
implicit def byteArrayPlus(self: Array[Byte]) = new ByteArray(self)
Array[Byte](0, 1, 2) + Array[Byte](0, 2, 3)
the last line of which should yield Array(1, 2, 3).
Related
Suppose I am writing library code that should be easy to extend and to use without verbose syntax. It seems like implicit conversions can be used to avoid verbosity, as in the Scala Collections library, but I am struggling at applying it to traversables as follows.
I have a trait:
trait Wrapped[T]
{
def value : T
}
Then I have the class Foo, a key class in the library. Foos are constructed with a list of anything that is Wrapped.
case class Foo[T <: Wrapped[_]](lst : Traversable[T]) {
override def toString = lst mkString " "
}
A common use case would be wrapping an Int so I provide a WrappedInt class:
case class WrappedInt(value : Int) extends Wrapped[Int]
With this code, I can make a Foo like this:
val wrappedInts = Seq(1, 2, 3, 4) map { new WrappedInt(_) }
val someFoo = Foo(wrappedInts)
I do not like the extra code to wrap here. I would like the following code to be equivalent:
val foo = Foo(Seq(1, 2, 3, 4)) //should be a Foo[WrappedInt] - gives error
I define the following implicit:
object Conversions {
implicit def intsToWrapped(lst : Traversable[Int]) = lst map { new WrappedInt(_) }
}
However, it still doesn't work, my val foo has a compilation error after changing the Foo constructor parameter to implicit lst. The Scala book says that an implicit conversion essentially allows x + y to be changed to convert(x) + y, where convert is an implicit conversion. It seems to me like I have the same exact case, one conversion of one parameter here is enough. I verify by doing this:
val foo = Foo(Conversions.intsToWrapped(Seq(1, 2, 3, 4)))
Why is my implicit not being applied? And is there a different, more idiomatic way in current Scala to let Foo be constructed with less code?
EDIT: Adding import Conversions._ does not help and should, if I understand correctly, not be necessary because this example is in one file.
Specific compiler errors I get are these:
val foo = Foo(Seq(1, 2, 3, 4))
inferred type arguments [Int] do not conform to method apply's type parameter bounds [T <: Wrapped[_]]
type mismatch; found : Seq[Int] required: Traversable[T]
Specifying the type to help with type inference, like this:
val foo = Foo[WrappedInt](Seq(1, 2, 3, 4))
gives a message for each int like
type mismatch; found : Int(1) required: WrappedInt
You can specify an implicit conversion in foo's constructor (what once was a view bound). You have to specify that the collection elements are "viewable" as their wrapped versions, not the collection itself.
trait Wrapped[T] {
def value : T
}
// you can specify bounds on W if you want to be able to do something specific on the values, e.g. W <: MyClass
case class Foo[T, W](lst : Traversable[T])(implicit asWrapped: T => Wrapped[W]) {
override def toString = lst.map(_.value) mkString " "
}
case class WrappedInt(value : Int) extends Wrapped[Int]
// This is your implicit conversion from Int to WrappedInt
implicit def intToWrapped(x : Int): WrappedInt = WrappedInt(x)
val wrappedInts = Seq(1, 2, 3, 4) map { new WrappedInt(_) }
val someFoo = Foo(wrappedInts)
val foo = Foo(Traversable(1, 2, 3, 4))
Is there a way to use shorter syntax when using context-bound type parameters? At the moment I have something like this
case class Vector2D[a : Numeric](x: a, y: a) {
val numA = implicitly[Numeric[a]]
def length2 = numA.plus(numA.times(x, x), numA.times(y, y))
}
and it makes more complex formulae unreadable.
Try this REPL session:
scala> case class Vector2D[T : Numeric](x: T, y: T) {
val numeric = implicitly[Numeric[T]]
import numeric._
def length2 = (x*x)+(y*y)
}
defined class Vector2D
scala> Vector2D(3,4).length2
res0: Int = 25
This is because Numeric contains an implicit conversion called mkNumericOps which you can import as shown above. If it didn't come out of the box, the way you could roll this yourself would be something like:
scala> implicit class NumericOps[T](val x: T) extends AnyVal { def +(y: T)(implicit n: Numeric[T]): T = n.plus(x, y)
| def *(y: T)(implicit n: Numeric[T]): T = n.times(x, y)
| }
defined class NumericOps
scala> case class Vector2D[a : Numeric](x: a, y: a) { def length2 = (x*x)+(y*y) }
defined class Vector2D
scala> Vector2D(3,4).length2
res0: Int = 25
If you make NumericOps not a value class (don't extend AnyVal) then the implicit Numeric can go on the constructor instead of each method, which might be better, or not really matter.
Anyway there's no need to write your own since Numeric already has mkNumericOps.
These "ops" classes are called the "enrich my library" pattern.
Numeric.Ops is here
and the implicit being imported to auto-create it is mkNumericOps on Numeric, here.
Just
import Numeric.Implicits._
then for every type that for which an implicit Numeric can be found
(importing just the NumericOps conversion of one Numeric instance as suggested by #Havoc P gives you finer control as to for which types operations are available, but most of the time, Numeric.Implicits should be fine)
On the more general question is there a shorter syntax when using context bounds type parameters: in general, there is not. It is up to the typeclass to provide some sugar to make it easy to use, as Numeric does here.
For instance, it is more or less customary to have an apply method in the companion object which makes getting the instance a little easier than with implicitly
object Ordering {
def apply[T](implicit ord: Ordering[T]): Ordering[T] = implicitly[Ordering[T]]
}
so that you can get the implicit just with e.g Ordering[Int], rather than implicitly[Ordering[Int]].
I am searching for a way to restrict my polymorphic class to types that have a certain member function.
class Table[T](bla: Array[T]) {
val symbols = bla
symbols.foreach( x => x * probability(x))
def probability(t: T) : Double = ...
}
This code does not compile because T doesnt have member *. How can I assure this. I dont want to use inheritance.
Edit: probability is actually implemented. It returns a Double.
Any ideas?
The problem can be solved in different ways. For example, if you just want type T to have some method (and you don't care whether this method defined on the object or there is implicit conversion that coverts object to something that has this method), then you can use view bounds. Here is an example that expects type T to have method def *(times: Int): T:
class Table[T <% {def *(times: Int): T}](bla: Array[T]) {
bla.foreach( x => println(x * 2))
}
new Table(Array("Hello", "World"))
// Prints:
// HelloHello
// WorldWorld
String does not have method *, but there exist an implicit conversion to StringOps that has this method.
Here is another example. In this case I restricting type T with method def size: Int:
class Table[T <% {def size: Int}](bla: Array[T]) {
bla.foreach( x => println(x.size))
}
new Table(Array(List(1, 2, 3), List("World")))
// Prints:
// 3
// 1
List has method size, and it also works as expected.
But this could be more involving if you are working with numeric values like ints, floats, doubles, etc. In this case I can recommend you to use context bound. Scala has Numeric type class. You can use it to work with numbers without knowledge about their type (with Numeric you can actually work with anything that can be represented as number, so your code would be much more general and abstract). Here is an example if it:
import math.Numeric.Implicits._
class Table[T : Numeric](bla: Array[T]) {
bla.foreach( x => println(x * x))
}
new Table(Array(1, 2, 3))
// Prints:
// 1
// 4
// 9
new Table(Array(BigInt("13473264523654723574623"), BigInt("5786785634377457457465784685683746583454545454")))
// Prints:
// 181528856924372945350108280958825119049592129
// 33486887978237312740760811863500355048015109407078304275771413678604907671187978933752066116
Update
As you noted in comments, Numeric still does not solve your problem, because it can only work on the numbers of the same type. You can simply solve this problem by introducing new type class. Here is an example of it:
import math.Numeric.Implicits._
trait Convert[From, To] {
def convert(f: From): To
}
object Convert {
implicit object DoubleToInt extends Convert[Double, Int] {
def convert(d: Double): Int = d.toInt
}
implicit object DoubleToBigInt extends Convert[Double, BigInt] {
def convert(d: Double): BigInt = d.toLong
}
}
type DoubleConvert[To] = Convert[Double, To]
class Table[T : Numeric : DoubleConvert](bla: Array[T]) {
bla.foreach( x => println(x * implicitly[DoubleConvert[T]].convert(probability(x))))
def probability(t: T) : Double = t.toDouble + 2.5
}
new Table(Array(1, 2, 3))
new Table(Array(BigInt("13473264523654723574623"), BigInt("5786785634377453434")))
With DoubleConvert type class and T : Numeric : DoubleConvert context bound you are not only saying, that T should be some kind of number, but also that there should exist some evidence, that it can be converted from Double. You are receiving such evidence with implicitly[DoubleConvert[T]] and then you are using it to convert Double to T. I defined Convert for Double -> Int and Double -> BigInt, but you can also define you own for the types you need.
Use scala's structural typing: http://markthomas.info/blog/?p=66
Your code will end up looking something like this:
class Table[T <: {def *(i:Int): T}](bla: Array[T]) {
...
}
Everyone else is answering with "Structural Types". Quite rightly so, because that's the correct answer!
Instead of repeating the obvious, I'll expand upon it. Taking a snippet from Easy Angel's reply:
class Table[T <% {def *(times: Int): T}](bla: Array[T]) {
bla foreach {x => println(x*2)}
}
If you find you're using the same expression {def *(times: Int): T} more than once, then you can create a type alias for it
type HasTimes = {def *(times: Int): T}
class Table[T <% HasTimes](bla: Array[T]) {
bla foreach {x => println(x*2)}
}
If you don't want to use inheritance, the only other restriction you can apply is a context bound. So if you have a list of classes that are okay, you create an implicit object HasStar[X] for each class X and use a context bound like T:HasStar. I know this probably isn't exactly what you want, but I don't think there are any better options.
Given the following code:
abstract class Field {
type T
val data: List[T]
def sum: T = data(0) + data(1)
}
I get an error on the last line - def sum: T = data(0) + data(1):
types2.scala:6: error: type mismatch;
found : Field.this.T
required: String
def sum: T = data(0) + data(1)
^
That is, it expects data(1) to be a String.
I dont understand why... (scala 2.8.1)
Your explanation will be much appreciated!
Since T does not support an addition operation, compiler assumes + to be a string concatenation operation. The following line I tried out at REPL indicates so:
scala> implicitly[Any => {def +(s: String): String}]
res16: (Any) => AnyRef{def +(s: String): String} = <function1>
What you can do is require that T have a Semigroup algebra defined. (A type is a semigroup if it supports an associative append operation.)
scala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> abstract class Field[A : Semigroup] {
| val data: IndexedSeq[A]
| def sum: A = data(0) |+| data(1)
| }
defined class Field
scala> val f = new Field[Int] {
| val data = IndexedSeq(2, 3, 4)
| }
f: Field[Int] = $anon$1#d1fd51
scala> f.sum
res12: Int = 5
I replaced abstract type by a type parameter simply because I do not know how to put a context bound on an abstract type. I also changed type of data from List[A] to IndexedSeq[A] because as the name indicates indexed sequences are more suitable for indexed access than lists (which is what you do in your sum method). And finally, |+| is the semigroup append operation. For numeric types it will perform addition. For sequences, concatenation etc.
As a complement to #missingfactor's answer, while in principle I would very much favor Semigroup, there is a trait Numeric in the standard library which would do the same. And on collections whose content is Numeric (where a "Numeric structure" exists for the elements' type), you can simply call collection.sum (should you want to sum all the elements rather than the two first ones).
I prefer Semigroup for two reasons. First Numeric is much more than what is needed here, second, what are the exact properties of a Numeric structure is not clear. On the other hand, even someone not familiar with basic algebra will have a reasonable understanding of what Numeric means.
So if you are afraid of scalaz and/or semigroups, you can replace Semigroup with Numeric and |+| with +. You must import Numeric.Implicits._ so that + is available.
The compiler doesn't know how to invoke + in your type T, because it knows nothing about T. The only solution to compile this + is then a pimped string concatenation (by means of the implicit Predef.any2stringadd), which expects a string as second argument — hence the error you're getting.
After a lot of playing with this, I came up with a very simple solution.
Here is the full program
package manytypes
abstract class Field {
type T
val data: List[T]
def add (a: T, b: T): T
}
abstract class FieldInt extends Field {
type T = Int
def add (a: T, b: T): T = a + b
}
abstract class FieldDouble extends Field {
type T = Double
def add (a: T, b: T): T = a + b
}
abstract class FieldString extends Field {
type T = String
def add (a: T, b: T): T = a + b
}
object A extends App {
val ints: Field = new FieldInt { val data = List(1, 2, 3)}
val doubles: Field = new FieldDouble { val data = List(1.2, 2.3, 3.4) }
val strings: Field = new FieldString { val data = List("hello ", "this is ", "a list ")}
val fields: List[Field] = List(ints, doubles, strings)
for (field <- fields) println(field.data.reduceLeft(field.add(_, _)))
}
In scala, we can use implicit typeclasses to conditionally add methods onto a parameterized type dependent on that type's parameters. For example, Iterator.sum:
def sum[B >: A](implicit num: Numeric[B]): B = foldLeft(num.zero)(num.plus)
There must be an instance of the Numeric typeclass for this method to even be called:
scala> List(1, 2, 3).sum
res0: Int = 6
scala> List("a", "b").sum
<console>:6: error: could not find implicit value for parameter num: Numeric[java.lang.String]
List("a", "b").sum
^
So far, so good. Let's say I want to have some collection type, My2Col:
class My2Col[A](a1 : A, a2 : A)
But I want to mandate that, if this is made with a A : Numeric, then a2 > a1. However, it is entirely valid for it to be made with an A which is not numeric.
My2Col("a", "b") //OK
My2Col("b", "a") //OK
My2Col(1, 2) //OK
My2Col(2, 1) //THROW IllegalArgumentException
Has anyone any ideas as to how I might do this?
PS. If anyone has any suggestions for a better question title, I'm all ears
class My2Col[A](a1 : A, a2 : A)(implicit num: Numeric[A] = null){
for{check <- Option(num); if(check.gteq(a1, a2))}
throw new IllegalArgumentException
}
I would implement this by creating 2 implicits that represent requirements, one being more general (for all types other than, say, Int or Numeric[T]), and the other being more specific (for Int or Numeric[T]).
Then, following the rules of implicit resolution, I would put the more specific one in the companion object of the Requirement type, and the more general one in the base class of the companion object. This way I would ensure that the compiler tries to apply the more specific one first.
Of course, the downside is that if the user were to explicitly provide the implicit parameter, this mechanism could be circumvented not to do the check.
Something like this (where Int is the type with specific rules, and Foo is the collection class):
package ex
trait Requirement[T] {
def check(a1: T, a2: T): Unit
}
trait BaseReq {
implicit def genericReq[T] = new Requirement[T] {
def check(a1: T, a2: T) {println("generic")}
}
}
object Requirement extends BaseReq {
implicit object IntReq extends Requirement[Int] {
def check(a1: Int, a2: Int) = {
println("int")
if (a2 <= a1) throw new IllegalArgumentException
}
}
}
class Foo[T](a1: T, a2: T)(implicit req: Requirement[T]) {
req.check(a1, a2)
// whatever `foo` does follows
}
object Main {
def main(args: Array[String]) {
new Foo(1, 2)
new Foo("S1", "S2")
new Foo(2, 1)
}
}