Why are functions values but methods are not, or what makes a function a value in particular? What would allow me to decipher that methods do not contain that characteristic?
Scala is an object-oriented language. In object-oriented languages, every value is an object, and every object is a value.
Methods are bound to objects. It is awkward to have methods at the same time be a building block of objects and be objects themselves. It is easier to have them not be objects.
A function in Scala is, in some sense, just an object with an apply method. If there is no method named foo in scope, then foo() is simply syntactic sugar for foo.apply(). So, functions are values because they are objects.
While any object that has an apply method can be called as if it were a function, when we talk about "functions" in Scala, we usually mean something more specific: an instance of one of the FunctionN traits such as Function2[-T1, -T2, +R]. In particular, the function literal syntax
val add = (a: Int, b: Int) => a + b
is syntactic sugar for
val add = new Function2[Int, Int, Int] {
override def apply(a: Int, b: Int) = a + b
}
And the function type
type F = (Int, String, Long) => Boolean
is syntactic sugar for
type F = Function3[Int, String, Long, Boolean]
[Scastie link]
where each of the FunctionN traits is defined like this:
package scala
trait Function0[+R] {
def apply: R
override def toString = "<function>"
}
trait Function1[-T, +R] {
def apply(x: T): R
override def toString = "<function>"
}
trait Function2[-T1, -T2, +R] {
def apply(x1: T1, x2: T2): R
override def toString = "<function>"
}
trait Function3[-T1, -T2, -T3, +R] {
def apply(x1: T1, x2: T2, x3: T3): R
override def toString = "<function>"
}
and so on.
It is possible to convert a method into a function value using η-expansion. This can be done explicitly using a trailing underscore:
val f = println _
or in some cases, when it is clear that a function value is required, even by just using the bare name of the method:
val it = Iterable(1, 2, 3)
it.foreach(println)
[Scastie link]
Note that this is not much different from other languages. In Java, C#, and Ruby, for example, it is the same thing: methods are defined as part of classes (or structs in C# and modules in Ruby) and are bound to objects, but aren't objects themselves. Instead, you have a separate notion of a function (instance of a SAM interface / functional interface in Java, Action or Func in C#, Proc in Ruby), which is an object.
In Ruby, you can create a proxy object for a method that is bound to an object which has the same interface as Proc.
Other languages make different choices, i.e. in ECMAScript and Python, methods are objects / values, but they are not as tightly bound to objects as they are in Scala, Java, C#, and Ruby. Instead, methods are basically normal functions that are assigned to fields of the object.
One of the defining characteristics of a value is that it can be assigned to a variable. A method, technically speaking, cannot be assigned to a variable, for example
def m(i: Int): Int = i + 1
val f = m // error
However there is a process called eta expansion that converts a method to a function value. In Scala 2, we can trigger it by providing type ascription to a variable
val f: Int => Int = m
or by using underscore _
val f = m _
However this restriction has been lifted in Scala 3 (Dotty) which now provides automatic eta expansion so the following compiles successfully
scala> def f(i: Int): Int = i + 1
| val x = f
def f(i: Int): Int
val x: Int => Int = Lambda$1218/158882051#62cf6a84
Related
I have defined an abstract base class like following:
abstract class Base() {
val somevariables
}
And then, I extend this class like following:
case class Derived (a: SomeOtherClass, i: Int) extends Base {
//Do something with a
}
Then, I have a method (independent of classes) that is as follows:
def myMethod (v1: Base, v2: Base, f:(Base, Base) => Int ): Int
And I want to use the above method as myMethod(o1, o2, f1), where
o1, o2 are objects of type Derived
f1 is as follows def f1(v1: Derived, v2: Derived): Int
Now, this gives me an error because myMethod expects the function f1 to be (Base, Base) => Int, and not (Derived, Derived) => Int. However, if I change the definition of f1 to (Base, Base) => Int, then it gives me an error because internally I want to use some variable from SomeOtherClass, an argument that Base does not have.
You should use type parameters to make sure that the types in myMethod line up correctly.
def myMethod[B <: Base](v1: B, v2: B)(f: (B, B) => Int): Int
Or perhaps a bit more general:
def myMethod[B <: Base, A >: B](v1: B, v2: B)(f: (A, A) => Int): Int
If you want to be able to use function f1 where function f2 is expected, f1 must either be of the same type (both input parameters and return value) or a subclass of f2. Liskov Substitution Principle teaches us that for one function to be a subclass of another, it needs to require less (or same) and provide more (or same).
So if you have a method that as a parameter takes a function of type (Fruit, Fruit) => Fruit, here are types for some valid functions that you can pass to that method:
(Fruit, Fruit) => Fruit
(Fruit, Fruit) => Apple
(Any, Any) => Fruit
(Any, Any) => Apple
This relates to covariance/contravariance rule; for example, every one-parameter function in Scala is a trait with two type parameters, Function2[-S, +T]. You can see that it is contravariant in its parameter type and covariant in its return type - requires S or less ("less" because it's more general, so we lose information) and provides T or more ("more" because it's more specific, so we get more information).
This brings us to your problem. If you had things the other way around, trying to fit (Base, Base) => Int in the place where (Derived, Derived) => Int is expected, that would work. Method myMethod obviously expects to be feeding this function with values of type Derived, and a function that takes values of type Base will happily accept those; after all, Derived is a Base. Basically what myMethod is saying is: "I need a function that can handle Deriveds", and any function that knows how to work with Bases can also take any of its subclasses, including Derived.
Other people have pointed out that you can set the type of function f's parameters to a subtype of Base, but at some point you will probably want to use v1 and v2 with that function, and then you will need to revert to downcasting via pattern matching. If you're fine with that, that you can also just pattern match on the function directly, trying to figure out what's its true nature. Either way, pattern matching sucks in this case because you will need to fiddle around myMethod every time a new type is introduced.
Here is how you can solve it more elegantly with type classes:
trait Base[T] {
def f(t1: T, t2: T): Int
}
case class Shape()
case class Derived()
object Base {
implicit val BaseDerived = new Base[Derived] {
def f(s1: Derived, s2: Derived): Int = ??? // some calculation
}
implicit val BaseShape = new Base[Shape] {
def f(s1: Shape, s2: Shape): Int = ??? // some calculation
}
// implementations for other types
}
def myMethod[T: Base](v1: T, v2: T): Int = {
// some logic
// now let's use f(), without knowing what T is:
implicitly[Base[T]].f
// some other stuff
}
myMethod(Shape(), Shape())
What happens here is that myMethod says: "I need two values of some type T and I need to have an implicit Base[T] available in scope (that's the [T: Base] part, which is a fancy way of saying that you need an implicit parameter of type Base[T]; that way you would access it by its name, and this way you access it via implicitly). Then I know I will have f() available which performs the needed logic". And since the logic can have different implementation based on the type, this is a case of ad-hoc polymorphism and type classes are a great way of dealing with that.
What's cool here is that when a new type is introduced that has its own implementation of f, you just need to put this implementation in the Base companion object as an implicit value, so that it's available to myMethod. Method myMethod itself remains unchanged.
According to my (very simple) tests, this change...
def myMethod[B <: Base](v1: Base, v2: Base, f:(B, B) => Int ): Int = ???
...will allow either of these methods...
def f1(a: Derived, b:Derived): Int = ???
def f2(a: Base, b:Base): Int = ???
...to be accepted as a passed parameter.
myMethod(Derived(x,1), Derived(x,2), f1)
myMethod(Derived(x,1), Derived(x,2), f2)
I have a simple trait that requires the implementation to have a method quality(x:A) which I want to return an Ordered[B]. In other words, quality transforms A to Ordered[B]. Such that I can compare to B's.
I have the following basic code:
trait Foo[A] {
def quality[B](x:A):Ordered[B]
def baz(x1:A, x2:A) = {
// some algorithm work here, and then
if (quality(x1) > quality(x2)) {
// some stuff
}
}
Which I want to implement like follows:
class FooImpl extends Foo[Bar] {
def quality(x:Bar):Double = {
someDifficultQualityCalculationWhichReturnsADouble
}
}
I figured this could work because Double is implicitly converted to RichDouble which implements Ordered[Double] if I am correct.
But at the > in the baz method of the trait it gives me an error of quality(x2) stating: Type mismatch, expected Nothing, actual Ordered[Nothing]
I do not understand this, because, coming from C#, I find it comparable to returning something like IEnumerable<A> and then using al the nice extension methods of an IEnumerable.
What am I missing here? What I want to to with the trait is define a complex algorithm inside the trait, but the key functions need to be defined by the class implementing the trait. On of these functions is needed to calculate a quality factor. This can be a Double, Int or whatnot but it can also be something more sophisticated. I could rewrite it that it always returns Double and that is certainly possible, but I want the trait to be as generic as possible because I want it to describe behavior and not implementation. I thought about the class A implementing Ordered[A] but that also seems weird, because it is not the 'purpose' of this class to be compared.
Using Ordering[A] you can compare As without requiring A to implement Ordered[A].
We can request that an Ordering[A] exists in baz by adding an implicit parameter :
trait Foo[A] {
def baz(x1:A, x2:A)(implicit ord: Ordering[A]) =
if (ord.gt(x1, x2)) "first is bigger"
else "first is smaller or equal"
}
Lets create a Person case class with an Ordering in its companion object.
case class Person(name: String, age: Int)
object Person {
implicit val orderByAge = Ordering.by[Person, Int](_.age)
}
We can now use Foo[Person].baz because an Ordering[Person] exists :
val (alice, bob) = (Person("Alice", 50), Person("Bob", 40))
val foo = new Foo[Person] {}
foo.baz(alice, bob)
// String = first is bigger
// using an explicit ordering
foor.baz(alice, bob)(Ordering.by[Person, String](_.name))
// String = first is smaller or equal
In the same manner as I compared Persons by age, you could create an Ordering[A] to compare your A by your quality function.
To complement Peter's answer: in Scala we have two traits: Ordering[T] and Ordered[A]. You should use them in different situations.
Ordered[A] is for cases when a class you implement can be ordered naturally and that order is the only one.
Example:
class Fraction(val numerator: Int, val denominator: Int) extends Ordered[Fraction]
{
def compare(that: Fraction) = {
(this.numerator * that.denominator) compare (this.denominator * that.numerator)
}
}
Ordering[T] is for cases when you want to have different ways to order things. This way the strategy of defining the order can be decoupled from the class being ordered.
For an example I will borrow Peter's Person:
case class Person(name: String, age: Int)
object PersonNameOrdering extends Ordering[Person]
{
def compare(x: Person, y: Person) = x.name compare y.name
}
Note, that since PersonNameOrdering doesn't have any instance fields, all it does is encapsulate the logic of defining an order of two Person's. Thus I made it an object rather than a class.
To cut down the boilerplate you can use Ordering.on to define an Ordering:
val personAgeOrdering: Ordering[Person] = Ordering.on[Person](_.age)
Now to the fun part: how to use all this stuff.
In your original code Foo[A].quantity was indirectly defining a way to order your A's. Now to make it idiomatic Scala let's use Ordering[A] instead, and rename quantity to ord:
trait Foo[A] {
def baz(x1: A, x2: A, ord: Ordering[A]) = {
import ord._
if (x1 > x2) "first is greater"
else "first is less or equal"
}
}
Several things to note here:
import ord._ allows to use infix notation for comparisons, i.e. x1 > x2 vs ord.gt(x1, x2)
baz is now parametrized by ordering, so you can dynamically choose how to order x1 and x2 on a case-by-case basis:
foo.baz(person1, person2, PersonNameOrdering)
foo.baz(person1, person2, personAgeOrdering)
The fact that ord is now an explicit parameter can sometimes be inconvenient: you may not want to pass it explicitly all the time, while there might be some cases when you want to do so. Implicits to the rescue!
def baz(x1: A, x2: A) = {
def inner(implicit ord: Ordering[A]) = {
import ord._
if (x1 > x2) "first is greater"
else "first is less or equal"
}
inner
}
Note the implicit keyword. It is used to tell the compiler to draw the parameter from the implicit scope in case you don't provide it explicitly:
// put an Int value to the implicit scope
implicit val myInt: Int = 5
def printAnInt(implicit x: Int) = { println(x) }
// explicitly pass the parameter
printAnInt(10) // would print "10"
// let the compiler infer the parameter from the implicit scope
printAnInt // would print "5"
You might want to learn where does Scala look for implicits.
Another thing to note is the need of a nested function. You cannot write def baz(x1: A, x2: A, implicit ord: Ordering[A]) - that would not compile, because the implicit keyword applies to the whole parameter list.
In order to cope with this little problem baz was rewritten in such a clunky way.
This form of rewritting turned out to be so common that a nice syntactic sugar was introduced for it - multiple parameter list:
def baz(x1: A, x2: A)(implicit ord: Ordering[A]) = {
import ord._
if (x1 > x2) "first is greater"
else "first is less or equal"
}
The need of an implicit parametrized by a type is also quite common so the code above can be rewritten with even more sugar - context bound:
def baz[A: Ordering](x1: A, x2: A) = {
val ord = implicitly[Ordering[A]]
import ord._
if (x1 > x2) "first is greater"
else "first is less or equal"
}
Please bear in mind that all these transformations of baz function are nothing but syntactic sugar application. So all the versions are exactly the same and compiler would desugarize each of the versions to the same bytecode.
To recap:
extract the A ordering logic from quantity function to the Ordering[A] class;
put an instance of Ordering[A] to the implicit scope or pass the ordering explicitly depending on your needs;
pick "your flavor" of syntactic sugar for baz: no sugar/nested functions, multiple parameter list or context bound.
UPD
To answer the original question "why doesn't it compile?" let me start from a little digression on how infix comparison operator works in Scala.
Given the following code:
val x: Int = 1
val y: Int = 2
val greater: Boolean = x > y
Here's what actually happens. Scala doesn't have infix operators per se, instead infix operators are just a syntactic sugar for single parameter method invocation. So internally the code above transforms to this:
val greater: Boolean = x.>(y)
Now the tricky part: Int doesn't have an > method on its own. Pick ordering by inheritance on the ScalaDoc page and check that this method is listed in a group titled "Inherited by implicit conversion intWrapper from Int to RichInt".
So internally compiler does this (well, except that for performance reasons that there is no actual instantiation of an extra object on heap):
val greater: Boolean = (new RichInt(x)).>(y)
If we proceed to ScalaDoc of RichInt and again order methods by inheritance it turns out that the > method actually comes from Ordered!
Let's rewrite the whole block to make it clearer what actually happens:
val x: Int = 1
val y: Int = 2
val richX: RichInt = new RichInt(x)
val xOrdered: Ordered[Int] = richX
val greater: Boolean = xOrdered.>(y)
The rewriting should have highlighted the types of variables involved in comparison: Ordered[Int] on the left and Int on the right. Refer > documentation for confirmation.
Now let's get back to the original code and rewrite it the same way to highlight the types:
trait Foo[A] {
def quality[B](x: A): Ordered[B]
def baz(x1: A, x2: A) = {
// some algorithm work here, and then
val x1Ordered: Ordered[B] = quality(x1)
val x2Ordered: Ordered[B] = quality(x2)
if (x1Ordered > x2Ordered) {
// some stuff
}
}
}
As you can see the types do not align: they are Ordered[B] and Ordered[B], while for > comparison to work they should have been Ordered[B] and B respectively.
The question is where do you get this B to put on the right? To me it seems that B is in fact the same as A in this context. Here's what I came up with:
trait Foo[A] {
def quality(x: A): Ordered[A]
def baz(x1: A, x2: A) = {
// some algorithm work here, and then
if (quality(x1) > x2) {
"x1 is greater"
} else {
"x1 is less or equal"
}
}
}
case class Cargo(weight: Int)
class CargoFooImpl extends Foo[Cargo] {
override def quality(x: Cargo): Ordered[Cargo] = new Ordered[Cargo] {
override def compare(that: Cargo): Int = x.weight compare that.weight
}
}
The downside of this approach is that it is not obvious: the implementation of quality is too verbose and quality(x1) > x2 is not symmetrical.
The bottom line:
if you want the code to be idiomatic Scala go for Ordering[T]
if you don't want to mess with implicits and other Scala magic implement quality as quality(x: A): Double for all As; Doubles are good and generic enough to be compared and ordered.
In Scala, everything is an object. Even functions are subclasses of the FunctionN classes. We can declare functions with the following syntax:
def foo(a:A, b:B):C = ...
where A, B, and C are types. Given that the function foo is a subclass of Function2[A,B,C], is it equivalent to say
val foo = new Function2[A,B,C] { def apply(a:A, b:B) = ... }
Furthermore, if so, how can generic functions such as
def bar[T](data:T)
be written using val syntax?
I'm trying to understand the crucial difference between these two approaches of referencing / defining Function Literal (reference to anonymous function):
By val
scala> val v2 = new Function[Int, Int] {
| def apply(a: Int): Int = a + 1
| }
v2: Int => Int = <function1>
And by def
scala> def f2 = new Function[Int, Int] {
| def apply(a: Int): Int = a + 1
| }
f2: Int => Int
It seems that it pretty much the same in terms of use. I either can pass v2 or f2 to the function that accepts (Int) => Int as an argument. Passing arguments to its..
I guess or the case of v2 it creates an Function1 object that refers to the Function1 object.. like a proxy?
Ok.. My question is: what is advantage and disadvantages of 1th and 2nd approach?
And of it is defined by def, is it still Function Literal?
First of all, neither of your examples are actually function literals—you're creating a Function instance in the plain old sugar-free way, and in fact you could use this approach (new Function { ... }) to create an instance of scala.Function from Java code.
The following are both function literals, and are exactly equivalent to your definitions:
val v2 = (a: Int) => a + 1
def f2 = (a: Int) => a + 1
The only real difference here is that the val will create a single instance once and for all, no matter how many times you use v2 (and even if you never use it), while the def will create a new instance every time (or not at all, if you never use it). So you'll generally want to go with a val.
There are cases, however, where you need to use def. Consider the following:
def myIdentity[A] = (a: A) => a
There's no way we could write this as a val, since Scala doesn't have polymorphic functions in this sense (for any instance of Function[A, B], A and B have to be concrete types). But we can define a polymorphic method that returns a function, and when we write e.g. myIndentity(1), the A will be inferred to be Int, and we'll create (and apply) a Function[Int, Int] exactly as you'd expect.
I am trying to learn Scala now, with a little bit of experience in Haskell. One thing that stood out as odd to me is that all function parameters in Scala must be annotated with a type - something that Haskell does not require. Why is this? To try to put it as a more concrete example: an add function is written like this:
def add(x:Double, y:Double) = x + y
But, this only works for doubles(well, ints work too because of the implicit type conversion). But what if you want to define your own type that defines its own + operator. How would you write an add function which works for any type that defines a + operator?
Haskell uses Hindley-Milner type inference algorithm whereas Scala, in order to support Object Oriented side of things, had to forgo using it for now.
In order to write an add function for all applicable types easily, you will need to use Scala 2.8.0:
Welcome to Scala version 2.8.0.r18189-b20090702020221 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_15).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import Numeric._
import Numeric._
scala> def add[A](x: A, y: A)(implicit numeric: Numeric[A]): A =
| numeric.plus(x, y)
add: [A](x: A,y: A)(implicit numeric: Numeric[A])A
scala> add(1, 2)
res0: Int = 3
scala> add(1.1, 2.2)
res1: Double = 3.3000000000000003
In order to solidify the concept of using implicit for myself, I wrote an example that does not require scala 2.8, but uses the same concept. I thought it might be helpful for some.
First, you define an generic-abstract class Addable:
scala> abstract class Addable[T]{
| def +(x: T, y: T): T
| }
defined class Addable
Now you can write the add function like this:
scala> def add[T](x: T, y: T)(implicit addy: Addable[T]): T =
| addy.+(x, y)
add: [T](T,T)(implicit Addable[T])T
This is used like a type class in Haskell. Then to realize this generic class for a specific type, you would write(examples here for Int, Double and String):
scala> implicit object IntAddable extends Addable[Int]{
| def +(x: Int, y: Int): Int = x + y
| }
defined module IntAddable
scala> implicit object DoubleAddable extends Addable[Double]{
| def +(x: Double, y: Double): Double = x + y
| }
defined module DoubleAddable
scala> implicit object StringAddable extends Addable[String]{
| def +(x: String, y: String): String = x concat y
| }
defined module StringAddable
At this point you can call the add function with all three types:
scala> add(1,2)
res0: Int = 3
scala> add(1.0, 2.0)
res1: Double = 3.0
scala> add("abc", "def")
res2: java.lang.String = abcdef
Certainly not as nice as Haskell which will essentially do all of this for you. But, that's where the trade-off lies.
Haskell uses the Hindley-Milner type inference. This kind of type-inference is powerful, but limits the type system of the language. Supposedly, for instance, subclassing doesn't work well with H-M.
At any rate, Scala type system is too powerful for H-M, so a more limited kind of type inference must be used.
I think the reason Scala requires the type annotation on the parameters of a newly defined function comes from the fact that Scala uses a more local type inference analysis than that used in Haskell.
If all your classes mixed in a trait, say Addable[T], that declared the + operator, you could write your generic add function as:
def add[T <: Addable[T]](x : T, y : T) = x + y
This restricts the add function to types T that implement the Addable trait.
Unfortunately, there is not such trait in the current Scala libraries. But you can see how it would be done by looking at a similar case, the Ordered[T] trait. This trait declares comparison operators and is mixed in by the RichInt, RichFloat, etc. classes. Then you can write a sort function that can take, for example, a List[T] where [T <: Ordered[T]] to sort a list of elements that mix in the ordered trait. Because of implicit type conversions like Float to RichFloat, you can even use your sort function on lists of Int, or Float or Double.
As I said, unfortunately, there is no corresponding trait for the + operator. So, you would have to write out everything yourself. You would do the Addable[T] trait, create AddableInt, AddableFloat, etc., classes that extend Int, Float, etc. and mix in the Addable trait, and finally add implicit conversion functions to turn, for example, and Int into an AddableInt, so that the compiler can instantiate and use your add function with it.
The function itself will be pretty straightforward:
def add(x: T, y: T): T = ...
Better yet, you can just overload the + method:
def +(x: T, y: T): T = ...
There's a missing piece, though, which is the type parameter itself. As written, the method is missing its class. The most likely case is that you're calling the + method on an instance of T, passing it another instance of T. I did this recently, defining a trait that said, "an additive group consists of an add operation plus the means to invert an element"
trait GroupAdditive[G] extends Structure[G] {
def +(that: G): G
def unary_- : G
}
Then, later, I define a Real class that knows how to add instances of itself (Field extends GroupAdditive):
class Real private (s: LargeInteger, err: LargeInteger, exp: Int) extends Number[Real] with Field[Real] with Ordered[Real] {
...
def +(that: Real): Real = { ... }
...
}
That may be more than you really wanted to know right now, but it does show both how to define generic arguments and how to realize them.
Ultimately, the specific types aren't required, but the compiler does need to know at least the type bounds.