I have a side-effect free method with default arguments that I'd like to invoke without parenthesis, e.g.:
scala> def foo(x: Int = 1) = 42
foo: (x: Int)Int
scala> foo
<console>:9: error: missing arguments for method foo in object $iw;
follow this method with `_' if you want to treat it as a partially applied function
foo
^
scala> foo()
res3: Int = 42
Is this intentional, or just a temporary limitation?
This is probably intentional so you don't get parameter blocks disappearing on you:
def foo(x: Int = 2)(y: Int = 4) = x*y
foo(3) // What does this mean???
Related
It's not very clear to me how adding a a Type parameter to a generic object can influence the call of its apply method. If that didn't make much sense, I have tried to formulate a simple example to express my trivial confusion.
scala> object Foo {def apply[T] = "Hello from foo"}
object Foo
scala> Foo
val res0: Foo.type = Foo$#709d6de5
scala> Foo[Int]
val res1: String = Hello from foo
Why is it only that when I specify [Int], the apply method is called, and returns "Hello from foo"
On the other hand, when I use an apply method that takes a parameter, I don't need to specify the type anymore.
scala> object Bar {def apply[T](useless: T) = "Hello from bar"}
object Bar
scala> Bar
val res2: Bar.type = Bar$#33089426
scala> Bar("Something useless")
val res3: String = Hello from bar
Why in the first case (when there were no parameters) I had to specify the type, while in the second case (when there was one useless parameter) I did not have to specify the type, for the apply to be called?
The compiler needs to know when you're referring to the object and when you're invoking the apply() method. It uses [] and/or () as the clue.
If you add an empty value parameter list to the Foo.apply then you can drop the [Int] specification.
scala> object Foo {def apply[T]() = "Hello from foo"}
defined object Foo
scala> Foo
res25: Foo.type = Foo$#332d4c4f
scala> Foo[Int]
res26: String = Hello from foo
scala> Foo()
res27: String = Hello from foo
If your apply takes no parameters, type or value, then the only way to invoke it is to specify it completely.
cala> object Baz {def apply = "Hello from Baz"}
defined object Baz
scala> Baz
res14: Baz.type = Baz$#5bd4ecec
scala> Baz()
<console>:13: error: Baz.type does not take parameters
Baz()
^
scala> Baz.apply
res16: String = Hello from Baz
Given:
scala> def f(x: Any*): String = "Foo"
f: (x: Any*)String
My understanding is that it'll take 1 or more arguments of any Any, and then return "Foo".
scala> f(1, 2, List(4), "foo")
res5: String = Foo
scala> f(null)
res6: String = Foo
But, then I passed in a higher-kinded type:
scala> f(Option)
res7: String = Foo
... but I expected a compile-time failure since edit - I think it's a type constructor.
Why did f(Option) work, i.e. output "Foo"?
That is not a type constructor, and there's nothing special about var args in this case. It is the companion object of Option. If you make f generic over a type parameter A, you can see that Option.type (the type of Options companion object) is inferred.
scala> def f[A](a: A) = a
f: [A](a: A)A
scala> f(Option)
res1: Option.type = scala.Option$#59f95c5d
I define foo:
scala> def foo(x: Int, y:Int): Int = x + y
foo: (x: Int, y: Int)Int
Then I failed to set bar equal to the curried function of foo.
scala> def bar = foo.curried
<console>:8: error: missing arguments for method foo;
follow this method with `_' if you want to treat it as a partially applied
function
def bar = foo.curried
^
What am I doing wrong?
foo is not a function, it's a method. It's not an object, it has no own methods. curried is a method on object of type FunctionN.
You have to convert it to function:
(foo _).curried
With foo _ you are creating a new object of type Function2.
Here are two method declaration:
def fun = "x"
def fun() = "x"
Since they both need no parameter and return a String, what's the difference besides invoking way?
Besides being right on the convention for no side effect for functions without parameters, there IS a difference between 'fun' and 'fun()' in Scala.
'fun' is called a 'parameterless' function, whereas 'fun()' is function with an 'empty parameter list'.
To make a long story short:
scala> def fun() = "x"
fun: ()java.lang.String
scala> fun
res0: java.lang.String = x
scala> fun()
res1: java.lang.String = x
scala> def fun = "y"
fun: java.lang.String
scala> fun
res2: java.lang.String = y
scala> fun()
<console>:9: error: not enough arguments for method apply: (index: Int)Char in class StringOps.
Unspecified value parameter index.
fun()
^
It's just a convention:
obj.fun //accessing like property with no side-effects
obj.fun() //ordinary method call, return value, but might also have side-effects
Prefer () version to emphasize that this is a method as opposed to simple property.
Note that this is just a convention, a way to document code, the compiler does not enforce the rules above.
Functions without () are usually used to express functionality without side effects, as #Tomasz noted (e.g. length of string - as far you have the same string, length would be the same)
If you define function without parentheses, you can't use them when you call function:
scala> def fun = "x"
fun: java.lang.String
scala> fun
res0: java.lang.String = x
scala> fun()
<console>:9: error: not enough arguments for method apply: (n: Int)Char in trait StringLike.
Unspecified value parameter n.
fun()
^
scala> def fun() = "x"
fun: ()java.lang.String
//now you may use () or may not - it is up to you
scala> fun
res2: java.lang.String = x
scala> fun()
res3: java.lang.String = x
(Addenda) You can find the "pure vs side effect" convention here : Scala Style Guide Chapter 3.4.2
Does anyone know if something like this is possible in Scala:
case class Thing(property:String)
def f(thing:Thing, prop:String = thing.property) = println(prop)
The above code doesn't compile; giving the error error: not found: value thing at thing.property
The following shows the expected behaviour:
f(Thing("abc"), "123") // prints "123"
f(Thing("abc")) // prints "abc"
I realise I could make the prop argument an Option[String] and do the check in the function definition, but I was wondering if there was a way around it with the new named/default argument support in 2.8.0.
Yes, it's possible in Scala 2.8. Here's a quote from the "Named and Default Arguments in Scala 2.8" design document:
Since the scope of a parameter extends
over all subsequent parameter lists
(and the method body), default
expressions can depend on parameters
of preceding parameter lists (but not
on other parameters in the same
parameter list). Note that when using
a default value which depends on
earlier parameters, the actual
arguments are used, not the default
arguments.
def f(a: Int = 0)(b: Int = a + 1) = b // OK
And another example:
def f[T](a: Int = 1)(b: T = a + 1)(c: T = b)
// generates:
// def f$default$1[T]: Int = 1
// def f$default$2[T](a: Int): Int = a + 1
// def f$default$3[T](a: Int)(b: T): T = b
According to this, your code may look as follows:
scala> case class Thing(property:String)
defined class Thing
scala> def f(thing:Thing)(prop:String = thing.property) = println(prop)
f: (thing: Thing)(prop: String)Unit
scala> f(Thing("abc"))("123")
123
scala> f(Thing("abc"))()
abc
Another simple solution is just to overload the method:
case class Thing (property: String)
def f(thing: Thing, prop: String) = println(prop)
def f(thing: Thing) = f(thing, thing.property)
This is exactly what Option is for. You can use the getOrElse method before the method call or inside the method f.
scala> val abc = Some("abc")
abc: Some[java.lang.String] = Some(abc)
scala> val none: Option[String] = None
none: Option[String] = None
scala> println(abc getOrElse "123")
abc
scala> println(none getOrElse "123")
123
scala> def f(o: Option[String]) = println(o getOrElse "123")
f: (o: Option[String])Unit
scala> f(abc)
abc
scala> f(none)
123
Oh here is something you could do via default arguments:
scala> case class Thing(property: String = "123")
defined class Thing
scala> def f(t: Thing) = println(t.property)
f: (t: Thing)Unit
scala> f(Thing("abc"))
abc
scala> f(Thing())
123
The expected behaviour can be achieved with simple overloading. I needed to put the method in an object because it looks like the REPL does not allow direct overloaded function declarations:
scala> object O {
def overloaded(t:Thing) = println(t.property)
def overloaded(t:Thing,s:String) = println(s)
}
defined module O
scala> O.overloaded(Thing("abc"), "123")
123
scala> O.overloaded(Thing("abc"))
abc