Let's say I want to create an alias for a method:
def foo = bar(_)
This will warn that
Anonymous function convertible to a method value
And I'm not quite sure what that's supposed to mean, because when I try what I think this might mean:
def foo = bar
I get an error
Missing arguments for method bar(a:A)
Cannot resolve reference bar with such signature.
First, If you want to create an "alias" for method, that's enough:
scala> val foo = bar(_) //val instead of def, still warning from Idea
foo: Int => Int = <function1>
Second, this shoud remove Idea's warning:
scala> val foo = bar _
foo: Int => Int
Actually, it's not just alias - your method becomes converted into a function (eta-expansion). You cant' just specify method (compile-time entity) as compiler will expect parameters - you need to convert it into a function (using underscore) first. Sometimes it's done automatically when compiler expects a function:
scala> val foo: Int => Int = bar
foo: Int => Int = <function1>
So this probably what Idea wants from you. In other cases - you have to use eta-expansion operator (_) explicitly.
P.S/1. def foo = bar(_) (def instead of val) makes no sense as it will return new (but same) function every time, val (or lazy val to be safe from NullPointerException) just returns it once.
P.S/2. The difference between (_) and _ is that first is partially applied function (which does _ eta-expansion automatically), which means that for let's say:
scala> def bar(a: Int, b: Int) = a
bar: (a: Int, b: Int)Int
scala> def foo = bar _
foo: (Int, Int) => Int
scala> def foo = bar(_)
<console>:8: error: missing parameter type for expanded function ((x$1) => bar(x$1))
def foo = bar(_)
^
<console>:8: error: not enough arguments for method bar: (a: Int, b: Int)Int.
Unspecified value parameter b.
def foo = bar(_)
^
scala> def foo = bar(_, _)
foo: (Int, Int) => Int
you have to specify bar(_, _) as there are two arguments.
That's a suggestion from IntelliJ. If you click "More" in the suggestion, you'll see the following (sorry it's graphic, I can't copy the text):
You can either ignore or use bar _ instead of bar(_).
Related
Consider the following code snippet:
def foo(a: Int)(b: Int) = a + b
foo
It does not compile, and produces the following error message:
error: missing argument list for method foo
Unapplied methods are only converted to functions when
a function type is expected.
You can make this conversion explicit by writing
`foo _` or `foo(_)(_)` instead of `foo`.
The foo _ hint works. But if I write the expression
foo(_)(_)
as suggested by the previous error message, I get a new error message:
error: missing parameter type for expanded
function ((x$1: <error>, x$2: <error>) => foo(x$1)(x$2))
This seems rather counterintuitive.
Under what circumstances is the foo(_)(_)-hint supposed to be helpful, what exactly does it tell me?
(noise removed; the more I kept editing the question, the less sense did it make; Kolmar is right)
The type of foo(_)(_) is (Int, Int) => Int. So it works if you specify that type or use it in the context that expects this type:
scala> foo(_: Int)(_: Int)
res1: (Int, Int) => Int = $$Lambda$1120/1321433666#798b36fd
scala> val f: (Int, Int) => Int = foo(_)(_)
f: (Int, Int) => Int = $$Lambda$1121/1281445260#2ae4c424
scala> def bar(f: (Int, Int) => Int): Int = f(10, 20)
bar: (f: (Int, Int) => Int)Int
scala> bar(foo(_)(_))
res2: Int = 30
I read, that in Scala you can overload any operator, not as in Groovy. But I saw no any example how to overload function call.
Is it possible / how to overload function call operator in Scala?
I know that "there is no operators in Scala", but despite this, I need to do what I would name that.
function call is spelled apply. Any object which has a method named apply overloads function call.
class Functionish(val int: Int, val str: String) {
def apply(i: Int): Int = i + int
def apply(s: String): String = s + str + s
}
val f = new Functionish(42, "hello")
println(f(4))
println(f("George, "))
prints
46
George, helloGeorge,
Of note: case class companion objects overload apply. This is why you can create a case class instance with
val instance = CaseClass(foo, bar, baz)
instead of
val instance = new CaseClass(foo, bar, baz)
Every "callable" object is called via apply method:
scala> def foo(i: Int) = i * i
foo: (i: Int)Int
scala> val f = foo _
f: Int => Int = <function1>
scala> f(42)
res2: Int = 1764
scala> f.apply(42)
res3: Int = 1764
Is that what are you looking for?
I'm beginner in scala.
Anonymous function syntax is clear for me:
(a: Int) => Int,
without parentheses: a: Int => Int - compile error.
But can somebody explain me purpose of this syntax?
{a: Int => Int}
Just another form of anonymous function?
I don't think it is clear to you.
(a: Int) => Int
this line is not something that someone would actually type. It creates an anonymous function that takes an Int named here a and returns an object Int that is of type Int.type and this is companion object of Int class.
scala> (a: Int) => Int
res0: Int => Int.type = <function1>
This is exactly the same thing, just wrapped in useless block that will evaluate to the only expression inside it.
{a: Int => Int}
To do things properly, to define anonymous function say
val fun = (a: Int) => a + 5
i.e. put some expression that should be evaluated.
You can also annotate the type of this val
val fun: Int => Int = _ + 5
To define the type of function, you say for example Int => Int
def apply5(f: Int => Int) = f(5)
It seems like you mixed those two concepts (definition of anonymous function and type of function).
Having defined both you can say
apply5(fun)
Which will have result 10
I think there is no notable difference between {a: Int => a + 5} and (a: Int) => a + 5. Actually both are quite common. For example look at defining an action in Play (type of request is annotated just to apply to the example, it is not needed)
Action { request: Request[AnyContent] =>
// some more code
Ok("")
}
It is an anonymous function, that takes a single argument a of type Int, discards it, and returns a scala object scala.Int representing the type Int.
You can answer questions like this yourself fairly easily with the help of scala repl:
scala> val f = { a: Int => Int }
f: Int => Int.type = <function1>
scala> f(1)
res210: Int.type = object scala.Int
Simplified, from a more complex program:
scala> type T = (String) => String
defined type alias T
scala> def f(s: String) = s + " (parsed)"
f: (s: String)java.lang.String
scala> f _
res0: (String) => java.lang.String = <function1>
scala> def g(func: T) = func _
<console>:6: error: _ must follow method; cannot follow (String) => String
def g(func: T) = func _
^
I don't really understand why this doesn't work. What is the difference between a method and something in the form of (Type1, Type2 ...) => Type, and what's the right way of getting the function partial from something like that?
In Scala there is a difference between methods and functions. Methods always belong to an object, but functions are objects. A method m can be converted into a function using m _
See Difference between method and function in Scala
scala> def g(func: String => String) = func(_)
g: (func: (String) => String)(String) => String
Parenthesis make all the difference. This is one of the tricky things about the binding of _; it can be used to lift a method to a closure, and it can be used for partial application, but the two usages are not the same!
is this what you're trying to do?
scala> def g(func: T) = func
g: (func: (String) => String)(String) => String
scala> g(f)("test")
res8: String = test (parsed)
I think you're looking for this: http://jim-mcbeath.blogspot.com/2009/05/scala-functions-vs-methods.html
I am trying to define a Map literal with key: String, value: (Any)=>String. I tried the following, but get a syntax error:
def foo(x: Int): String = /...
def bar(x: Boolean): String = /...
val m = Map[String, (Any) => String]("hello" -> foo, "goodbye" -> bar)
Funny that no one actually gave a type that would work. Here's one such:
def foo(x: Int): String = x.toString
def bar(x: Boolean): String = x.toString
val m = Map[String, (Nothing) => String]("hello" -> foo, "goodbye" -> bar)
The reason why it works this way is because Function1 is contra-variant on the input, so (Nothing) => String is a superclass of (Int) => String. It is also co-variant on the output, so (Nothing) => Any would be a superclass to any other Function1.
Of course, you can't use it like that. Without manifests, you can't even uncover what the original type of Function1 is. You could try something like this, though:
def f[T : Manifest](v: T) = v -> manifest[T]
val m = Map[String, ((Nothing) => String, Manifest[_])]("hello" -> f(foo), "goodbye" -> f(bar))
val IntManifest = manifest[Int]
val BooleanManifest = manifest[Boolean]
val StringManifest = manifest[String]
m("hello")._2.typeArguments match {
case List(IntManifest, StringManifest) =>
m("hello")._1.asInstanceOf[(Int) => String](5)
case List(BooleanManifest, StringManifest) =>
m("hello")._1.asInstanceOf[(Boolean) => String](true)
case _ => "Unknown function type"
}
Int => String is not a subclass of Any => String, rather, the contrary. You can't put (replace) an Int => String function when a code expects Any => String, since that code can apply the function with, say, "hi".
#Ben suggestion works, but how is it useful? you can't invoke the function once you get it from the Map.
If you really want to do this, maybe define foo as a partial function:
val foo: PartialFunction[Any, String] = {case i: Int => ....}
Obviously, this will fail at runtime if you pass it a string, but you can always test if the function is ok for use with your parameter by using isDefinedAt. (another alternative may be manifests, but I don't see the value here)
If I let the compiler infer it I seem to get an illegal type:
scala> val m = Map("hello" -> foo _, "goodbye" -> bar _)
m: scala.collection.immutable.Map[java.lang.String,(Boolean with Int) => String] =
Map((hello,<function1>), (goodbye,<function1>))
scala> m("hello")(8)
<console>:9: error: type mismatch;
found : Int(8)
required: Boolean with Int
m("hello")(8)
scala> var q = new Boolean with Int
<console>:5: error: illegal inheritance from final class Boolean
var q = new Boolean with Int
Anyway, what you want is not the type Any but a generic of "any type" which is _:
scala> val mm = Map[String, (_) => String]("hello" -> foo _, "goodbye" -> bar _)
mm: scala.collection.immutable.Map[String,Function1[_, String]] =
Map((hello,<function1>), (goodbye,<function1>))
I just posted a question about how to invoke such functions because I don't actually know.
Trait Function1 is contravariant for parameter, so def foo(x: Int): String is not a (Any) => String. So the following would work:
scala> def baz(x: Any): String = "baz"
baz: (x: Any)String
scala> val m2 = Map[String, (String) => String]("hello" -> baz)
m2: scala.collection.immutable.Map[String,(String) => String] = Map((hello,<function1>))
This is how I did it to fulfill a similar requirement.
object MapToMethods {
private def increment(x: Int): Int = x+1
private def decrement(x: Int): Int = x-1
val m: Map[String, Int => Int] =Map("increment" -> increment, "decrement" ->decrement)
println(m("increment")(2)) //prints 3
println(m("decrement")(3)) //prints 2
}