Say I have a trait like this
trait X {
def foo(param: String): Int
}
and I want to override it with a function value, I have to do this:
class XImpl extends X {
private val fooF: String => Int = ???
override def foo(param: String): Int = fooF(param)
}
because the following does not work
class XImpl extends X {
override val foo: String => Int = ???
}
/*
error: class XImpl needs to be abstract. Missing implementation for:
def foo(param: String): Int // inherited from trait X
^
error: value foo overrides nothing.
Note: the super classes of class XImpl contain the following, non final members named foo:
def foo(param: String): Int
*/
Is it possible to directly implement/override the trait method with the function value in some way and avoid the forwarder?
The simple answer is that you cannot override a method with a function value because they are not the same type.
A method must be called on a particular instance of a class (even if the method itself does not use any fields in that class).
A function value stands alone and can be called without any additional information.
A method can be converted a function value using eta expansion x.foo _. This creates a function value which has the class value embedded within it.
val x: X = ???
val etaFoo: String => Int = x.foo _
In this case Scala will actually do the eta expansion for you so the _ is optional, but it is required in more complex uses and is good practice to keep it there so show that eta expansion is happening.
To convert a function value to a method you need to define a method as shown in the question.
Eta expansion works with methods with multiple parameters:
trait X2 {
def foo2(p1: String, p2: Int): String
}
val x2: X2 = ???
val etaFoo2: (String, Int) => String = x2.foo2 _
Related
In Scala, I want to generate some aliases for basic types, and then implement conversions through a type class. This is both useful for me, and an opportunity to understand type classes. The code is the following:
type Index = Int
val Index = Int
type Integer = Int
val Integer = Int
type Real = Double
val Real = Double // to have companion object of Double also be the companion object of Real
trait Convertible[A] {
def toIndex(a: A): Index
def toInteger(a: A): Integer
def toReal(a: A): Real
}
implicit val ConvertibleIndex: Convertible[Index] = new Convertible[Index] {
def toIndex(i: Index) = i
def toInteger(i: Index) = i
def toReal(i: Index) = i.toDouble
}
implicit val ConvertibleInteger: Convertible[Integer] = new Convertible[Integer] {
def toIndex(i: Integer) = i
def toInteger(i: Integer) = i
def toReal(i: Integer) = i.toDouble
}
implicit val ConvertibleReal: Convertible[Real] = new Convertible[Real] {
def toIndex(r: Real) = r.toInt
def toInteger(r: Real) = r.toInt
def toReal(r: Real) = r
}
implicit val ConvertibleString: Convertible[String] = new Convertible[String] {
def toIndex(s: String) = s.toInt
def toInteger(s: String) = s.toInt
def toReal(s: String) = s.toDouble
}
implicit class ConvertibleSyntax[A](a: A)(implicit val c: Convertible[A]) {
def toIndex = c.toIndex(a)
def toInteger = c.toInteger(a)
def toReal = c.toReal(a)
}
Consider now:
val a = 3.toReal
val b = 3.0.toReal
val c = "3".toReal
The statement for a does not compile, with the compilation error: method toReal is not a member of Int. But, for the b and c statements, the implicit conversion to ConvertibleSyntax is properly done.
Why is the implicit conversion not working on Int, but is working on Double and String ?
Because you define ambiguous implicits for Index and Integer (both Int).
Which one should be chosen by compiler?
I think you might be a little confused about how Scala does implicit conversions. (A common mistake, as implicit is a little overused.)
I think that what you want, first of all, is an implicit conversion function - or even an implicit class. Here's how you could do this using the latter:
Note: Int, Index and Integer are treated identically, so are Real and Double, confusing matters somewhat, so I've pared this down to something that will work. Also, Convertible does not need to be generic as its conversion functions need no arguments. Finally, you shouldn't have both type and val declarations for your types.
type Index = Int
type Integer = Int
type Real = Double
trait Convertible {
def toIndex: Index
def toInteger: Integer
def toReal: Real
}
// Implicit classes cannot be defined in top-level scope, so they belong to an object.
object Implicits {
implicit class ConvertibleInt(i: Int)
extends Convertible {
override def toIndex = i
override def toInteger = i
override def toReal = i.toDouble
}
implicit class ConvertibleDouble(d: Double)
extends Convertible {
override def toIndex = d.toInt
override def toInteger = d.toInt
override def toReal = d
}
implicit class ConvertibleString(s: String)
extends Convertible {
override def toIndex = s.toInt
override def toInteger = s.toInt
override def toReal = s.toDouble
}
}
Now try this:
import Implicits._
val a = 3.toReal
val b = 3.0.toReal
val c = "3".toReal
What's happening here? Well, the implicit class declarations define classes that decorate the sole constructor argument with additional functions. If the compiler sees that you're trying to call a method on a type that doesn't have that method, it will look to see if there's an implicit conversion, in scope, to a type that does. If so, it is used and the function is called; if not, you get a compiler error. (The import statement is used to bring the classes into your current scope.)
So, for example, when the compiler sees "3".toReal it firstly determines that "3" is a String. Since this type doesn't have a .toReal member, it tries to find a conversion from a String to a type that does have such a member. It finds the ConvertibleString implicit class that takes a String argument and provides a .toReal method. Yay! So the compiler creates an instance of this class by passing "3" to ConvertibleString's constructor, then calls .toReal on the result.
On the other hand, when implicit is used with a value, it tells the compiler that the value is a default for any matching implicit arguments of the same type that are not provided. NEVER USE implicit WITH A PRIMITIVE OR COMMON LIBRARY TYPE!
For example:
final case class Example(i: Int)
// Default.
implicit val nameCanBeAnythingAtAll = Example(5)
// Function with implicit argument.
def someFunc(implicit x: Example): Unit = println(s"Value is $x")
Now, if you write something like this:
someFunc
the output will be Value is Example(5).
implicit values and arguments are an advanced topic, and I wouldn't worry about how they're used right now.
I'm quite new to Scala and a part of my project ended up with the following design.
trait StringService {
def length(s: String): Int
def vowels(s: String): Int
}
Those methods are used as parameters to
def processStrings(operation: String => Int) = {...}
Calls like processStrings(ss.length) work fine. Now I would like to abstract
the type of these methods
type StringFuction = String => Int
The problem is that an implementation like
override def length(s: String): Int = { ... }
is no longer valid. Of course, I can go with
override def length: StringFunction = { (s: String) => ... }
but this seems a little off.
What's the proper way? Please feel free to suggest a different design if this isn't a true Scala approach.
Well, there are different ways to do this, depending on the purpose you want to use your type alias for. This works for example:
type StringFunction = String => Int
trait Foo { def foo(s: String) = ??? }
class Bar extends Foo {
def foo(s: String) = s.length
}
def foobar(f: StringFunction)(s) = f(s)
foobar(new Bar().foo)("bar")
This works too:
type StringFunction = String => Int
trait Foo { def foo: StringFunction = ??? }
class Bar extends Foo {
override def foo = _.length
}
def foobar(f: StringFunction)(s) = f(s)
foobar(new Bar().foo)("bar")
Strictly speaking, these are not the same constructs: in the first case Foo.foo is a method, that takes an String argument and returns an Int.
In the second case, it is a method, that takes no arguments, and returns a lambda function, that take a String argument, and returns an Int.
This difference is fairly subtle though. It does matter for some specific cases, but often can be ignored.
I'm having difficulty understanding how curried functions (with one argument) differ from normal methods. I tried to implement the latter with the former, but wasn't able to.
I have Market trait defined as follows:
package market {
trait Market {
def getBuyRate(currency: String): Double
def getSellRate(currency: String): Double
}
}
I have another FakeMarket trait that extends Market where I wanted to use currying to implement getBuyRate and getSellRate, as follows:
package market {
trait FakeMarket extends Market with Iterable[Double] {
def getRate(factor: Double)(currency: String): Double = {
factor * this.iterator.next()
}
def getBuyRate = getRate(1) _
def getSellRate = getRate(1.02) _
}
}
Finally, I have RandomFakeMarket object that extends FakeMarket:
package market {
object RandomFakeMarket extends FakeMarket {
def iterator = new Iterator[Double] {
def hasNext = true
def next = 100.0
}
}
}
Having the types defined as such gives an error saying:
<console>:10: error: object creation impossible, since:
it has 2 unimplemented members.
/** As seen from object RandomFakeMarket, the missing signatures are as follows.
* For convenience, these are usable as stub implementations.
*/
def getBuyRate(currency: String): Double = ???
def getSellRate(currency: String): Double = ???
object RandomFakeMarket extends FakeMarket {
^
This seems odd to me because FakeMarket implements methods called getBuyRate and getSellRate of String => Double type.
I can get this to work if in Market I had done:
getBuyRate: String => Double
Why is this different from how I originally defined getBuyRate? Why should this be different when there's only one argument? Now it seems that the parent trait Market has to worry about how getBuyRate gets implemented (a normal function vs a curried function).
It's not so much related to currying. def method(p1: String, p2: String): String is not equivalent to def method: (String, String) => String in scala. The difference between methods and functions is that methods support inheritance, so they need to know the method's input and output, which is not so obvious because of ambiguity:
def get: String => Double may be both String -> Double (iterpreted as unified member) and () -> String -> Double (interpreted as function). But in scala it's Function1[String, Double] or () Function1[String, Double], which are simmilar in the meaning that there is no input. Unfortunatelly, def get(): String => Double makes no difference here (see examples below).
In other words, method may not have input parameters in scala (as it's may not be a pure function because of side effects), so it can't infer (String)Double from String => Double so your whole function becomes an output parameter. For example you could do override def method: (String, String) => String in some subclass - this will override method without parameters and with return type (String, String) => String, but not override the method with input (String, String) and return type String.
Another problem is that methods have different types than functions and may be only one-way converted by eta-expansion, so scala is a little bit incompatible with UAP :
scala> def aaa(b: String): String = "aaa"
aaa: (b: String)String
scala> aaa _
res4: String => String = <function1>
scala> def aaa: String => String = (a: String) => "aa"
aaa: String => String
scala> def aaa()(b: String): String = "aaa"
aaa: ()(b: String)String
scala> def aaa(): String => String = (a: String) => "aa"
aaa: ()String => String
A bit more about methods vs functions: Difference between method and function in Scala
I was under the impression that this
// short syntax
def foo(bar: Bar)(baz: Baz): Quux
was syntax sugar for this
// long syntax
def foo(bar: Bar): (Baz) => Quux
But I cannot seem to mix the two when it comes to inheritance. The whole tree has to be defined in either the short syntax or the long syntax; never both.
For example:
case class Context
case class Work
trait ContextualWorker {
def workWithContext(ctxt: Context)(work: Work): Traversable[Work]
}
class ShortConcreteWorker extends ContextualWorker {
override def workWithContext(ctxt: Context)(work: Work) = Nil
}
class LongConcreteWorker extends ContextualWorker {
// error on next line: method workWithContext overrides nothing <-------------
override def workWithContext(ctxt: Context): (Work) => Traversable[Work] = {
val setupCode = 1
{ work => Nil }
}
}
If I change the trait to use the long syntax, then ShortConcreteWorker doesn't compile.
Is there a reason why these aren't interchangeable/inheritable? How have you gotten around it?
Right now the most flexible approach appears to be to define the tree in the long syntax, perhaps delegating to an implementation class in ShortConcreteWorker like so:
case class Context
case class Work
trait ContextualWorker {
def workWithContext(ctxt: Context): (Work) => Traversable[Work]
}
class ShortConcreteWorker extends ContextualWorker {
override def workWithContext(ctxt: Context) = workWithContextImpl(ctxt)_
private def workWithContextImpl(ctxt: Context)(work: Work) = Nil
}
class LongConcreteWorker extends ContextualWorker {
override def workWithContext(ctxt: Context): (Work) => Traversable[Work] = {
val setupCode = 1
{ work => Nil }
}
}
The two methods described quite simply have different signatures. The REPL confirms this:
scala> def foo1(a: Int)(b: Int): Int = a + b
foo1: (a: Int)(b: Int)Int
scala> def foo2(a: Int): (Int => Int) = (b: Int) => a + b
foo2: (a: Int)Int => Int
The first is a function that requires two arguments, given in separate argument lists, and returns an Int. The second is a function that takes one argument and returns a function from Int to Int. While these two things are conceptually similar, they are, in fact, different constructs, and Scala treats them as such.
This is not limited to functions with multiple argument lists. It works the same way here:
scala> def foo3(a: Int): Int = a + 1
foo3: (a: Int)Int
scala> def foo4: (Int => Int) = (a: Int) => a + 1
foo4: Int => Int
Note that there are different ramifications for usage as well. With foo2, because it only accepts one argument, we can call it with just one argument. However, foo1 requires two arguments, an so we cannot simply call it with one. You can however use the _ syntax to convert it into a callable function.
foo2(2) // Int => Int = <function1>
foo1(2) // error: missing arguments for method foo1
foo1(2) _ // Int => Int = <function1>
So to answer your question directly: The reason they are not interchangeable is because they are not the same. If they were the same, we would be able to call them the same way. If you could change the signature upon extension, how would Scala know which calling syntax to allow? The way to "get around" this is to simply make the signatures consistent.
I want to do this:
abstract class Context {
def getInt(id: Int): Int
}
abstract class Dependency[+T]
(val name: String, val id: Int)
extends Function1[Context,T]
class IntDependency(name: String, id: Int)
extends Dependency[Int](name, id) {
def apply(implicit context: Context): Int =
context.getInt(id)
}
But then I get an error message like this:
class IntDependency needs to be abstract, since method apply in trait
Function1 of type (v1: Context)Long is not defined (Note that T1 does
not match Context)
I understand that implicits should normally be part of the second parameter list, but I can't work out how to code it so it compiles, and gives the result I want.
Explanation: I'm trying to create a framework where one can define "Function" object, which can depend on other functions to compute their value. All functions should only take a single Context parameter. The context know the "result" of the other functions. The function instances should be immutable, with the state residing in the context. I want the functions to create "dependency" fields at creation time, which take the context implicitly, and return the value of the dependency within that context, so that accessing the dependency inside of the apply method "feels like" accessing a parameter or field, that is without explicitly giving the context as parameter to the dependency.
Are you sure you need your Dependency to extend a Function? Because if you don't, just leave the extends Function1[Context,T] part out and your code will work.
If you really need to extend a Function than I don't know of a solution in your case. But there are cases where you could try to overload the apply method. Like here:
scala> val sum = new Function1[Int, Function1[Int, Int]] {
| def apply(a: Int) = (b: Int) => a + b
| def apply(a: Int)(implicit b: Int) = a + b
|}
sum: java.lang.Object with (Int) => (Int) => Int{def apply(a:Int)(implicit b: Int): Int} = <function1>
scala> sum(2)(3)
res0: Int = 5
scala> implicit val b = 10
b: Int = 10
scala> sum(2)
res1: Int = 12
A method may have its final parameter section marked implicit; it need not be the second section, although that is most commonly seen.
But it seems that when a subclass marks a parameter section implicit, it is no longer considered to override the method in the superclass.
scala> new (Int => Int) { def apply(implicit i: Int) = i }
<console>:8: error: object creation impossible, since method apply in trait Function1 of type (v1: Int)Int is not defined
(Note that T1 does not match Int)
new (Int => Int) { def apply(implicit i: Int) = i }
^
scala> trait F1 { def f(a: Any) }; new F1 { def f(implicit a: Any) = () }
<console>:8: error: object creation impossible, since method f in trait F1 of type (a: Any)Unit is not defined
trait F1 { def f(a: Any) }; new F1 { def f(implicit a: Any) = () }
^
The spec does not specifically mention this (§5.1.4 Overriding), so it may be an implementation restriction, or an bug.
Its sure, that your apply method signature with implicit doesn´t conform with the signature of Function1.apply.
Hopefully I get your problem right, so what about (assuming that your context is mutable and perhaps singleton) having the implicit context injected at creation time? Is that possible in your case?
class IntDependency(id: Int)(implicit context: Context) extends Dependency[Int](id)
But then I wonder (and still was wondering before) what to do with the context argument at the apply method.
Here is the working solution:
abstract class Context {
def getInt(id: Int): Int
}
abstract class Dependency[+T]
(val name: String, val id: Int) {
def get(context: Context): T
}
class IntDependency(name: String, id: Int)
extends Dependency[Int](name, id) {
def get(context: Context): Int =
context.getInt(id)
}
implicit def intDep2Int(dep: IntDependency)
(implicit context: Context): Int =
dep.get(context)